changeset 4462:d47a98f52e25 libavcodec

General approach to parsing chunks in VC-1 AP
author kostya
date Fri, 02 Feb 2007 06:45:21 +0000
parents c95e0df9841f
children 6018c147ea93
files vc1.c
diffstat 1 files changed, 124 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/vc1.c	Fri Feb 02 02:58:01 2007 +0000
+++ b/vc1.c	Fri Feb 02 06:45:21 2007 +0000
@@ -46,6 +46,19 @@
 #define AC_VLC_BITS 9
 static const uint16_t table_mb_intra[64][2];
 
+/** Markers used if VC-1 AP frame data */
+//@{
+enum VC1Code{
+    VC1_CODE_RES0       = 0x00000100,
+    VC1_CODE_ESCAPE     = 0x00000103,
+    VC1_CODE_ENDOFSEQ   = 0x0000010A,
+    VC1_CODE_SLICE,
+    VC1_CODE_FIELD,
+    VC1_CODE_FRAME,
+    VC1_CODE_ENTRYPOINT,
+    VC1_CODE_SEQHDR,
+};
+//@}
 
 /** Available Profiles */
 //@{
@@ -4094,6 +4107,42 @@
     }
 }
 
+#define IS_MARKER(x) ((((x) & ~0xFF) == VC1_CODE_RES0) && ((x) != VC1_CODE_ESCAPE))
+
+/** Find VC-1 marker in buffer
+ * @return position where next marker starts or end of buffer if no marker found
+ */
+static av_always_inline uint8_t* find_next_marker(uint8_t *src, uint8_t *end)
+{
+    uint32_t mrk = 0xFFFFFFFF;
+
+    if(end-src < 4) return end;
+    while(src < end){
+        mrk = (mrk << 8) | *src++;
+        if(IS_MARKER(mrk))
+            return src-4;
+    }
+    return end;
+}
+
+static av_always_inline int vc1_unescape_buffer(uint8_t *src, int size, uint8_t *dst)
+{
+    int dsize = 0, i;
+
+    if(size < 4){
+        for(dsize = 0; dsize < size; dsize++) *dst++ = *src++;
+        return size;
+    }
+    for(i = 0; i < size; i++, src++) {
+        if(src[0] == 3 && i >= 2 && !src[-1] && !src[-2] && i < size-1 && src[1] < 4) {
+            dst[dsize++] = src[1];
+            src++;
+            i++;
+        } else
+            dst[dsize++] = *src;
+    }
+    return dsize;
+}
 
 /** Initialize a VC1/WMV3 decoder
  * @todo TODO: Handle VC-1 IDUs (Transport level?)
@@ -4145,44 +4194,47 @@
             av_log(avctx, AV_LOG_INFO, "Read %i bits in overflow\n", -count);
         }
     } else { // VC1/WVC1
-        int edata_size = avctx->extradata_size;
-        uint8_t *edata = avctx->extradata;
+        uint8_t *start = avctx->extradata, *end = avctx->extradata + avctx->extradata_size;
+        uint8_t *next; int size, buf2_size;
+        uint8_t *buf2 = NULL;
+        int seq_inited = 0, ep_inited = 0;
 
         if(avctx->extradata_size < 16) {
-            av_log(avctx, AV_LOG_ERROR, "Extradata size too small: %i\n", edata_size);
+            av_log(avctx, AV_LOG_ERROR, "Extradata size too small: %i\n", avctx->extradata_size);
             return -1;
         }
-        while(edata_size > 8) {
-            // test if we've found header
-            if(AV_RB32(edata) == 0x0000010F) {
-                edata += 4;
-                edata_size -= 4;
+
+        buf2 = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+        if(start[0]) start++; // in WVC1 extradata first byte is its size
+        next = start;
+        for(; next < end; start = next){
+            next = find_next_marker(start + 4, end);
+            size = next - start - 4;
+            if(size <= 0) continue;
+            buf2_size = vc1_unescape_buffer(start + 4, size, buf2);
+            init_get_bits(&gb, buf2, buf2_size * 8);
+            switch(AV_RB32(start)){
+            case VC1_CODE_SEQHDR:
+                if(decode_sequence_header(avctx, &gb) < 0){
+                    av_free(buf2);
+                    return -1;
+                }
+                seq_inited = 1;
+                break;
+            case VC1_CODE_ENTRYPOINT:
+                if(decode_entry_point(avctx, &gb) < 0){
+                    av_free(buf2);
+                    return -1;
+                }
+                ep_inited = 1;
                 break;
             }
-            edata_size--;
-            edata++;
         }
-
-        init_get_bits(&gb, edata, edata_size*8);
-
-        if (decode_sequence_header(avctx, &gb) < 0)
-          return -1;
-
-        while(edata_size > 8) {
-            // test if we've found entry point
-            if(AV_RB32(edata) == 0x0000010E) {
-                edata += 4;
-                edata_size -= 4;
-                break;
-            }
-            edata_size--;
-            edata++;
+        av_free(buf2);
+        if(!seq_inited || !ep_inited){
+            av_log(avctx, AV_LOG_ERROR, "Incomplete extradata\n");
+            return -1;
         }
-
-        init_get_bits(&gb, edata, edata_size*8);
-
-        if (decode_entry_point(avctx, &gb) < 0)
-          return -1;
     }
     avctx->has_b_frames= !!(avctx->max_b_frames);
     s->low_delay = !avctx->has_b_frames;
@@ -4246,17 +4298,49 @@
         s->current_picture_ptr= &s->picture[i];
     }
 
-    //for advanced profile we need to unescape buffer
+    //for advanced profile we may need to parse and unescape data
     if (avctx->codec_id == CODEC_ID_VC1) {
-        int i, buf_size2;
-        buf2 = av_malloc(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
-        buf_size2 = 0;
-        for(i = 0; i < buf_size; i++) {
-            if(buf[i] == 3 && i >= 2 && !buf[i-1] && !buf[i-2] && i < buf_size-1 && buf[i+1] < 4) {
-                buf2[buf_size2++] = buf[i+1];
-                i++;
-            } else
-                buf2[buf_size2++] = buf[i];
+        int buf_size2 = 0;
+        buf2 = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
+
+        if(IS_MARKER(AV_RB32(buf))){ /* frame starts with marker and needs to be parsed */
+            uint8_t *dst = buf2, *start, *end, *next;
+            int size;
+
+            next = buf;
+            for(start = buf, end = buf + buf_size; next < end; start = next){
+                next = find_next_marker(start + 4, end);
+                size = next - start - 4;
+                if(size <= 0) continue;
+                switch(AV_RB32(start)){
+                case VC1_CODE_FRAME:
+                    buf_size2 = vc1_unescape_buffer(start + 4, size, buf2);
+                    break;
+                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);
+                    break;
+                case VC1_CODE_SLICE:
+                    av_log(avctx, AV_LOG_ERROR, "Sliced decoding is not implemented (yet)\n");
+                    av_free(buf2);
+                    return -1;
+                }
+            }
+        }else if(v->interlace && ((buf[0] & 0xC0) == 0xC0)){ /* WVC1 interlaced stores both fields divided by marker */
+            uint8_t *divider;
+
+            divider = find_next_marker(buf, buf + buf_size);
+            if((divider == (buf + buf_size)) || AV_RB32(divider) != VC1_CODE_FIELD){
+                av_log(avctx, AV_LOG_ERROR, "Error in WVC1 interlaced frame\n");
+                return -1;
+            }
+
+            buf_size2 = vc1_unescape_buffer(buf, divider - buf, buf2);
+            // TODO
+            av_free(buf2);return -1;
+        }else{
+            buf_size2 = vc1_unescape_buffer(buf, buf_size, buf2);
         }
         init_get_bits(&s->gb, buf2, buf_size2*8);
     } else