mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
gst/matroska/matroska-mux.*: Keep track of first and last timestamps for each incoming stream, so we can calculate th...
Original commit message from CVS: Based on patch by: Wouter Cloetens <wouter at mind be> * gst/matroska/matroska-mux.c: (gst_matroska_mux_video_pad_setcaps), (gst_matroska_mux_request_new_pad), (gst_matroska_mux_release_pad), (gst_matroska_mux_finish), (gst_matroska_mux_collected): * gst/matroska/matroska-mux.h: Keep track of first and last timestamps for each incoming stream, so we can calculate the total duration for live sources and other input where we can't query the duration from the start or where there's no constant framerate from which we can deduce the duration; also use calculated/observed duration if it is bigger than the previously queried duration. Furthermore, use gst_pad_query_peer_duration() and take into account that it may return TRUE but still a duration of CLOCK_TIME_NONE, which easily screws up comparisons when using unsigned integers. Fixes #504081.
This commit is contained in:
parent
b76819bbd2
commit
0a3ae38bf0
3 changed files with 66 additions and 16 deletions
18
ChangeLog
18
ChangeLog
|
@ -1,3 +1,21 @@
|
||||||
|
2008-01-08 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
|
Based on patch by: Wouter Cloetens <wouter at mind be>
|
||||||
|
|
||||||
|
* gst/matroska/matroska-mux.c: (gst_matroska_mux_video_pad_setcaps),
|
||||||
|
(gst_matroska_mux_request_new_pad), (gst_matroska_mux_release_pad),
|
||||||
|
(gst_matroska_mux_finish), (gst_matroska_mux_collected):
|
||||||
|
* gst/matroska/matroska-mux.h:
|
||||||
|
Keep track of first and last timestamps for each incoming stream,
|
||||||
|
so we can calculate the total duration for live sources and other
|
||||||
|
input where we can't query the duration from the start or where
|
||||||
|
there's no constant framerate from which we can deduce the
|
||||||
|
duration; also use calculated/observed duration if it is bigger
|
||||||
|
than the previously queried duration. Furthermore, use
|
||||||
|
gst_pad_query_peer_duration() and take into account that it may
|
||||||
|
return TRUE but still a duration of CLOCK_TIME_NONE, which easily
|
||||||
|
screws up comparisons when using unsigned integers. Fixes #504081.
|
||||||
|
|
||||||
2008-01-08 Sebastian Dröge <slomo@circular-chaos.org>
|
2008-01-08 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
* configure.ac:
|
* configure.ac:
|
||||||
|
|
|
@ -513,10 +513,10 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
GstMatroskaTrackVideoContext *videocontext;
|
GstMatroskaTrackVideoContext *videocontext;
|
||||||
GstMatroskaMux *mux;
|
GstMatroskaMux *mux;
|
||||||
GstMatroskaPad *collect_pad;
|
GstMatroskaPad *collect_pad;
|
||||||
|
GstStructure *structure;
|
||||||
const gchar *mimetype;
|
const gchar *mimetype;
|
||||||
gint width, height, pixel_width, pixel_height;
|
gint width, height, pixel_width, pixel_height;
|
||||||
const GValue *framerate;
|
gint fps_d, fps_n;
|
||||||
GstStructure *structure;
|
|
||||||
|
|
||||||
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
|
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
@ -541,16 +541,16 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
/* get general properties */
|
/* get general properties */
|
||||||
gst_structure_get_int (structure, "width", &width);
|
gst_structure_get_int (structure, "width", &width);
|
||||||
gst_structure_get_int (structure, "height", &height);
|
gst_structure_get_int (structure, "height", &height);
|
||||||
framerate = gst_structure_get_value (structure, "framerate");
|
|
||||||
if (framerate == NULL || !GST_VALUE_HOLDS_FRACTION (framerate))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
videocontext->pixel_width = width;
|
videocontext->pixel_width = width;
|
||||||
videocontext->pixel_height = height;
|
videocontext->pixel_height = height;
|
||||||
context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
|
if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
|
||||||
gst_value_get_fraction_denominator (framerate),
|
context->default_duration =
|
||||||
gst_value_get_fraction_numerator (framerate));
|
gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
|
||||||
|
GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (context->default_duration));
|
||||||
|
} else {
|
||||||
|
context->default_duration = 0;
|
||||||
|
}
|
||||||
if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
|
if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
|
||||||
&pixel_width, &pixel_height)) {
|
&pixel_width, &pixel_height)) {
|
||||||
if (pixel_width > pixel_height) {
|
if (pixel_width > pixel_height) {
|
||||||
|
@ -1136,6 +1136,8 @@ gst_matroska_mux_request_new_pad (GstElement * element,
|
||||||
context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
|
context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
|
||||||
collect_pad->track = context;
|
collect_pad->track = context;
|
||||||
collect_pad->buffer = NULL;
|
collect_pad->buffer = NULL;
|
||||||
|
collect_pad->start_ts = GST_CLOCK_TIME_NONE;
|
||||||
|
collect_pad->end_ts = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
/* FIXME: hacked way to override/extend the event function of
|
/* FIXME: hacked way to override/extend the event function of
|
||||||
* GstCollectPads; because it sets its own event function giving the
|
* GstCollectPads; because it sets its own event function giving the
|
||||||
|
@ -1176,6 +1178,13 @@ gst_matroska_mux_release_pad (GstElement * element, GstPad * pad)
|
||||||
GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
|
GstMatroskaPad *collect_pad = (GstMatroskaPad *) cdata;
|
||||||
|
|
||||||
if (cdata->pad == pad) {
|
if (cdata->pad == pad) {
|
||||||
|
GstClockTime min_dur; /* observed minimum duration */
|
||||||
|
|
||||||
|
/* no need to check if start_ts and end_ts are set, in the worst case
|
||||||
|
* they're both -1 and we'll end up with a duration of 0 again */
|
||||||
|
min_dur = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
|
||||||
|
if (collect_pad->duration < min_dur)
|
||||||
|
collect_pad->duration = min_dur;
|
||||||
if (collect_pad->duration > mux->duration)
|
if (collect_pad->duration > mux->duration)
|
||||||
mux->duration = collect_pad->duration;
|
mux->duration = collect_pad->duration;
|
||||||
gst_matroska_pad_free (collect_pad);
|
gst_matroska_pad_free (collect_pad);
|
||||||
|
@ -1351,23 +1360,22 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
|
||||||
collected = g_slist_next (collected)) {
|
collected = g_slist_next (collected)) {
|
||||||
GstMatroskaPad *collect_pad;
|
GstMatroskaPad *collect_pad;
|
||||||
GstFormat format = GST_FORMAT_TIME;
|
GstFormat format = GST_FORMAT_TIME;
|
||||||
GstPad *thepad, *peerpad;
|
GstPad *thepad;
|
||||||
gint64 trackduration;
|
gint64 trackduration;
|
||||||
|
|
||||||
collect_pad = (GstMatroskaPad *) collected->data;
|
collect_pad = (GstMatroskaPad *) collected->data;
|
||||||
thepad = collect_pad->collect.pad;
|
thepad = collect_pad->collect.pad;
|
||||||
|
|
||||||
/* Query the total length of the track. */
|
/* Query the total length of the track. */
|
||||||
peerpad = gst_pad_get_peer (thepad);
|
GST_DEBUG_OBJECT (thepad, "querying peer duration");
|
||||||
GST_DEBUG_OBJECT (thepad, "querying duration");
|
if (gst_pad_query_peer_duration (thepad, &format, &trackduration)) {
|
||||||
if (gst_pad_query_duration (peerpad, &format, &trackduration)) {
|
|
||||||
GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (thepad, "duration: %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (trackduration));
|
GST_TIME_ARGS (trackduration));
|
||||||
if ((gdouble) trackduration > duration) {
|
if (trackduration != GST_CLOCK_TIME_NONE &&
|
||||||
|
(gdouble) trackduration > duration) {
|
||||||
duration = (gdouble) trackduration;
|
duration = (gdouble) trackduration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gst_object_unref (peerpad);
|
|
||||||
}
|
}
|
||||||
gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
|
gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
|
||||||
duration / gst_guint64_to_gdouble (mux->time_scale));
|
duration / gst_guint64_to_gdouble (mux->time_scale));
|
||||||
|
@ -1600,13 +1608,23 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
for (collected = mux->collect->data; collected;
|
for (collected = mux->collect->data; collected;
|
||||||
collected = g_slist_next (collected)) {
|
collected = g_slist_next (collected)) {
|
||||||
GstMatroskaPad *collect_pad;
|
GstMatroskaPad *collect_pad;
|
||||||
|
GstClockTime min_duration; /* observed minimum duration */
|
||||||
|
|
||||||
collect_pad = (GstMatroskaPad *) collected->data;
|
collect_pad = (GstMatroskaPad *) collected->data;
|
||||||
|
|
||||||
|
/* no need to check if start_ts and end_ts are set, in the worst case
|
||||||
|
* they're both -1 and we'll end up with a duration of 0 again */
|
||||||
|
min_duration = GST_CLOCK_DIFF (collect_pad->start_ts, collect_pad->end_ts);
|
||||||
|
if (collect_pad->duration < min_duration)
|
||||||
|
collect_pad->duration = min_duration;
|
||||||
|
GST_DEBUG_OBJECT (collect_pad, "final track duration: %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (collect_pad->duration));
|
||||||
if (collect_pad->duration > duration)
|
if (collect_pad->duration > duration)
|
||||||
duration = collect_pad->duration;
|
duration = collect_pad->duration;
|
||||||
}
|
}
|
||||||
if (duration != 0) {
|
if (duration != 0) {
|
||||||
|
GST_DEBUG_OBJECT (mux, "final total duration: %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (duration));
|
||||||
pos = mux->ebml_write->pos;
|
pos = mux->ebml_write->pos;
|
||||||
gst_ebml_write_seek (ebml, mux->duration_pos);
|
gst_ebml_write_seek (ebml, mux->duration_pos);
|
||||||
gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
|
gst_ebml_write_float (ebml, GST_MATROSKA_ID_DURATION,
|
||||||
|
@ -1920,6 +1938,18 @@ gst_matroska_mux_collected (GstCollectPads * pads, gpointer user_data)
|
||||||
}
|
}
|
||||||
GST_DEBUG_OBJECT (best->collect.pad, "best pad");
|
GST_DEBUG_OBJECT (best->collect.pad, "best pad");
|
||||||
|
|
||||||
|
/* make note of first and last encountered timestamps, so we can calculate
|
||||||
|
* the actual duration later when we send an updated header on eos */
|
||||||
|
best->end_ts = GST_BUFFER_TIMESTAMP (best->buffer);
|
||||||
|
if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
|
||||||
|
best->end_ts += GST_BUFFER_DURATION (best->buffer);
|
||||||
|
else if (best->track->default_duration)
|
||||||
|
best->end_ts += best->track->default_duration;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE)) {
|
||||||
|
best->start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/* write one buffer */
|
/* write one buffer */
|
||||||
ret = gst_matroska_mux_write_data (mux, best);
|
ret = gst_matroska_mux_write_data (mux, best);
|
||||||
} while (ret == GST_FLOW_OK && !popped);
|
} while (ret == GST_FLOW_OK && !popped);
|
||||||
|
|
|
@ -76,6 +76,8 @@ typedef struct
|
||||||
GstBuffer *buffer; /* the queued buffer for this pad */
|
GstBuffer *buffer; /* the queued buffer for this pad */
|
||||||
|
|
||||||
guint64 duration;
|
guint64 duration;
|
||||||
|
GstClockTime start_ts;
|
||||||
|
GstClockTime end_ts; /* last timestamp + (if available) duration */
|
||||||
}
|
}
|
||||||
GstMatroskaPad;
|
GstMatroskaPad;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue