Commit 62bc3b92 authored by Wim Taymans's avatar Wim Taymans

ext/ffmpeg/gstffmpegdec.c: Detect DTS or PTS as timestamps. This is done by...

ext/ffmpeg/gstffmpegdec.c: Detect DTS or PTS as timestamps. This is done by tracking frame reordering on the output a...

Original commit message from CVS:
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_class_init),
(gst_ffmpegdec_setcaps), (check_keyframe),
(gst_ffmpegdec_video_frame), (gst_ffmpegdec_sink_event),
(gst_ffmpegdec_set_property):
Detect DTS or PTS as timestamps. This is done by tracking frame
reordering on the output and making sure that timestamps don't go
backwards. Fixes #482660.
parent bebde6f8
2008-03-05 Wim Taymans <wim.taymans@collabora.co.uk>
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_class_init),
(gst_ffmpegdec_setcaps), (check_keyframe),
(gst_ffmpegdec_video_frame), (gst_ffmpegdec_sink_event),
(gst_ffmpegdec_set_property):
Detect DTS or PTS as timestamps. This is done by tracking frame
reordering on the output and making sure that timestamps don't go
backwards. Fixes #482660.
2008-02-11 Wim Taymans <wim.taymans@collabora.co.uk> 2008-02-11 Wim Taymans <wim.taymans@collabora.co.uk>
Patch by: Damien Lespiau <damien dot lespiau at gmail dot com> Patch by: Damien Lespiau <damien dot lespiau at gmail dot com>
......
common @ e02bd43f
Subproject commit 05a617c9043ddb78f8578195b18c166d7e1d4c2e Subproject commit e02bd43fe6b9e45536eccbf5b7a5f9eae62030fd
...@@ -73,6 +73,9 @@ struct _GstFFMpegDec ...@@ -73,6 +73,9 @@ struct _GstFFMpegDec
gboolean discont; gboolean discont;
guint64 next_ts; guint64 next_ts;
guint64 in_ts; guint64 in_ts;
GstClockTime last_out;
gboolean ts_is_dts;
gboolean has_b_frames;
/* parsing */ /* parsing */
AVCodecParserContext *pctx; AVCodecParserContext *pctx;
...@@ -301,7 +304,7 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) ...@@ -301,7 +304,7 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass * klass)
g_object_class_install_property (gobject_class, PROP_DEBUG_MV, g_object_class_install_property (gobject_class, PROP_DEBUG_MV,
g_param_spec_boolean ("debug-mv", "Debug motion vectors", g_param_spec_boolean ("debug-mv", "Debug motion vectors",
"Whether ffmpeg should print motion vectors on top of the image", "Whether ffmpeg should print motion vectors on top of the image",
DEFAULT_DEBUG_MV, G_PARAM_READWRITE)); DEFAULT_DEBUG_MV, G_PARAM_READWRITE));
} }
gstelement_class->change_state = gst_ffmpegdec_change_state; gstelement_class->change_state = gst_ffmpegdec_change_state;
...@@ -619,6 +622,11 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) ...@@ -619,6 +622,11 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer; ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;
ffmpegdec->context->draw_horiz_band = NULL; ffmpegdec->context->draw_horiz_band = NULL;
/* assume PTS as input, we will adapt when we detect timestamp reordering
* in the output frames. */
ffmpegdec->ts_is_dts = FALSE;
ffmpegdec->has_b_frames = FALSE;
/* get size and so */ /* get size and so */
gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
oclass->in_plugin->type, caps, ffmpegdec->context); oclass->in_plugin->type, caps, ffmpegdec->context);
...@@ -704,6 +712,11 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) ...@@ -704,6 +712,11 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
gst_structure_get_int (structure, "height", gst_structure_get_int (structure, "height",
&ffmpegdec->format.video.clip_height); &ffmpegdec->format.video.clip_height);
/* take into account the lowres property */
ffmpegdec->format.video.clip_width >>= ffmpegdec->lowres;
ffmpegdec->format.video.clip_height >>= ffmpegdec->lowres;
done: done:
GST_OBJECT_UNLOCK (ffmpegdec); GST_OBJECT_UNLOCK (ffmpegdec);
...@@ -1260,6 +1273,13 @@ check_keyframe (GstFFMpegDec * ffmpegdec) ...@@ -1260,6 +1273,13 @@ check_keyframe (GstFFMpegDec * ffmpegdec)
/* figure out if we are dealing with a keyframe */ /* figure out if we are dealing with a keyframe */
oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
/* remember that we have B frames, we need this for the DTS -> PTS conversion
* code */
if (!ffmpegdec->has_b_frames && ffmpegdec->picture->pict_type == FF_B_TYPE) {
GST_DEBUG_OBJECT (ffmpegdec, "we have B frames");
ffmpegdec->has_b_frames = TRUE;
}
is_itype = (ffmpegdec->picture->pict_type == FF_I_TYPE); is_itype = (ffmpegdec->picture->pict_type == FF_I_TYPE);
is_reference = (ffmpegdec->picture->reference == 1); is_reference = (ffmpegdec->picture->reference == 1);
...@@ -1387,7 +1407,7 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, ...@@ -1387,7 +1407,7 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
gboolean mode_switch; gboolean mode_switch;
gboolean decode; gboolean decode;
gint hurry_up = 0; gint hurry_up = 0;
GstClockTime out_timestamp, out_duration; GstClockTime out_timestamp, out_duration, out_pts;
*ret = GST_FLOW_OK; *ret = GST_FLOW_OK;
*outbuf = NULL; *outbuf = NULL;
...@@ -1434,7 +1454,6 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, ...@@ -1434,7 +1454,6 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
if (!decode) if (!decode)
ffmpegdec->context->hurry_up = hurry_up; ffmpegdec->context->hurry_up = hurry_up;
GST_DEBUG_OBJECT (ffmpegdec, "after decode: len %d, have_data %d", GST_DEBUG_OBJECT (ffmpegdec, "after decode: len %d, have_data %d",
len, have_data); len, have_data);
...@@ -1447,18 +1466,49 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, ...@@ -1447,18 +1466,49 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
if (len < 0 || have_data <= 0) if (len < 0 || have_data <= 0)
goto beach; goto beach;
GST_DEBUG_OBJECT (ffmpegdec, "picture: pts %" G_GUINT64_FORMAT, /* get pts */
ffmpegdec->picture->pts); out_pts = ffmpegdec->picture->pts;
GST_DEBUG_OBJECT (ffmpegdec, "picture: pts %" G_GUINT64_FORMAT, out_pts);
GST_DEBUG_OBJECT (ffmpegdec, "picture: num %d", GST_DEBUG_OBJECT (ffmpegdec, "picture: num %d",
ffmpegdec->picture->coded_picture_number); ffmpegdec->picture->coded_picture_number);
GST_DEBUG_OBJECT (ffmpegdec, "picture: ref %d",
ffmpegdec->picture->reference);
GST_DEBUG_OBJECT (ffmpegdec, "picture: display %d", GST_DEBUG_OBJECT (ffmpegdec, "picture: display %d",
ffmpegdec->picture->display_picture_number); ffmpegdec->picture->display_picture_number);
GST_DEBUG_OBJECT (ffmpegdec, "picture: opaque %p", GST_DEBUG_OBJECT (ffmpegdec, "picture: opaque %p",
ffmpegdec->picture->opaque); ffmpegdec->picture->opaque);
/* check if we are dealing with a keyframe here */ /* check if we are dealing with a keyframe here, this will also check if we
* are dealing with B frames. */
iskeyframe = check_keyframe (ffmpegdec); iskeyframe = check_keyframe (ffmpegdec);
/* check that the timestamps go upwards */
if (ffmpegdec->last_out != -1) {
if (ffmpegdec->last_out > out_pts) {
/* timestamps go backwards, this means frames were reordered and we must
* be dealing with DTS as the buffer timestamps */
ffmpegdec->ts_is_dts = TRUE;
GST_DEBUG_OBJECT (ffmpegdec,
"timestamp discont, we have DTS as timestamps");
}
}
ffmpegdec->last_out = out_pts;
if (ffmpegdec->ts_is_dts) {
/* we are dealing with DTS as the timestamps, only copy the DTS on the picture
* to the PTS of the output frame if we are dealing with a non-reference
* frame, else we leave the timestamp as -1, which will interpollate from the
* last outputted value. */
if (ffmpegdec->context->has_b_frames && ffmpegdec->has_b_frames &&
ffmpegdec->picture->reference && ffmpegdec->next_ts != -1) {
/* we have b frames and this picture is a reference picture, don't use the
* DTS as the PTS */
GST_DEBUG_OBJECT (ffmpegdec, "DTS as timestamps, interpollate");
out_pts = -1;
}
}
/* when we're waiting for a keyframe, see if we have one or drop the current /* when we're waiting for a keyframe, see if we have one or drop the current
* non-keyframe */ * non-keyframe */
if (G_UNLIKELY (ffmpegdec->waiting_for_key)) { if (G_UNLIKELY (ffmpegdec->waiting_for_key)) {
...@@ -1482,9 +1532,9 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, ...@@ -1482,9 +1532,9 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
* 3) else copy input timestamp * 3) else copy input timestamp
*/ */
out_timestamp = -1; out_timestamp = -1;
if (ffmpegdec->picture->pts != -1) { if (out_pts != -1) {
/* Get (interpolated) timestamp from FFMPEG */ /* Get (interpolated) timestamp from FFMPEG */
out_timestamp = (GstClockTime) ffmpegdec->picture->pts; out_timestamp = (GstClockTime) out_pts;
GST_LOG_OBJECT (ffmpegdec, "using timestamp %" GST_TIME_FORMAT GST_LOG_OBJECT (ffmpegdec, "using timestamp %" GST_TIME_FORMAT
" returned by ffmpeg", GST_TIME_ARGS (out_timestamp)); " returned by ffmpeg", GST_TIME_ARGS (out_timestamp));
} }
...@@ -1923,6 +1973,7 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) ...@@ -1923,6 +1973,7 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
if (ffmpegdec->opened) { if (ffmpegdec->opened) {
avcodec_flush_buffers (ffmpegdec->context); avcodec_flush_buffers (ffmpegdec->context);
} }
ffmpegdec->last_out = GST_CLOCK_TIME_NONE;
ffmpegdec->next_ts = GST_CLOCK_TIME_NONE; ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
gst_ffmpegdec_reset_qos (ffmpegdec); gst_ffmpegdec_reset_qos (ffmpegdec);
gst_ffmpegdec_flush_pcache (ffmpegdec); gst_ffmpegdec_flush_pcache (ffmpegdec);
...@@ -2298,7 +2349,7 @@ gst_ffmpegdec_set_property (GObject * object, ...@@ -2298,7 +2349,7 @@ gst_ffmpegdec_set_property (GObject * object,
ffmpegdec->do_padding = g_value_get_boolean (value); ffmpegdec->do_padding = g_value_get_boolean (value);
break; break;
case PROP_DEBUG_MV: case PROP_DEBUG_MV:
ffmpegdec->debug_mv = ffmpegdec->context->debug_mv = ffmpegdec->debug_mv = ffmpegdec->context->debug_mv =
g_value_get_boolean (value); g_value_get_boolean (value);
break; break;
default: default:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment