From 77aa841ba7f4249dceaea6470cb025f976a6e57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20Ni=C3=9Fl?= Date: Sun, 20 Feb 2011 23:38:32 +0100 Subject: vdpau_mpeg12: fix frame duration calculation when repeating frames or fields. Frame duration calculation for repeated frames or fields is now correct, but video_out_vdpau.c needs to be adjusted too, because for now it will show for example 1.5x top field and 1.5x bottom field instead of 1x top field, 1x bottom field and 1x top field again. --- src/video_dec/libvdpau/vdpau_mpeg12.c | 177 ++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/video_dec/libvdpau/vdpau_mpeg12.c b/src/video_dec/libvdpau/vdpau_mpeg12.c index d771fd364..1067f8634 100644 --- a/src/video_dec/libvdpau/vdpau_mpeg12.c +++ b/src/video_dec/libvdpau/vdpau_mpeg12.c @@ -118,6 +118,7 @@ typedef struct { int slices_pos, slices_pos_top; int progressive_frame; + int repeat_first_field; } picture_t; @@ -126,14 +127,27 @@ typedef struct { uint32_t coded_width; uint32_t coded_height; - uint64_t video_step; /* frame duration in pts units */ - uint64_t reported_video_step; /* frame duration in pts units */ + double video_step; /* frame duration in pts units */ + double reported_video_step; /* frame duration in pts units */ double ratio; + VdpDecoderProfile profile; + int horizontal_size_value; + int vertical_size_value; + int aspect_ratio_information; + int frame_rate_code; + int progressive_sequence; int chroma; + int horizontal_size_extension; + int vertical_size_extension; + int frame_rate_extension_n; + int frame_rate_extension_d; + int display_horizontal_size; + int display_vertical_size; int top_field_first; int have_header; + int have_display_extension; uint8_t *buf; /* accumulate data */ int bufseek; @@ -200,6 +214,7 @@ static void reset_picture( picture_t *pic ) pic->slices_pos = 0; pic->slices_pos_top = 0; pic->progressive_frame = 0; + pic->repeat_first_field = 0; } @@ -245,7 +260,7 @@ static void free_sequence( sequence_t *sequence ) sequence->have_header = 0; sequence->profile = VDP_DECODER_PROFILE_MPEG1; sequence->chroma = 0; - sequence->video_step = 3600; + sequence->video_step = 3600; reset_sequence( sequence, 1 ); } @@ -257,35 +272,23 @@ static void sequence_header( vdpau_mpeg12_decoder_t *this_gen, uint8_t *buf, int int i, j; + if ( !sequence->have_header ) + sequence->have_header = 1; + + sequence->profile = VDP_DECODER_PROFILE_MPEG1; + sequence->horizontal_size_extension = 0; + sequence->vertical_size_extension = 0; + sequence->have_display_extension = 0; + bits_reader_set( &sequence->br, buf, len ); - sequence->coded_width = read_bits( &sequence->br, 12 ); - lprintf( "coded_width: %d\n", sequence->coded_width ); - sequence->coded_height = read_bits( &sequence->br, 12 ); - lprintf( "coded_height: %d\n", sequence->coded_height ); - int rt = read_bits( &sequence->br, 4 ); - switch ( rt ) { - case 1: sequence->ratio = 1.0; break; - case 2: sequence->ratio = 4.0/3.0; break; - case 3: sequence->ratio = 16.0/9.0; break; - case 4: sequence->ratio = 2.21; break; - default: sequence->ratio = (double)sequence->coded_width/(double)sequence->coded_height; - } - lprintf( "ratio: %d\n", rt ); - int fr = read_bits( &sequence->br, 4 ); - switch ( fr ) { - case 1: sequence->video_step = 3913; break; /* 23.976.. */ - case 2: sequence->video_step = 3750; break; /* 24 */ - case 3: sequence->video_step = 3600; break; /* 25 */ - case 4: sequence->video_step = 3003; break; /* 29.97.. */ - case 5: sequence->video_step = 3000; break; /* 30 */ - case 6: sequence->video_step = 1800; break; /* 50 */ - case 7: sequence->video_step = 1525; break; /* 59.94.. */ - case 8: sequence->video_step = 1509; break; /* 60 */ - } - if (sequence->reported_video_step != sequence->video_step) { - _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_FRAME_DURATION, (sequence->reported_video_step = sequence->video_step) ); - } - lprintf( "frame_rate: %d\n", fr ); + sequence->horizontal_size_value = read_bits( &sequence->br, 12 ); + lprintf( "horizontal_size_value: %d\n", sequence->horizontal_size_value ); + sequence->vertical_size_value = read_bits( &sequence->br, 12 ); + lprintf( "vertical_size_value: %d\n", sequence->vertical_size_value ); + sequence->aspect_ratio_information = read_bits( &sequence->br, 4 ); + lprintf( "aspect_ratio_information: %d\n", sequence->aspect_ratio_information ); + sequence->frame_rate_code = read_bits( &sequence->br, 4 ); + lprintf( "frame_rate_code: %d\n", sequence->frame_rate_code ); int tmp; tmp = read_bits( &sequence->br, 18 ); lprintf( "bit_rate_value: %d\n", tmp ); @@ -319,9 +322,72 @@ static void sequence_header( vdpau_mpeg12_decoder_t *this_gen, uint8_t *buf, int memset( sequence->picture.vdp_infos.non_intra_quantizer_matrix, 16, 64 ); memset( sequence->picture.vdp_infos2.non_intra_quantizer_matrix, 16, 64 ); } +} - if ( !sequence->have_header ) { - sequence->have_header = 1; + + +static void process_sequence_mpeg12_dependent_data( vdpau_mpeg12_decoder_t *this_gen ) +{ + sequence_t *sequence = (sequence_t*)&this_gen->sequence; + + int frame_rate_value_n, frame_rate_value_d; + + sequence->coded_width = sequence->horizontal_size_value | (sequence->horizontal_size_extension << 14); + sequence->coded_height = sequence->vertical_size_value | (sequence->vertical_size_extension << 14); + + switch ( sequence->frame_rate_code ) { + case 1: frame_rate_value_n = 24; frame_rate_value_d = 1001; break; /* 23.976.. */ + case 2: frame_rate_value_n = 24; frame_rate_value_d = 1000; break; /* 24 */ + case 3: frame_rate_value_n = 25; frame_rate_value_d = 1000; break; /* 25 */ + case 4: frame_rate_value_n = 30; frame_rate_value_d = 1001; break; /* 29.97.. */ + case 5: frame_rate_value_n = 30; frame_rate_value_d = 1000; break; /* 30 */ + case 6: frame_rate_value_n = 50; frame_rate_value_d = 1000; break; /* 50 */ + case 7: frame_rate_value_n = 60; frame_rate_value_d = 1001; break; /* 59.94.. */ + case 8: frame_rate_value_n = 60; frame_rate_value_d = 1000; break; /* 60 */ + default: frame_rate_value_n = 50; frame_rate_value_d = 1000; /* assume 50 */ + } + + sequence->video_step = 90.0 * (frame_rate_value_d * (sequence->frame_rate_extension_d + 1)) + / (frame_rate_value_n * (sequence->frame_rate_extension_n + 1)); + + if ( sequence->profile==VDP_DECODER_PROFILE_MPEG1 ) { + double pel_aspect_ratio; /* height / width */ + + switch ( sequence->aspect_ratio_information ) { + case 1: pel_aspect_ratio = 1.0000; + case 2: pel_aspect_ratio = 0.6735; + case 3: pel_aspect_ratio = 0.7031; + case 4: pel_aspect_ratio = 0.7615; + case 5: pel_aspect_ratio = 0.8055; + case 6: pel_aspect_ratio = 0.8437; + case 7: pel_aspect_ratio = 0.8935; + case 8: pel_aspect_ratio = 0.9157; + case 9: pel_aspect_ratio = 0.9815; + case 10: pel_aspect_ratio = 1.0255; + case 11: pel_aspect_ratio = 1.0695; + case 12: pel_aspect_ratio = 1.0950; + case 13: pel_aspect_ratio = 1.1575; + case 14: pel_aspect_ratio = 1.2015; + default: pel_aspect_ratio = 1.0000; /* fallback */ + } + + sequence->ratio = ((double)sequence->coded_width/(double)sequence->coded_height)/pel_aspect_ratio; + } + else { + switch ( sequence->aspect_ratio_information ) { + case 1: sequence->ratio = sequence->have_display_extension + ? ((double)sequence->display_horizontal_size/(double)sequence->display_vertical_size)/1.0 + : ((double)sequence->coded_width/(double)sequence->coded_height)/1.0; + break; + case 2: sequence->ratio = 4.0/3.0; break; + case 3: sequence->ratio = 16.0/9.0; break; + case 4: sequence->ratio = 2.21; break; + default: sequence->ratio = ((double)sequence->coded_width/(double)sequence->coded_height)/1.0; + } + } + + if ( sequence->have_header == 1 ) { + sequence->have_header = 2; _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_VIDEO_WIDTH, sequence->coded_width ); _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, sequence->coded_height ); _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_VIDEO_RATIO, ((double)10000*sequence->ratio) ); @@ -338,6 +404,9 @@ static void sequence_header( vdpau_mpeg12_decoder_t *this_gen, uint8_t *buf, int data.aspect = sequence->ratio; xine_event_send( this_gen->stream, &event ); } + else if ( sequence->have_header == 2 && sequence->reported_video_step != sequence->video_step ) { + _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_FRAME_DURATION, (sequence->reported_video_step = sequence->video_step) ); + } } @@ -346,6 +415,8 @@ static void picture_header( vdpau_mpeg12_decoder_t *this_gen, uint8_t *buf, int { sequence_t *sequence = (sequence_t*)&this_gen->sequence; + process_sequence_mpeg12_dependent_data(this_gen); + if ( sequence->profile==VDP_DECODER_PROFILE_MPEG1 ) sequence->picture.vdp_infos.picture_structure = PICTURE_FRAME; @@ -407,8 +478,8 @@ static void sequence_extension( sequence_t *sequence, uint8_t *buf, int len ) default: sequence->profile = VDP_DECODER_PROFILE_MPEG2_MAIN; } skip_bits( &sequence->br, 4 ); - tmp = read_bits( &sequence->br, 1 ); - lprintf( "progressive_sequence: %d\n", tmp ); + sequence->progressive_sequence = read_bits( &sequence->br, 1 ); + lprintf( "progressive_sequence: %d\n", sequence->progressive_sequence ); if ( read_bits( &sequence->br, 2 ) == 2 ) sequence->chroma = VO_CHROMA_422; tmp = read_bits( &sequence->br, 2 ); @@ -423,10 +494,10 @@ static void sequence_extension( sequence_t *sequence, uint8_t *buf, int len ) lprintf( "vbv_buffer_size_extension: %d\n", tmp ); tmp = read_bits( &sequence->br, 1 ); lprintf( "low_delay: %d\n", tmp ); - tmp = read_bits( &sequence->br, 2 ); - lprintf( "frame_rate_extension_n: %d\n", tmp ); - tmp = read_bits( &sequence->br, 5 ); - lprintf( "frame_rate_extension_d: %d\n", tmp ); + sequence->frame_rate_extension_n = read_bits( &sequence->br, 2 ); + lprintf( "frame_rate_extension_n: %d\n", sequence->frame_rate_extension_n ); + sequence->frame_rate_extension_d = read_bits( &sequence->br, 5 ); + lprintf( "frame_rate_extension_d: %d\n", sequence->frame_rate_extension_d ); } @@ -464,8 +535,8 @@ static void picture_coding_extension( sequence_t *sequence, uint8_t *buf, int le lprintf( "intra_vlc_format: %d\n", infos->intra_vlc_format ); infos->alternate_scan = read_bits( &sequence->br, 1 ); lprintf( "alternate_scan: %d\n", infos->alternate_scan ); - tmp = read_bits( &sequence->br, 1 ); - lprintf( "repeat_first_field: %d\n", tmp ); + sequence->picture.repeat_first_field = read_bits( &sequence->br, 1 ); + lprintf( "repeat_first_field: %d\n", sequence->picture.repeat_first_field ); tmp = read_bits( &sequence->br, 1 ); lprintf( "chroma_420_type: %d\n", tmp ); sequence->picture.progressive_frame = read_bits( &sequence->br, 1 ); @@ -727,7 +798,6 @@ static void decode_picture( vdpau_mpeg12_decoder_t *vd, uint8_t end_of_sequence img->pts = seq->seq_pts; seq->seq_pts = 0; /* reset */ img->bad_frame = 0; - img->duration = seq->video_step; if ( end_of_sequence ) { if ( seq->backward_ref ) @@ -735,6 +805,7 @@ static void decode_picture( vdpau_mpeg12_decoder_t *vd, uint8_t end_of_sequence seq->backward_ref = NULL; } +#if 0 /* trying to deal with (french) buggy streams that randomly set bottom_field_first while stream is top_field_first. So we assume that when top_field_first is set one time, the stream _is_ top_field_first. */ @@ -742,6 +813,9 @@ static void decode_picture( vdpau_mpeg12_decoder_t *vd, uint8_t end_of_sequence if ( pic->vdp_infos.top_field_first ) seq->top_field_first = 1; img->top_field_first = seq->top_field_first; +#else + img->top_field_first = pic->vdp_infos.top_field_first; +#endif /* progressive_frame is unreliable with most mpeg2 streams */ if ( pic->vdp_infos.picture_structure!=PICTURE_FRAME ) @@ -749,6 +823,25 @@ static void decode_picture( vdpau_mpeg12_decoder_t *vd, uint8_t end_of_sequence else img->progressive_frame = pic->progressive_frame; + img->repeat_first_field = pic->repeat_first_field; + + double duration = seq->video_step; + + if ( img->repeat_first_field ) { + if( !seq->progressive_sequence && pic->progressive_frame ) { + /* decoder should output 3 fields, so adjust duration to + count on this extra field time */ + duration *= 3; + duration /= 2; + } else if ( seq->progressive_sequence ) { + /* for progressive sequences the output should repeat the + frame 1 or 2 times depending on top_field_first flag. */ + duration *= (pic->vdp_infos.top_field_first ? 3 : 2); + } + } + + img->duration = (int)(duration + .5); + if ( pic->vdp_infos.picture_coding_type!=B_FRAME ) { if ( pic->vdp_infos.picture_coding_type==I_FRAME && !seq->backward_ref ) { img->pts = 0; -- cgit v1.2.3