[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