summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author"Torsten Jager" <t.jager@gmx.de>2011-12-27 15:11:28 +0100
committer"Torsten Jager" <t.jager@gmx.de>2011-12-27 15:11:28 +0100
commit761030ff507cea3b6bd9bca4a755811725fdde1a (patch)
treed6f71cb6a572035abd592e89f94ce317b2477e0e
parent8e8d3892412c5b3166efbc9aa4571dcaf2cc2a57 (diff)
downloadxine-lib-761030ff507cea3b6bd9bca4a755811725fdde1a.tar.gz
xine-lib-761030ff507cea3b6bd9bca4a755811725fdde1a.tar.bz2
Fixes nasty mpeg2 on ts A/V lag when using ff.
--HG-- branch : point-release extra : rebase_source : 6e059c732a63d40b65b09f4ef725ec5ca45c4c1c
-rw-r--r--src/combined/ffmpeg/ff_video_decoder.c122
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);