mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
General approach to parsing chunks in VC-1 AP
Originally committed as revision 7803 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
14c49573d8
commit
77ccd3ba54
164
libavcodec/vc1.c
164
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;
|
||||
|
||||
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 @@ 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
|
||||
|
Loading…
Reference in New Issue
Block a user