[Ffmpeg-devel] [RFC] VC1 in EVO support
Kostya
kostya.shishkov
Fri Feb 2 19:40:49 CET 2007
This patch enables decoding VC-1 stream (tested on MAININTRO.EVO)
It consists of three parts:
* support for initialization with extradata present in first frame
* parser for reconstructing frames
* a few hacks to make it work now (two conditions commented out)
It also requires EVO demuxing support enabled (still pending,
you can find the very patch at
http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2007-January/051183.html )
Please test and give tips on implementation as it's my first attempt
to use parser and to make decoder work without extradata.
If it works as supposed I will clean it and divide before commit
Thanks
-------------- next part --------------
Index: libavcodec/allcodecs.c
===================================================================
--- libavcodec/allcodecs.c (revision 7803)
+++ libavcodec/allcodecs.c (working copy)
@@ -254,6 +254,7 @@
REGISTER_PARSER (MPEGAUDIO, mpegaudio);
REGISTER_PARSER (MPEGVIDEO, mpegvideo);
REGISTER_PARSER (PNM, pnm);
+ REGISTER_PARSER (VC1, vc1);
av_register_bitstream_filter(&dump_extradata_bsf);
av_register_bitstream_filter(&remove_extradata_bsf);
Index: libavcodec/avcodec.h
===================================================================
--- libavcodec/avcodec.h (revision 7803)
+++ libavcodec/avcodec.h (working copy)
@@ -2637,6 +2638,7 @@
extern AVCodecParser mpegaudio_parser;
extern AVCodecParser mpegvideo_parser;
extern AVCodecParser pnm_parser;
+extern AVCodecParser vc1_parser;
typedef struct AVBitStreamFilterContext {
Index: libavcodec/vc1.c
===================================================================
--- libavcodec/vc1.c (revision 7807)
+++ libavcodec/vc1.c (working copy)
@@ -1282,7 +1282,7 @@
v->interlace = get_bits1(gb);
if(v->interlace){
av_log(v->s.avctx, AV_LOG_ERROR, "Interlaced mode not supported (yet)\n");
- return -1;
+// return -1;
}
v->tfcntrflag = get_bits1(gb);
v->finterpflag = get_bits1(gb);
@@ -1305,8 +1305,8 @@
if(get_bits1(gb)) { //Display Info - decoding is not affected by it
int w, h, ar = 0;
av_log(v->s.avctx, AV_LOG_INFO, "Display extended info:\n");
- w = get_bits(gb, 14) + 1;
- h = get_bits(gb, 14) + 1;
+ v->s.width = w = get_bits(gb, 14) + 1;
+ v->s.height = h = get_bits(gb, 14) + 1;
av_log(v->s.avctx, AV_LOG_INFO, "Display dimensions: %ix%i\n", w, h);
if(get_bits1(gb))
ar = get_bits(gb, 4);
@@ -4143,6 +4143,30 @@
return dsize;
}
+static void after_init(VC1Context *v, AVCodecContext *avctx)
+{
+ MpegEncContext *s = &v->s;
+
+ avctx->has_b_frames= !!(avctx->max_b_frames);
+ s->low_delay = !avctx->has_b_frames;
+
+ s->mb_width = (avctx->coded_width+15)>>4;
+ s->mb_height = (avctx->coded_height+15)>>4;
+
+ /* Allocate mb bitplanes */
+ v->mv_type_mb_plane = av_malloc(s->mb_stride * s->mb_height);
+ v->direct_mb_plane = av_malloc(s->mb_stride * s->mb_height);
+ v->acpred_plane = av_malloc(s->mb_stride * s->mb_height);
+ v->over_flags_plane = av_malloc(s->mb_stride * s->mb_height);
+
+ /* allocate block type info in that way so it could be used with s->block_index[] */
+ v->mb_type_base = av_malloc(s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
+ v->mb_type[0] = v->mb_type_base + s->b8_stride + 1;
+ v->mb_type[1] = v->mb_type_base + s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride + 1;
+ v->mb_type[2] = v->mb_type[1] + s->mb_stride * (s->mb_height + 1);
+}
+
+
/** Initialize a VC1/WMV3 decoder
* @todo TODO: Handle VC-1 IDUs (Transport level?)
* @todo TODO: Decypher remaining bits in extra_data
@@ -4150,10 +4174,9 @@
static int vc1_decode_init(AVCodecContext *avctx)
{
VC1Context *v = avctx->priv_data;
- MpegEncContext *s = &v->s;
GetBitContext gb;
- if (!avctx->extradata_size || !avctx->extradata) return -1;
+// if (!avctx->extradata_size || !avctx->extradata) return -1;
if (!(avctx->flags & CODEC_FLAG_GRAY))
avctx->pix_fmt = PIX_FMT_YUV420P;
else
@@ -4198,7 +4221,10 @@
uint8_t *buf2 = NULL;
int seq_inited = 0, ep_inited = 0;
- if(avctx->extradata_size < 16) {
+ if(!avctx->extradata_size) {
+ v->profile = -1;
+ return 0; //init later
+ } else if(avctx->extradata_size < 16) {
av_log(avctx, AV_LOG_ERROR, "Extradata size too small: %i\n", avctx->extradata_size);
return -1;
}
@@ -4235,24 +4261,9 @@
return -1;
}
}
- avctx->has_b_frames= !!(avctx->max_b_frames);
- s->low_delay = !avctx->has_b_frames;
- s->mb_width = (avctx->coded_width+15)>>4;
- s->mb_height = (avctx->coded_height+15)>>4;
+ after_init(v, avctx);
- /* Allocate mb bitplanes */
- v->mv_type_mb_plane = av_malloc(s->mb_stride * s->mb_height);
- v->direct_mb_plane = av_malloc(s->mb_stride * s->mb_height);
- v->acpred_plane = av_malloc(s->mb_stride * s->mb_height);
- v->over_flags_plane = av_malloc(s->mb_stride * s->mb_height);
-
- /* allocate block type info in that way so it could be used with s->block_index[] */
- v->mb_type_base = av_malloc(s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride * (s->mb_height + 1) * 2);
- v->mb_type[0] = v->mb_type_base + s->b8_stride + 1;
- v->mb_type[1] = v->mb_type_base + s->b8_stride * (s->mb_height * 2 + 1) + s->mb_stride + 1;
- v->mb_type[2] = v->mb_type[1] + s->mb_stride * (s->mb_height + 1);
-
/* Init coded blocks info */
if (v->profile == PROFILE_ADVANCED)
{
@@ -4292,7 +4303,7 @@
}
//we need to set current_picture_ptr before reading the header, otherwise we cant store anyting im there
- if(s->current_picture_ptr==NULL || s->current_picture_ptr->data[0]){
+ if(v->profile != -1 && (s->current_picture_ptr==NULL || s->current_picture_ptr->data[0])){
int i= ff_find_unused_picture(s, 0);
s->current_picture_ptr= &s->picture[i];
}
@@ -4305,7 +4316,7 @@
if(IS_MARKER(AV_RB32(buf))){ /* frame starts with marker and needs to be parsed */
uint8_t *dst = buf2, *start, *end, *next;
int size;
-
+ int needs_init = (v->profile == -1), seqhdr_inited = -1, ep_inited = -1;
next = buf;
for(start = buf, end = buf + buf_size; next < end; start = next){
next = find_next_marker(start + 4, end);
@@ -4318,14 +4329,48 @@
case VC1_CODE_ENTRYPOINT: /* it should be before frame data */
buf_size2 = vc1_unescape_buffer(start + 4, size, buf2);
init_get_bits(&s->gb, buf2, buf_size2*8);
- decode_entry_point(avctx, &s->gb);
+ ep_inited = decode_entry_point(avctx, &s->gb);
+ if(ep_inited == -1 && needs_init){ /* entry point errors sometimes may be ignored */
+ v->profile = -1;
+ av_free(buf2);
+ return -1;
+ }
break;
+ case VC1_CODE_SEQHDR: /* it should be before frame data */
+ if(needs_init){
+ buf_size2 = vc1_unescape_buffer(start + 4, size, buf2);
+ init_get_bits(&s->gb, buf2, buf_size2*8);
+ seqhdr_inited = decode_sequence_header(avctx, &s->gb);
+ if(seqhdr_inited == -1){
+ v->profile = -1;
+ av_free(buf2);
+ return -1;
+ }
+ avcodec_set_dimensions(avctx, s->width, s->height);
+ }
+ break;
case VC1_CODE_SLICE:
av_log(avctx, AV_LOG_ERROR, "Sliced decoding is not implemented (yet)\n");
av_free(buf2);
return -1;
}
}
+ /* check for correct init */
+ if(needs_init){
+ if(seqhdr_inited == -1 || ep_inited == -1){
+ av_log(avctx, AV_LOG_ERROR, "Initialization is not complete. Cannot proceed\n");
+ v->profile = -1;
+ return -1;
+ }
+ MPV_common_end(&v->s);
+ if(ff_h263_decode_init(avctx) < 0)
+ return -1;
+ after_init(v, avctx);
+ if(s->current_picture_ptr==NULL || s->current_picture_ptr->data[0]){
+ int i= ff_find_unused_picture(s, 0);
+ s->current_picture_ptr= &s->picture[i];
+ }
+ }
}else if(v->interlace && ((buf[0] & 0xC0) == 0xC0)){ /* WVC1 interlaced stores both fields divided by marker */
uint8_t *divider;
@@ -4474,3 +4519,79 @@
CODEC_CAP_DELAY,
NULL
};
+
+#ifdef CONFIG_VC1_PARSER
+/**
+ * finds the end of the current frame in the bitstream.
+ * @return the position of the first byte of the next frame, or -1
+ */
+static int vc1_find_frame_end(ParseContext *pc, const uint8_t *buf,
+ int buf_size) {
+ int pic_found, i;
+ uint32_t state;
+
+ pic_found= pc->frame_start_found;
+ state= pc->state;
+
+ i=0;
+ if(!pic_found){
+ for(i=0; i<buf_size; i++){
+ state= (state<<8) | buf[i];
+ if(state == VC1_CODE_FRAME || state == VC1_CODE_FIELD){
+ i++;
+ pic_found=1;
+ break;
+ }
+ }
+ }
+
+ if(pic_found){
+ /* EOF considered as end of frame */
+ if (buf_size == 0)
+ return 0;
+ for(; i<buf_size; i++){
+ state= (state<<8) | buf[i];
+ if(IS_MARKER(state) && state != VC1_CODE_FIELD && state != VC1_CODE_SLICE){
+ pc->frame_start_found=0;
+ pc->state=-1;
+ return i-3;
+ }
+ }
+ }
+ pc->frame_start_found= pic_found;
+ pc->state= state;
+ return END_NOT_FOUND;
+}
+
+static int vc1_parse(AVCodecParserContext *s,
+ AVCodecContext *avctx,
+ uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ ParseContext *pc = s->priv_data;
+ int next;
+
+ if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){
+ next= buf_size;
+ }else{
+ next= vc1_find_frame_end(pc, buf, buf_size);
+
+ if (ff_combine_frame(pc, next, (uint8_t **)&buf, &buf_size) < 0) {
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+ return buf_size;
+ }
+ }
+ *poutbuf = (uint8_t *)buf;
+ *poutbuf_size = buf_size;
+ return next;
+}
+
+AVCodecParser vc1_parser = {
+ { CODEC_ID_VC1 },
+ sizeof(ParseContext1),
+ NULL,
+ vc1_parse,
+ ff_parse1_close,
+};
+#endif /* CONFIG_VC1_PARSER */
More information about the ffmpeg-devel
mailing list