summaryrefslogtreecommitdiff
path: root/libavcodec/vc1.c
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2007-02-02 06:45:21 +0000
committerKostya Shishkov <kostya.shishkov@gmail.com>2007-02-02 06:45:21 +0000
commit77ccd3ba546e8a420aea4c5b915df72abb49f7fd (patch)
tree7ea07d27affb5801c8c07f93c3acc4e56a568b3f /libavcodec/vc1.c
parent14c49573d82ef607005d2787cd099f7887a14793 (diff)
General approach to parsing chunks in VC-1 AP
Originally committed as revision 7803 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/vc1.c')
-rw-r--r--libavcodec/vc1.c164
1 files changed, 124 insertions, 40 deletions
diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c
index 0c17083039..722e885144 100644
--- a/libavcodec/vc1.c
+++ b/libavcodec/vc1.c
@@ -46,6 +46,19 @@ extern const uint16_t ff_msmp4_mb_i_table[64][2];
#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 @@ static void vc1_decode_blocks(VC1Context *v)
}
}
+#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 @@ static int vc1_decode_init(AVCodecContext *avctx)
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;
- 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;
+ 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_entry_point(avctx, &gb) < 0)
- return -1;
+ av_free(buf2);
+ if(!seq_inited || !ep_inited){
+ av_log(avctx, AV_LOG_ERROR, "Incomplete extradata\n");
+ return -1;
+ }
}
avctx->has_b_frames= !!(avctx->max_b_frames);
s->low_delay = !avctx->has_b_frames;
@@ -4246,17 +4298,49 @@ static int vc1_decode_frame(AVCodecContext *avctx,
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