mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-30 19:18:31 +00:00
qtmux: autodetect out-of-order input timestamps and determine DTS accordingly
Favour using input buffer timestamps for DTS, but fallback to using buffer duration (accumulation) if input ts detected out-of-order. Fixes #624212.
This commit is contained in:
parent
9e79307431
commit
365b419216
1 changed files with 56 additions and 12 deletions
|
@ -1545,6 +1545,14 @@ ftyp_error:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check whether @a differs from @b by order of @magn */
|
||||||
|
static gboolean inline
|
||||||
|
gst_qtmux_check_difference (GstQTMux * qtmux, GstClockTime a,
|
||||||
|
GstClockTime b, GstClockTime magn)
|
||||||
|
{
|
||||||
|
return ((a - b >= (magn >> 1)) || (b - a >= (magn >> 1)));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we push the buffer and update the tables in the track atoms
|
* Here we push the buffer and update the tables in the track atoms
|
||||||
*/
|
*/
|
||||||
|
@ -1585,14 +1593,42 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
|
||||||
} else
|
} else
|
||||||
gst_buffer_ref (last_buf);
|
gst_buffer_ref (last_buf);
|
||||||
|
|
||||||
/* fall back to duration if:
|
/* nasty heuristic mess to guestimate dealing with DTS/PTS,
|
||||||
* - last bufer
|
* while also trying to stay close to input ts to preserve sync, so:
|
||||||
* - the buffers are out of order,
|
* - prefer using input ts where possible
|
||||||
* - lack of valid time forces fall back */
|
* - if those detected out-of-order (*), and input duration available,
|
||||||
if (buf == NULL ||
|
* mark as out-of-order and fallback to duration
|
||||||
!GST_BUFFER_TIMESTAMP_IS_VALID (last_buf) ||
|
* - if in out-of-order, need to preserve sync between streams, and adding
|
||||||
!GST_BUFFER_TIMESTAMP_IS_VALID (buf) ||
|
* durations might drift, so try to resync when we expect
|
||||||
GST_BUFFER_TIMESTAMP (buf) < GST_BUFFER_TIMESTAMP (last_buf)) {
|
* input ts == (sum of durations), which is at some keyframe input frame.
|
||||||
|
*
|
||||||
|
* (*) if input ts out-of-order, or if ts differs from (sum of durations)
|
||||||
|
* by an (approx) order-of-duration magnitude
|
||||||
|
*/
|
||||||
|
if (G_LIKELY (buf) && !pad->is_out_of_order) {
|
||||||
|
if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (last_buf) &&
|
||||||
|
GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
|
||||||
|
if ((GST_BUFFER_TIMESTAMP (buf) < GST_BUFFER_TIMESTAMP (last_buf)) ||
|
||||||
|
(!GST_CLOCK_TIME_IS_VALID (pad->first_ts) &&
|
||||||
|
GST_BUFFER_DURATION_IS_VALID (last_buf) &&
|
||||||
|
gst_qtmux_check_difference (qtmux,
|
||||||
|
GST_BUFFER_TIMESTAMP (last_buf) +
|
||||||
|
GST_BUFFER_DURATION (last_buf), GST_BUFFER_TIMESTAMP (buf),
|
||||||
|
GST_BUFFER_DURATION (last_buf)))) {
|
||||||
|
GST_DEBUG_OBJECT (qtmux, "detected out-of-order input");
|
||||||
|
pad->is_out_of_order = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* this is pretty bad */
|
||||||
|
GST_WARNING_OBJECT (qtmux, "missing input timestamp");
|
||||||
|
/* fall back to durations */
|
||||||
|
pad->is_out_of_order = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fall back to duration if last buffer or
|
||||||
|
* out-of-order (determined previously), otherwise use input ts */
|
||||||
|
if (buf == NULL || pad->is_out_of_order) {
|
||||||
if (!GST_BUFFER_DURATION_IS_VALID (last_buf)) {
|
if (!GST_BUFFER_DURATION_IS_VALID (last_buf)) {
|
||||||
/* be forgiving for some possibly last upstream flushed buffer */
|
/* be forgiving for some possibly last upstream flushed buffer */
|
||||||
if (buf)
|
if (buf)
|
||||||
|
@ -1602,6 +1638,18 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
|
||||||
duration = 0;
|
duration = 0;
|
||||||
} else {
|
} else {
|
||||||
duration = GST_BUFFER_DURATION (last_buf);
|
duration = GST_BUFFER_DURATION (last_buf);
|
||||||
|
/* avoid drift in sum timestamps,
|
||||||
|
* so use input timestamp for suitable keyframe */
|
||||||
|
if (buf && !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) &&
|
||||||
|
GST_BUFFER_TIMESTAMP (buf) >= pad->last_dts &&
|
||||||
|
!gst_qtmux_check_difference (qtmux, pad->last_dts + duration,
|
||||||
|
GST_BUFFER_TIMESTAMP (buf), duration)) {
|
||||||
|
GST_DEBUG_OBJECT (qtmux, "resyncing out-of-order input to ts; "
|
||||||
|
"replacing %" GST_TIME_FORMAT " by %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (pad->last_dts + duration),
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||||
|
duration = GST_BUFFER_TIMESTAMP (buf) - pad->last_dts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
duration = GST_BUFFER_TIMESTAMP (buf) - GST_BUFFER_TIMESTAMP (last_buf);
|
duration = GST_BUFFER_TIMESTAMP (buf) - GST_BUFFER_TIMESTAMP (last_buf);
|
||||||
|
@ -2317,7 +2365,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
|
||||||
}
|
}
|
||||||
} else if (strcmp (mimetype, "video/x-h264") == 0) {
|
} else if (strcmp (mimetype, "video/x-h264") == 0) {
|
||||||
entry.fourcc = FOURCC_avc1;
|
entry.fourcc = FOURCC_avc1;
|
||||||
qtpad->is_out_of_order = TRUE;
|
|
||||||
if (qtpad->avg_bitrate == 0) {
|
if (qtpad->avg_bitrate == 0) {
|
||||||
gint avg_bitrate = 0;
|
gint avg_bitrate = 0;
|
||||||
gst_structure_get_int (structure, "bitrate", &avg_bitrate);
|
gst_structure_get_int (structure, "bitrate", &avg_bitrate);
|
||||||
|
@ -2342,7 +2389,6 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
|
||||||
entry.fourcc = FOURCC_SVQ3;
|
entry.fourcc = FOURCC_SVQ3;
|
||||||
entry.version = 3;
|
entry.version = 3;
|
||||||
entry.depth = 32;
|
entry.depth = 32;
|
||||||
qtpad->is_out_of_order = TRUE;
|
|
||||||
|
|
||||||
seqh_value = gst_structure_get_value (structure, "seqh");
|
seqh_value = gst_structure_get_value (structure, "seqh");
|
||||||
if (seqh_value) {
|
if (seqh_value) {
|
||||||
|
@ -2441,14 +2487,12 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
|
||||||
|
|
||||||
gst_structure_get_fourcc (structure, "format", &fourcc);
|
gst_structure_get_fourcc (structure, "format", &fourcc);
|
||||||
entry.fourcc = fourcc;
|
entry.fourcc = fourcc;
|
||||||
qtpad->is_out_of_order = TRUE;
|
|
||||||
qtpad->have_dts = TRUE;
|
qtpad->have_dts = TRUE;
|
||||||
} else if (strcmp (mimetype, "video/x-mp4-part") == 0) {
|
} else if (strcmp (mimetype, "video/x-mp4-part") == 0) {
|
||||||
guint32 fourcc;
|
guint32 fourcc;
|
||||||
|
|
||||||
gst_structure_get_fourcc (structure, "format", &fourcc);
|
gst_structure_get_fourcc (structure, "format", &fourcc);
|
||||||
entry.fourcc = fourcc;
|
entry.fourcc = fourcc;
|
||||||
qtpad->is_out_of_order = TRUE;
|
|
||||||
qtpad->have_dts = TRUE;
|
qtpad->have_dts = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue