diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/combined/ffmpeg/ff_video_decoder.c | 122 |
1 files changed, 72 insertions, 50 deletions
diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index a1d729df4..50357182a 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -96,6 +96,7 @@ struct ff_video_decoder_s { xine_stream_t *stream; int64_t pts; + int64_t last_pts; #ifdef AVCODEC_HAS_REORDERED_OPAQUE uint64_t pts_tag_mask; uint64_t pts_tag; @@ -433,6 +434,9 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type) break; } + /* dont want initial AV_NOPTS_VALUE here */ + this->context->reordered_opaque = 0; + } static void choose_speed_over_accuracy_cb(void *user_data, xine_cfg_entry_t *entry) { @@ -1081,6 +1085,54 @@ static void ff_handle_special_buffer (ff_video_decoder_t *this, buf_element_t *b } } +#ifdef AVCODEC_HAS_REORDERED_OPAQUE +static uint64_t ff_tag_pts(ff_video_decoder_t *this, uint64_t pts) +{ + return pts | this->pts_tag; +} + +static uint64_t ff_untag_pts(ff_video_decoder_t *this, uint64_t pts) +{ + if (this->pts_tag_mask == 0) + return pts; /* pts tagging inactive */ + + if (this->pts_tag != 0 && (pts & this->pts_tag_mask) != this->pts_tag) + return 0; /* reset pts if outdated while waiting for first pass (see below) */ + + return pts & ~this->pts_tag_mask; +} + +static void ff_check_pts_tagging(ff_video_decoder_t *this, uint64_t pts) +{ + if (this->pts_tag_mask == 0) + return; /* pts tagging inactive */ + if ((pts & this->pts_tag_mask) != this->pts_tag) { + this->pts_tag_stable_counter = 0; + return; /* pts still outdated */ + } + + /* the tag should be stable for 100 frames */ + this->pts_tag_stable_counter++; + + if (this->pts_tag != 0) { + if (this->pts_tag_stable_counter >= 100) { + /* first pass: reset pts_tag */ + this->pts_tag = 0; + this->pts_tag_stable_counter = 0; + } + } else if (pts == 0) + return; /* cannot detect second pass */ + else { + if (this->pts_tag_stable_counter >= 100) { + /* second pass: reset pts_tag_mask and pts_tag_counter */ + this->pts_tag_mask = 0; + this->pts_tag_counter = 0; + this->pts_tag_stable_counter = 0; + } + } +} +#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ + static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *buf) { vo_frame_t *img; @@ -1102,6 +1154,15 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu uint8_t *current; int next_flush; +#ifdef AVCODEC_HAS_REORDERED_OPAQUE + /* apply valid pts to first frame _starting_ thereafter only */ + if (this->pts && !this->context->reordered_opaque) { + this->context->reordered_opaque = + this->av_frame->reordered_opaque = ff_tag_pts (this, this->pts); + this->pts = 0; + } +#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ + got_picture = 0; if (!flush) { current = mpeg_parser_decode_data(this->mpeg_parser, @@ -1183,8 +1244,16 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu free_img = 0; } +#ifdef AVCODEC_HAS_REORDERED_OPAQUE + /* get back reordered pts */ + img->pts = ff_untag_pts (this, this->av_frame->reordered_opaque); + ff_check_pts_tagging (this, this->av_frame->reordered_opaque); + this->av_frame->reordered_opaque = 0; + this->context->reordered_opaque = 0; +#else img->pts = this->pts; this->pts = 0; +#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ if (this->av_frame->repeat_pict) img->duration = this->video_step * 3 / 2; @@ -1225,54 +1294,6 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu } } -#ifdef AVCODEC_HAS_REORDERED_OPAQUE -static uint64_t ff_tag_pts(ff_video_decoder_t *this, uint64_t pts) -{ - return pts | this->pts_tag; -} - -static uint64_t ff_untag_pts(ff_video_decoder_t *this, uint64_t pts) -{ - if (this->pts_tag_mask == 0) - return pts; /* pts tagging inactive */ - - if (this->pts_tag != 0 && (pts & this->pts_tag_mask) != this->pts_tag) - return 0; /* reset pts if outdated while waiting for first pass (see below) */ - - return pts & ~this->pts_tag_mask; -} - -static void ff_check_pts_tagging(ff_video_decoder_t *this, uint64_t pts) -{ - if (this->pts_tag_mask == 0) - return; /* pts tagging inactive */ - if ((pts & this->pts_tag_mask) != this->pts_tag) { - this->pts_tag_stable_counter = 0; - return; /* pts still outdated */ - } - - /* the tag should be stable for 100 frames */ - this->pts_tag_stable_counter++; - - if (this->pts_tag != 0) { - if (this->pts_tag_stable_counter >= 100) { - /* first pass: reset pts_tag */ - this->pts_tag = 0; - this->pts_tag_stable_counter = 0; - } - } else if (pts == 0) - return; /* cannot detect second pass */ - else { - if (this->pts_tag_stable_counter >= 100) { - /* second pass: reset pts_tag_mask and pts_tag_counter */ - this->pts_tag_mask = 0; - this->pts_tag_counter = 0; - this->pts_tag_stable_counter = 0; - } - } -} -#endif /* AVCODEC_HAS_REORDERED_OPAQUE */ - static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { uint8_t *chunk_buf = this->buf; AVRational avr00 = {0, 1}; @@ -1616,8 +1637,9 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { } else { /* decode */ - if (buf->pts) - this->pts = buf->pts; + /* PES: each valid pts shall be used only once */ + if (buf->pts && (buf->pts != this->last_pts)) + this->last_pts = this->pts = buf->pts; if ((buf->type & 0xFFFF0000) == BUF_VIDEO_MPEG) { ff_handle_mpeg12_buffer(this, buf); |