summaryrefslogtreecommitdiff
path: root/src/libffmpeg
diff options
context:
space:
mode:
authorJames Stembridge <jstembridge@users.sourceforge.net>2004-09-11 20:01:38 +0000
committerJames Stembridge <jstembridge@users.sourceforge.net>2004-09-11 20:01:38 +0000
commitabb6ce74beb401ef996c7a66f9b103d4fa566640 (patch)
treeb2a763cadd4369944fbdd7c1ce46a1615a74ebb3 /src/libffmpeg
parenta958fd5a24107fb894903fc5f5955e6d69eb2de0 (diff)
downloadxine-lib-abb6ce74beb401ef996c7a66f9b103d4fa566640.tar.gz
xine-lib-abb6ce74beb401ef996c7a66f9b103d4fa566640.tar.bz2
Support for H.264/AVC video
CVS patchset: 6959 CVS date: 2004/09/11 20:01:38
Diffstat (limited to 'src/libffmpeg')
-rw-r--r--src/libffmpeg/libavcodec/cabac.c1
-rw-r--r--src/libffmpeg/libavcodec/cabac.h9
-rw-r--r--src/libffmpeg/libavcodec/h264.c185
-rw-r--r--src/libffmpeg/video_decoder.c96
4 files changed, 206 insertions, 85 deletions
diff --git a/src/libffmpeg/libavcodec/cabac.c b/src/libffmpeg/libavcodec/cabac.c
index 2ae996a39..9d56e23fc 100644
--- a/src/libffmpeg/libavcodec/cabac.c
+++ b/src/libffmpeg/libavcodec/cabac.c
@@ -93,6 +93,7 @@ void ff_init_cabac_encoder(CABACContext *c, uint8_t *buf, int buf_size){
void ff_init_cabac_decoder(CABACContext *c, const uint8_t *buf, int buf_size){
c->bytestream_start=
c->bytestream= buf;
+ c->bytestream_end= buf + buf_size;
c->low= *c->bytestream++;
c->low= (c->low<<9) + ((*c->bytestream++)<<1);
diff --git a/src/libffmpeg/libavcodec/cabac.h b/src/libffmpeg/libavcodec/cabac.h
index 05c47363d..21085b21e 100644
--- a/src/libffmpeg/libavcodec/cabac.h
+++ b/src/libffmpeg/libavcodec/cabac.h
@@ -39,6 +39,7 @@ typedef struct CABACContext{
uint8_t mps_state[2*64]; ///< transIdxMPS
const uint8_t *bytestream_start;
const uint8_t *bytestream;
+ const uint8_t *bytestream_end;
int bits_left; ///<
PutBitContext pb;
}CABACContext;
@@ -253,7 +254,9 @@ static inline void renorm_cabac_decoder(CABACContext *c){
c->range+= c->range;
c->low+= c->low;
if(--c->bits_left == 0){
- c->low+= *c->bytestream++;
+ if(c->bytestream < c->bytestream_end)
+ c->low+= *c->bytestream;
+ c->bytestream++;
c->bits_left= 8;
}
}
@@ -298,7 +301,9 @@ static inline int get_cabac_bypass(CABACContext *c){
c->low += c->low;
if(--c->bits_left == 0){
- c->low+= *c->bytestream++;
+ if(c->bytestream < c->bytestream_end)
+ c->low+= *c->bytestream;
+ c->bytestream++;
c->bits_left= 8;
}
diff --git a/src/libffmpeg/libavcodec/h264.c b/src/libffmpeg/libavcodec/h264.c
index 594a4b264..a456e6074 100644
--- a/src/libffmpeg/libavcodec/h264.c
+++ b/src/libffmpeg/libavcodec/h264.c
@@ -82,6 +82,10 @@ typedef struct SPS{
int crop_bottom; ///< frame_cropping_rect_bottom_offset
int vui_parameters_present_flag;
AVRational sar;
+ int timing_info_present_flag;
+ uint32_t num_units_in_tick;
+ uint32_t time_scale;
+ int fixed_frame_rate_flag;
short offset_for_ref_frame[256]; //FIXME dyn aloc?
}SPS;
@@ -147,6 +151,11 @@ typedef struct H264Context{
uint8_t *rbsp_buffer;
int rbsp_buffer_size;
+ // AVC
+ int is_avc; // != 0 if data is avc variant of h264
+ int got_avcC; // flag to parse avcC data only once
+ int nal_length_size; // Number of bytes used for nal length (1, 2 or 4)
+
int chroma_qp; //QPc
int prev_mb_skiped; //FIXME remove (IMHO not used)
@@ -738,6 +747,9 @@ static inline int check_intra_pred_mode(H264Context *h, int mode){
static const int8_t top [7]= {LEFT_DC_PRED8x8, 1,-1,-1};
static const int8_t left[7]= { TOP_DC_PRED8x8,-1, 2,-1,DC_128_PRED8x8};
+ if(mode < 0 || mode > 6)
+ return -1;
+
if(!(h->top_samples_available&0x8000)){
mode= top[ mode ];
if(mode<0){
@@ -2257,6 +2269,17 @@ static int decode_init(AVCodecContext *avctx){
decode_init_vlc(h);
+ if(avctx->codec_tag != 0x31637661) // avc1
+ h->is_avc = 0;
+ else {
+ if((avctx->extradata_size == 0) || (avctx->extradata == NULL)) {
+ av_log(avctx, AV_LOG_ERROR, "AVC codec requires avcC data\n");
+ return -1;
+ }
+ h->is_avc = 1;
+ h->got_avcC = 0;
+ }
+
return 0;
}
@@ -2314,6 +2337,8 @@ static inline void xchg_mb_border(H264Context *h, uint8_t *src_y, uint8_t *src_c
MpegEncContext * const s = &h->s;
int temp8, i;
uint64_t temp64;
+ int deblock_left = (s->mb_x > 0);
+ int deblock_top = (s->mb_y > 0);
src_y -= linesize + 1;
src_cb -= uvlinesize + 1;
@@ -2324,21 +2349,29 @@ t= a;\
if(xchg)\
a= b;\
b= t;
-
- for(i=0; i<17; i++){
- XCHG(h->left_border[i ], src_y [i* linesize], temp8, xchg);
+
+ if(deblock_left){
+ for(i = !deblock_top; i<17; i++){
+ XCHG(h->left_border[i ], src_y [i* linesize], temp8, xchg);
+ }
+ }
+
+ if(deblock_top){
+ XCHG(*(uint64_t*)(h->top_border[s->mb_x]+0), *(uint64_t*)(src_y +1), temp64, xchg);
+ XCHG(*(uint64_t*)(h->top_border[s->mb_x]+8), *(uint64_t*)(src_y +9), temp64, 1);
}
-
- XCHG(*(uint64_t*)(h->top_border[s->mb_x]+0), *(uint64_t*)(src_y +1), temp64, xchg);
- XCHG(*(uint64_t*)(h->top_border[s->mb_x]+8), *(uint64_t*)(src_y +9), temp64, 1);
if(!(s->flags&CODEC_FLAG_GRAY)){
- for(i=0; i<9; i++){
- XCHG(h->left_border[i+17 ], src_cb[i*uvlinesize], temp8, xchg);
- XCHG(h->left_border[i+17+9], src_cr[i*uvlinesize], temp8, xchg);
+ if(deblock_left){
+ for(i = !deblock_top; i<9; i++){
+ XCHG(h->left_border[i+17 ], src_cb[i*uvlinesize], temp8, xchg);
+ XCHG(h->left_border[i+17+9], src_cr[i*uvlinesize], temp8, xchg);
+ }
+ }
+ if(deblock_top){
+ XCHG(*(uint64_t*)(h->top_border[s->mb_x]+16), *(uint64_t*)(src_cb+1), temp64, 1);
+ XCHG(*(uint64_t*)(h->top_border[s->mb_x]+24), *(uint64_t*)(src_cr+1), temp64, 1);
}
- XCHG(*(uint64_t*)(h->top_border[s->mb_x]+16), *(uint64_t*)(src_cb+1), temp64, 1);
- XCHG(*(uint64_t*)(h->top_border[s->mb_x]+24), *(uint64_t*)(src_cr+1), temp64, 1);
}
}
@@ -3039,6 +3072,11 @@ static int decode_slice_header(H264Context *h){
s->avctx->width = s->width;
s->avctx->height = s->height;
s->avctx->sample_aspect_ratio= h->sps.sar;
+
+ if(h->sps.timing_info_present_flag && h->sps.fixed_frame_rate_flag){
+ s->avctx->frame_rate = h->sps.time_scale;
+ s->avctx->frame_rate_base = h->sps.num_units_in_tick;
+ }
}
if(first_mb_in_slice == 0){
@@ -4479,17 +4517,15 @@ decode_intra_mb:
} else {
ref[list][i] = -1;
}
- h->ref_cache[list][ scan8[4*i] ]=h->ref_cache[list][ scan8[4*i]+1 ]=
+ h->ref_cache[list][ scan8[4*i]+1 ]=
h->ref_cache[list][ scan8[4*i]+8 ]=h->ref_cache[list][ scan8[4*i]+9 ]= ref[list][i];
}
}
}
for(list=0; list<2; list++){
-
for(i=0; i<4; i++){
- //h->ref_cache[list][ scan8[4*i] ]=h->ref_cache[list][ scan8[4*i]+1 ]=
- //h->ref_cache[list][ scan8[4*i]+8 ]=h->ref_cache[list][ scan8[4*i]+9 ]= ref[list][i];
+ h->ref_cache[list][ scan8[4*i] ]=h->ref_cache[list][ scan8[4*i]+1 ];
if(IS_DIR(h->sub_mb_type[i], 0, list) && !IS_DIRECT(h->sub_mb_type[i])){
const int sub_mb_type= h->sub_mb_type[i];
@@ -5119,7 +5155,7 @@ static int decode_slice(H264Context *h){
ff_init_cabac_states( &h->cabac, ff_h264_lps_range, ff_h264_mps_state, ff_h264_lps_state, 64 );
ff_init_cabac_decoder( &h->cabac,
s->gb.buffer + get_bits_count(&s->gb)/8,
- ( s->gb.size_in_bits - get_bits_count(&s->gb) ) );
+ ( s->gb.size_in_bits - get_bits_count(&s->gb) + 7)/8);
/* calculate pre-state */
for( i= 0; i < 399; i++ ) {
int pre;
@@ -5138,20 +5174,20 @@ static int decode_slice(H264Context *h){
int ret = decode_mb_cabac(h);
int eos = get_cabac_terminate( &h->cabac ); /* End of Slice flag */
- hl_decode_mb(h);
+ if(ret>=0) hl_decode_mb(h);
/* XXX: useless as decode_mb_cabac it doesn't support that ... */
if( ret >= 0 && h->sps.mb_aff ) { //FIXME optimal? or let mb_decode decode 16x32 ?
s->mb_y++;
- ret = decode_mb_cabac(h);
+ if(ret>=0) ret = decode_mb_cabac(h);
eos = get_cabac_terminate( &h->cabac );
hl_decode_mb(h);
s->mb_y--;
}
- if( ret < 0 ) {
+ if( ret < 0 || h->cabac.bytestream > h->cabac.bytestream_end + 1) {
av_log(h->s.avctx, AV_LOG_ERROR, "error while decoding MB %d %d\n", s->mb_x, s->mb_y);
ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, (AC_ERROR|DC_ERROR|MV_ERROR)&part_mask);
return -1;
@@ -5182,13 +5218,13 @@ static int decode_slice(H264Context *h){
for(;;){
int ret = decode_mb_cavlc(h);
- hl_decode_mb(h);
+ if(ret>=0) hl_decode_mb(h);
if(ret>=0 && h->sps.mb_aff){ //FIXME optimal? or let mb_decode decode 16x32 ?
s->mb_y++;
ret = decode_mb_cavlc(h);
- hl_decode_mb(h);
+ if(ret>=0) hl_decode_mb(h);
s->mb_y--;
}
@@ -5301,32 +5337,34 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps){
sps->sar.den= 0;
}
// s->avctx->aspect_ratio= sar_width*s->width / (float)(s->height*sar_height);
+
+ if(get_bits1(&s->gb)){ /* overscan_info_present_flag */
+ get_bits1(&s->gb); /* overscan_appropriate_flag */
+ }
+
+ if(get_bits1(&s->gb)){ /* video_signal_type_present_flag */
+ get_bits(&s->gb, 3); /* video_format */
+ get_bits1(&s->gb); /* video_full_range_flag */
+ if(get_bits1(&s->gb)){ /* colour_description_present_flag */
+ get_bits(&s->gb, 8); /* colour_primaries */
+ get_bits(&s->gb, 8); /* transfer_characteristics */
+ get_bits(&s->gb, 8); /* matrix_coefficients */
+ }
+ }
+
+ if(get_bits1(&s->gb)){ /* chroma_location_info_present_flag */
+ get_ue_golomb(&s->gb); /* chroma_sample_location_type_top_field */
+ get_ue_golomb(&s->gb); /* chroma_sample_location_type_bottom_field */
+ }
+
+ sps->timing_info_present_flag = get_bits1(&s->gb);
+ if(sps->timing_info_present_flag){
+ sps->num_units_in_tick = get_bits_long(&s->gb, 32);
+ sps->time_scale = get_bits_long(&s->gb, 32);
+ sps->fixed_frame_rate_flag = get_bits1(&s->gb);
+ }
+
#if 0
-| overscan_info_present_flag |0 |u(1) |
-| if( overscan_info_present_flag ) | | |
-| overscan_appropriate_flag |0 |u(1) |
-| video_signal_type_present_flag |0 |u(1) |
-| if( video_signal_type_present_flag ) { | | |
-| video_format |0 |u(3) |
-| video_full_range_flag |0 |u(1) |
-| colour_description_present_flag |0 |u(1) |
-| if( colour_description_present_flag ) { | | |
-| colour_primaries |0 |u(8) |
-| transfer_characteristics |0 |u(8) |
-| matrix_coefficients |0 |u(8) |
-| } | | |
-| } | | |
-| chroma_location_info_present_flag |0 |u(1) |
-| if ( chroma_location_info_present_flag ) { | | |
-| chroma_sample_location_type_top_field |0 |ue(v) |
-| chroma_sample_location_type_bottom_field |0 |ue(v) |
-| } | | |
-| timing_info_present_flag |0 |u(1) |
-| if( timing_info_present_flag ) { | | |
-| num_units_in_tick |0 |u(32) |
-| time_scale |0 |u(32) |
-| fixed_frame_rate_flag |0 |u(1) |
-| } | | |
| nal_hrd_parameters_present_flag |0 |u(1) |
| if( nal_hrd_parameters_present_flag = = 1) | | |
| hrd_parameters( ) | | |
@@ -5579,7 +5617,15 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
int dst_length;
int bit_length;
uint8_t *ptr;
+ int i, nalsize = 0;
+ if(h->is_avc) {
+ if(buf_index >= buf_size) break;
+ nalsize = 0;
+ for(i = 0; i < h->nal_length_size; i++)
+ nalsize = (nalsize << 8) | buf[buf_index + i];
+ buf_index += h->nal_length_size;
+ } else {
// start code prefix search
for(; buf_index + 3 < buf_size; buf_index++){
// this should allways succeed in the first iteration
@@ -5590,6 +5636,7 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
if(buf_index+3 >= buf_size) break;
buf_index+=3;
+ }
ptr= decode_nal(h, buf + buf_index, &dst_length, &consumed, buf_size - buf_index);
if(ptr[dst_length - 1] == 0) dst_length--;
@@ -5599,6 +5646,9 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
av_log(h->s.avctx, AV_LOG_DEBUG, "NAL %d at %d length %d\n", h->nal_unit_type, buf_index, dst_length);
}
+ if (h->is_avc && (nalsize != consumed))
+ av_log(h->s.avctx, AV_LOG_ERROR, "AVC: Consumed only %d bytes instead of %d\n", consumed, nalsize);
+
buf_index += consumed;
if( s->hurry_up == 1 && h->nal_ref_idc == 0 )
@@ -5657,6 +5707,8 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
break;
case NAL_FILTER_DATA:
break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unknown NAL code: %d\n", h->nal_unit_type);
}
//FIXME move after where irt is set
@@ -5726,7 +5778,46 @@ static int decode_frame(AVCodecContext *avctx,
//printf("next:%d buf_size:%d last_index:%d\n", next, buf_size, s->parse_context.last_index);
}
- if(s->avctx->extradata_size && s->picture_number==0){
+ if(h->is_avc && !h->got_avcC) {
+ int i, cnt, poffs;
+ unsigned char *p = avctx->extradata;
+ if(avctx->extradata_size < 7) {
+ av_log(avctx, AV_LOG_ERROR, "avcC too short\n");
+ return -1;
+ }
+ if(*p != 1) {
+ av_log(avctx, AV_LOG_ERROR, "Unknown avcC version %d\n", *p);
+ return -1;
+ }
+ /* sps and pps in the avcC always have length coded with 2 bytes,
+ so put a fake nal_length_size = 2 while parsing them */
+ h->nal_length_size = 2;
+ poffs = 6;
+ // Decode sps from avcC
+ cnt = *(p+5) & 0x1f; // Number of sps
+ for (i = 0; i < cnt; i++) {
+ if(decode_nal_units(h, p + poffs, BE_16(p + poffs) + 2) != BE_16(p + poffs) + 2) {
+ av_log(avctx, AV_LOG_ERROR, "Decoding sps %d from avcC failed\n", i);
+ return -1;
+ }
+ poffs += BE_16(p + poffs) + 2;
+ }
+ // Decode pps from avcC
+ cnt = *(p + poffs++); // Number of pps
+ for (i = 0; i < cnt; i++) {
+ if(decode_nal_units(h, p + poffs, BE_16(p + poffs) + 2) != BE_16(p + poffs) + 2) {
+ av_log(avctx, AV_LOG_ERROR, "Decoding pps %d from avcC failed\n", i);
+ return -1;
+ }
+ poffs += BE_16(p + poffs) + 2;
+ }
+ // Now store right nal length size, that will be use to parse all other nals
+ h->nal_length_size = ((*(p+4))&0x03)+1;
+ // Do not reparse avcC
+ h->got_avcC = 1;
+ }
+
+ if(!h->is_avc && s->avctx->extradata_size && s->picture_number==0){
if(0 < decode_nal_units(h, s->avctx->extradata, s->avctx->extradata_size) )
return -1;
}
diff --git a/src/libffmpeg/video_decoder.c b/src/libffmpeg/video_decoder.c
index 35f88b1e1..7607ee2a1 100644
--- a/src/libffmpeg/video_decoder.c
+++ b/src/libffmpeg/video_decoder.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: video_decoder.c,v 1.26 2004/08/16 15:31:23 mroi Exp $
+ * $Id: video_decoder.c,v 1.27 2004/09/11 20:01:39 jstembridge Exp $
*
* xine video decoder plugin using ffmpeg
*
@@ -111,6 +111,12 @@ struct ff_video_decoder_s {
};
+static void set_stream_info(ff_video_decoder_t *this) {
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->aspect_ratio*10000);
+}
+
#ifdef ENABLE_DIRECT_RENDERING
/* called from ffmpeg to do direct rendering method 1 */
static int get_buffer(AVCodecContext *context, AVFrame *av_frame){
@@ -119,6 +125,13 @@ static int get_buffer(AVCodecContext *context, AVFrame *av_frame){
int width = context->width;
int height = context->height;
+ if(!this->bih.biWidth || !this->bih.biHeight) {
+ this->bih.biWidth = width;
+ this->bih.biHeight = height;
+ this->aspect_ratio = (double)width / (double)height;
+ set_stream_info(this);
+ }
+
avcodec_align_dimensions(context, &width, &height);
if( (this->context->pix_fmt != PIX_FMT_YUV420P) ||
@@ -174,7 +187,7 @@ static void release_buffer(struct AVCodecContext *context, AVFrame *av_frame){
}
#endif
-static void init_video_codec (ff_video_decoder_t *this, xine_bmiheader *bih) {
+static void init_video_codec (ff_video_decoder_t *this) {
/* force (width % 8 == 0), otherwise there will be
* display problems with Xv.
@@ -193,17 +206,6 @@ static void init_video_codec (ff_video_decoder_t *this, xine_bmiheader *bih) {
this->context->palctrl = &this->palette_control;
- if( bih && bih->biSize > sizeof(xine_bmiheader) ) {
- this->context->extradata_size = bih->biSize - sizeof(xine_bmiheader);
- this->context->extradata = malloc(this->context->extradata_size);
- memcpy( this->context->extradata,
- (uint8_t *)bih + sizeof(xine_bmiheader),
- this->context->extradata_size );
- }
-
- if(bih)
- this->context->bits_per_sample = bih->biBitCount;
-
/* Some codecs (eg rv10) copy flags in init so it's necessary to set
* this flag here in case we are going to use direct rendering */
if(this->codec->capabilities & CODEC_CAP_DR1) {
@@ -223,18 +225,10 @@ static void init_video_codec (ff_video_decoder_t *this, xine_bmiheader *bih) {
this->aspect_ratio = (double)this->bih.biWidth / (double)this->bih.biHeight;
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->aspect_ratio*10000);
+ set_stream_info(this);
this->stream->video_out->open (this->stream->video_out, this->stream);
- if (this->buf)
- free (this->buf);
-
- this->buf = xine_xmalloc (VIDEOBUFSIZE);
- this->bufsize = VIDEOBUFSIZE;
-
this->skipframes = 0;
if((this->context->pix_fmt == PIX_FMT_RGBA32) ||
@@ -340,7 +334,7 @@ static int ff_handle_mpeg_sequence(ff_video_decoder_t *this, mpeg_parser_t *pars
_x_abort();
}
- init_video_codec (this, NULL);
+ init_video_codec (this);
}
/* frame format change */
@@ -353,9 +347,7 @@ static int ff_handle_mpeg_sequence(ff_video_decoder_t *this, mpeg_parser_t *pars
this->bih.biWidth = parser->width;
this->bih.biHeight = parser->height;
this->aspect_ratio = parser->frame_aspect_ratio;
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->aspect_ratio * 10000);
+ set_stream_info(this);
event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
event.stream = this->stream;
@@ -699,7 +691,8 @@ static const ff_codec_t ff_video_lookup[] = {
{BUF_VIDEO_ASV2, CODEC_ID_ASV2, "ASV v2 Video (ffmpeg)"},
{BUF_VIDEO_ATIVCR1, CODEC_ID_VCR1, "ATI VCR-1 (ffmpeg)"},
{BUF_VIDEO_FLV1, CODEC_ID_FLV1, "Flash Video (ffmpeg)"},
- {BUF_VIDEO_QTRLE, CODEC_ID_QTRLE, "Apple Quicktime Animation/RLE (ffmpeg)"} };
+ {BUF_VIDEO_QTRLE, CODEC_ID_QTRLE, "Apple Quicktime Animation/RLE (ffmpeg)"},
+ {BUF_VIDEO_H264, CODEC_ID_H264, "H.264/AVC (ffmpeg"} };
static void ff_check_bufsize (ff_video_decoder_t *this, int size) {
if (size > this->bufsize) {
@@ -758,7 +751,14 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
/* init package containing bih */
memcpy ( &this->bih, buf->content, sizeof(xine_bmiheader) );
- init_video_codec (this, (xine_bmiheader *) buf->content );
+ if (this->bih.biSize > sizeof(xine_bmiheader)) {
+ this->context->extradata_size = this->bih.biSize - sizeof(xine_bmiheader);
+ this->context->extradata = malloc(this->context->extradata_size);
+ memcpy(this->context->extradata, buf->content + sizeof(xine_bmiheader),
+ this->context->extradata_size);
+ }
+
+ this->context->bits_per_sample = this->bih.biBitCount;
} else {
@@ -778,17 +778,17 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
"ffmpeg_video_dec: unknown header for buf type 0x%X\n", codec_type);
return;
}
-
- init_video_codec (this, NULL);
}
init_postprocess(this);
} else if (buf->decoder_flags & BUF_FLAG_SPECIAL) {
- /* take care of all the various types of special buffers */
+ /* take care of all the various types of special buffers
+ * note that order is important here */
lprintf("BUF_FLAG_SPECIAL\n");
- if (buf->decoder_info[1] == BUF_SPECIAL_STSD_ATOM) {
+ if (buf->decoder_info[1] == BUF_SPECIAL_STSD_ATOM &&
+ !this->context->extradata_size) {
lprintf("BUF_SPECIAL_STSD_ATOM\n");
this->context->extradata_size = buf->decoder_info[2];
@@ -796,6 +796,15 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
memcpy(this->context->extradata, buf->decoder_info_ptr[2],
buf->decoder_info[2]);
+ } else if (buf->decoder_info[1] == BUF_SPECIAL_DECODER_CONFIG &&
+ !this->context->extradata_size) {
+
+ lprintf("BUF_SPECIAL_DECODER_CONFIG\n");
+ this->context->extradata_size = buf->decoder_info[2];
+ this->context->extradata = xine_xmalloc(buf->decoder_info[2]);
+ memcpy(this->context->extradata, buf->decoder_info_ptr[2],
+ buf->decoder_info[2]);
+
} else if (buf->decoder_info[1] == BUF_SPECIAL_PALETTE) {
palette_entry_t *demuxer_palette;
@@ -862,9 +871,15 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
if (buf->pts)
this->pts = buf->pts;
- if ((this->decoder_ok && this->size) || this->is_mpeg12) {
+ if (this->size || this->is_mpeg12) {
- if ( (buf->decoder_flags & BUF_FLAG_FRAME_END) || this->is_mpeg12 ) {
+ if (!this->decoder_ok && !this->is_mpeg12 &&
+ (_x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED) != 0)) {
+ init_video_codec(this);
+ }
+
+ if (this->decoder_ok &&
+ ((buf->decoder_flags & BUF_FLAG_FRAME_END) || this->is_mpeg12)) {
vo_frame_t *img;
int free_img;
@@ -961,6 +976,13 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
this->size -= len;
offset += len;
+ if(!this->bih.biWidth || !this->bih.biHeight) {
+ this->bih.biWidth = this->context->width;
+ this->bih.biHeight = this->context->height;
+ this->aspect_ratio = (double)this->bih.biWidth / (double)this->bih.biHeight;
+ set_stream_info(this);
+ }
+
if (!got_picture || !this->av_frame->data[0]) {
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
"ffmpeg_video_dec: didn't get a picture, %d bytes left\n",
@@ -1079,7 +1101,7 @@ static void ff_reset (video_decoder_t *this_gen) {
this->size = 0;
- if(this->context)
+ if(this->context && this->decoder_ok)
avcodec_flush_buffers(this->context);
if (this->is_mpeg12)
@@ -1160,7 +1182,8 @@ static video_decoder_t *ff_video_open_plugin (video_decoder_class_t *class_gen,
this->context->opaque = this;
this->decoder_ok = 0;
- this->buf = NULL;
+ this->buf = xine_xmalloc(VIDEOBUFSIZE);
+ this->bufsize = VIDEOBUFSIZE;
this->is_mpeg12 = 0;
this->aspect_ratio = 0;
@@ -1262,6 +1285,7 @@ static uint32_t supported_video_types[] = {
BUF_VIDEO_ATIVCR1,
BUF_VIDEO_FLV1,
BUF_VIDEO_QTRLE,
+ BUF_VIDEO_H264,
0
};