summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorReinhard Nißl <rnissl@gmx.de>2011-02-20 23:38:32 +0100
committerReinhard Nißl <rnissl@gmx.de>2011-02-20 23:38:32 +0100
commit77aa841ba7f4249dceaea6470cb025f976a6e57a (patch)
tree9d6ce9741e9c4db37d3917f16a164f693f1912a0 /src
parent4ab7d99460d0bcefba85b7285d3742cae2905314 (diff)
downloadxine-lib-77aa841ba7f4249dceaea6470cb025f976a6e57a.tar.gz
xine-lib-77aa841ba7f4249dceaea6470cb025f976a6e57a.tar.bz2
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.
Diffstat (limited to 'src')
-rw-r--r--src/video_dec/libvdpau/vdpau_mpeg12.c177
1 files changed, 135 insertions, 42 deletions
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;