mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
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.
This commit is contained in:
parent
bebde6f878
commit
62bc3b929b
3 changed files with 71 additions and 10 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
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>
|
||||
|
||||
Patch by: Damien Lespiau <damien dot lespiau at gmail dot com>
|
||||
|
|
2
common
2
common
|
@ -1 +1 @@
|
|||
Subproject commit 05a617c9043ddb78f8578195b18c166d7e1d4c2e
|
||||
Subproject commit e02bd43fe6b9e45536eccbf5b7a5f9eae62030fd
|
|
@ -73,6 +73,9 @@ struct _GstFFMpegDec
|
|||
gboolean discont;
|
||||
guint64 next_ts;
|
||||
guint64 in_ts;
|
||||
GstClockTime last_out;
|
||||
gboolean ts_is_dts;
|
||||
gboolean has_b_frames;
|
||||
|
||||
/* parsing */
|
||||
AVCodecParserContext *pctx;
|
||||
|
@ -301,7 +304,7 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass * klass)
|
|||
g_object_class_install_property (gobject_class, PROP_DEBUG_MV,
|
||||
g_param_spec_boolean ("debug-mv", "Debug motion vectors",
|
||||
"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;
|
||||
|
@ -619,6 +622,11 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
|
|||
ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;
|
||||
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 */
|
||||
gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
|
||||
oclass->in_plugin->type, caps, ffmpegdec->context);
|
||||
|
@ -704,6 +712,11 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
|
|||
gst_structure_get_int (structure, "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:
|
||||
GST_OBJECT_UNLOCK (ffmpegdec);
|
||||
|
||||
|
@ -1260,6 +1273,13 @@ check_keyframe (GstFFMpegDec * ffmpegdec)
|
|||
/* figure out if we are dealing with a keyframe */
|
||||
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_reference = (ffmpegdec->picture->reference == 1);
|
||||
|
||||
|
@ -1387,7 +1407,7 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
|
|||
gboolean mode_switch;
|
||||
gboolean decode;
|
||||
gint hurry_up = 0;
|
||||
GstClockTime out_timestamp, out_duration;
|
||||
GstClockTime out_timestamp, out_duration, out_pts;
|
||||
|
||||
*ret = GST_FLOW_OK;
|
||||
*outbuf = NULL;
|
||||
|
@ -1434,7 +1454,6 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
|
|||
if (!decode)
|
||||
ffmpegdec->context->hurry_up = hurry_up;
|
||||
|
||||
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "after decode: len %d, have_data %d",
|
||||
len, have_data);
|
||||
|
||||
|
@ -1447,18 +1466,49 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
|
|||
if (len < 0 || have_data <= 0)
|
||||
goto beach;
|
||||
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "picture: pts %" G_GUINT64_FORMAT,
|
||||
ffmpegdec->picture->pts);
|
||||
/* get pts */
|
||||
out_pts = ffmpegdec->picture->pts;
|
||||
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "picture: pts %" G_GUINT64_FORMAT, out_pts);
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "picture: num %d",
|
||||
ffmpegdec->picture->coded_picture_number);
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "picture: ref %d",
|
||||
ffmpegdec->picture->reference);
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "picture: display %d",
|
||||
ffmpegdec->picture->display_picture_number);
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "picture: opaque %p",
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* non-keyframe */
|
||||
if (G_UNLIKELY (ffmpegdec->waiting_for_key)) {
|
||||
|
@ -1482,9 +1532,9 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
|
|||
* 3) else copy input timestamp
|
||||
*/
|
||||
out_timestamp = -1;
|
||||
if (ffmpegdec->picture->pts != -1) {
|
||||
if (out_pts != -1) {
|
||||
/* 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
|
||||
" returned by ffmpeg", GST_TIME_ARGS (out_timestamp));
|
||||
}
|
||||
|
@ -1923,6 +1973,7 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
|
|||
if (ffmpegdec->opened) {
|
||||
avcodec_flush_buffers (ffmpegdec->context);
|
||||
}
|
||||
ffmpegdec->last_out = GST_CLOCK_TIME_NONE;
|
||||
ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
|
||||
gst_ffmpegdec_reset_qos (ffmpegdec);
|
||||
gst_ffmpegdec_flush_pcache (ffmpegdec);
|
||||
|
@ -2298,7 +2349,7 @@ gst_ffmpegdec_set_property (GObject * object,
|
|||
ffmpegdec->do_padding = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_DEBUG_MV:
|
||||
ffmpegdec->debug_mv = ffmpegdec->context->debug_mv =
|
||||
ffmpegdec->debug_mv = ffmpegdec->context->debug_mv =
|
||||
g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue