diff options
author | James Stembridge <jstembridge@users.sourceforge.net> | 2004-09-11 20:01:38 +0000 |
---|---|---|
committer | James Stembridge <jstembridge@users.sourceforge.net> | 2004-09-11 20:01:38 +0000 |
commit | abb6ce74beb401ef996c7a66f9b103d4fa566640 (patch) | |
tree | b2a763cadd4369944fbdd7c1ce46a1615a74ebb3 | |
parent | a958fd5a24107fb894903fc5f5955e6d69eb2de0 (diff) | |
download | xine-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
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | src/demuxers/demux_qt.c | 28 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/cabac.c | 1 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/cabac.h | 9 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/h264.c | 185 | ||||
-rw-r--r-- | src/libffmpeg/video_decoder.c | 96 |
6 files changed, 232 insertions, 90 deletions
@@ -20,7 +20,7 @@ xine-lib (1-rc6) * Added experimental time stretching plugin: play stream faster or slower than original speed, optionally preserving pitch * Fixed another win32 dll crash (after playing several files) - * Added onfigure option for building xine with external ffmpeg library + * Added configure option for building xine with external ffmpeg library * Added api for finer playback speed control (requires frontend support) * Added support for QuickTime 6.3 DLLs * Improved response time on video grabber ports @@ -32,6 +32,7 @@ xine-lib (1-rc6) * Fixed wrong, very bright overlays on some DVDs [bug #1018193] * Fixed WIN32 replacement of gettimeofday [bug #995961] * Removed unistd.h from public header + * Added support for H.264/AVC video xine-lib (1-rc5) * add support for ejecting removable media on Solaris diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index a349bbc07..9f9099220 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -30,7 +30,7 @@ * build_frame_table * free_qt_info * - * $Id: demux_qt.c,v 1.191 2004/08/18 22:12:31 jstembridge Exp $ + * $Id: demux_qt.c,v 1.192 2004/09/11 20:01:39 jstembridge Exp $ * */ @@ -92,6 +92,7 @@ typedef unsigned int qt_atom; #define ESDS_ATOM QT_ATOM('e', 's', 'd', 's') #define WAVE_ATOM QT_ATOM('w', 'a', 'v', 'e') #define FRMA_ATOM QT_ATOM('f', 'r', 'm', 'a') +#define AVCC_ATOM QT_ATOM('a', 'v', 'c', 'C') #define IMA4_FOURCC ME_FOURCC('i', 'm', 'a', '4') #define MP4A_FOURCC ME_FOURCC('m', 'p', '4', 'a') @@ -101,6 +102,7 @@ typedef unsigned int qt_atom; #define TWOS_FOURCC ME_FOURCC('t', 'w', 'o', 's') #define SOWT_FOURCC ME_FOURCC('s', 'o', 'w', 't') #define RAW_FOURCC ME_FOURCC('r', 'a', 'w', ' ') +#define AVC1_FOURCC ME_FOURCC('a', 'v', 'c', '1') #define UDTA_ATOM QT_ATOM('u', 'd', 't', 'a') #define META_ATOM QT_ATOM('m', 'e', 't', 'a') @@ -262,7 +264,7 @@ typedef struct { /* formattag-like field that specifies codec in mp4 files */ unsigned int object_type_id; - /* decoder data pass information to the AAC decoder */ + /* decoder data pass information to the decoder */ void *decoder_config; int decoder_config_len; @@ -1229,6 +1231,14 @@ static qt_error parse_trak_atom (qt_trak *trak, } } + } else if (current_atom == AVCC_ATOM) { + + debug_atom_load(" avcC atom\n"); + + trak->decoder_config_len = current_atom_size - 8; + trak->decoder_config = realloc(trak->decoder_config, trak->decoder_config_len); + memcpy(trak->decoder_config, &trak_atom[i + 4], trak->decoder_config_len); + } else if (current_atom == STSZ_ATOM) { /* there should only be one of these atoms */ @@ -2581,8 +2591,18 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { if( video_trak->decoder_config ) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = video_trak->properties->video.codec_buftype; - buf->size = video_trak->decoder_config_len; - buf->content = video_trak->decoder_config; + + if (video_trak->properties->video.codec_fourcc == AVC1_FOURCC) { + buf->size = 0; + buf->decoder_flags = BUF_FLAG_SPECIAL|BUF_FLAG_HEADER; + buf->decoder_info[1] = BUF_SPECIAL_DECODER_CONFIG; + buf->decoder_info[2] = video_trak->decoder_config_len; + buf->decoder_info_ptr[2] = video_trak->decoder_config; + } else { + buf->size = video_trak->decoder_config_len; + buf->content = video_trak->decoder_config; + } + this->video_fifo->put (this->video_fifo, buf); } 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 }; |