summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
authorEdward Hervey <edward@centricular.com>2021-07-15 10:16:34 +0200
committerEdward Hervey <bilboed@bilboed.com>2021-07-21 14:33:19 +0000
commit3303e0ebd26232f5fc44fb4709369ac97aac787d (patch)
tree131ca22cbb236566f38ac2b0f376cccf01a51044 /gst
parent8817b08d5e36b4f2a4c12eaf74db0f6d6725a81b (diff)
downloadgstreamer-plugins-bad-3303e0ebd26232f5fc44fb4709369ac97aac787d.tar.gz
mxfdemux: Refactor pull seek
In order to figure out the exact start position (backed by a keyframe) accross all tracks, we first figure out the backing keyframe position, and *then* seek to that position. Avoids ending up in situations where we would properly seek to the backing keyframe on video ... but not on the audio streams (they would have been set to the original non-keyframe position). Fixes key-unit seeking. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2371>
Diffstat (limited to 'gst')
-rw-r--r--gst/mxf/mxfdemux.c221
1 files changed, 198 insertions, 23 deletions
diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c
index d40ff4c3c..52bbb23fc 100644
--- a/gst/mxf/mxfdemux.c
+++ b/gst/mxf/mxfdemux.c
@@ -4165,6 +4165,126 @@ gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
return ret;
}
+/* Given a stream time for an output pad, figure out:
+ * * The Essence track for that stream time
+ * * The position on that track
+ */
+static gboolean
+gst_mxf_demux_pad_to_track_and_position (GstMXFDemux * demux,
+ GstMXFDemuxPad * pad, GstClockTime streamtime,
+ GstMXFDemuxEssenceTrack ** etrack, gint64 * position)
+{
+ gint64 material_position;
+ guint64 sum = 0;
+ guint i;
+ MXFMetadataSourceClip *clip = NULL;
+ gchar str[96];
+
+ /* Convert to material position */
+ material_position =
+ gst_util_uint64_scale (streamtime, pad->material_track->edit_rate.n,
+ pad->material_track->edit_rate.d * GST_SECOND);
+
+ GST_DEBUG_OBJECT (pad,
+ "streamtime %" GST_TIME_FORMAT " position %" G_GINT64_FORMAT,
+ GST_TIME_ARGS (streamtime), material_position);
+
+
+ /* Find sequence component covering that position */
+ for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
+ i++) {
+ clip =
+ MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
+ structural_components[i]);
+ GST_LOG_OBJECT (pad,
+ "clip %d start_position:%" G_GINT64_FORMAT " duration %"
+ G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
+ clip->parent.duration);
+ if (clip->parent.duration <= 0)
+ break;
+ if ((sum + clip->parent.duration) > material_position)
+ break;
+ sum += clip->parent.duration;
+ }
+
+ if (i == pad->material_track->parent.sequence->n_structural_components) {
+ GST_WARNING_OBJECT (pad, "Requested position beyond the last clip");
+ /* Outside of current components. Setting to the end of the last clip */
+ material_position = sum;
+ sum -= clip->parent.duration;
+ }
+
+ GST_DEBUG_OBJECT (pad, "Looking for essence track for track_id:%d umid:%s",
+ clip->source_track_id, mxf_umid_to_string (&clip->source_package_id,
+ str));
+
+ /* Get the corresponding essence track for the given source package and stream id */
+ for (i = 0; i < demux->essence_tracks->len; i++) {
+ GstMXFDemuxEssenceTrack *track =
+ &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
+ GST_LOG_OBJECT (pad,
+ "Looking at essence track body_sid:%d index_sid:%d",
+ track->body_sid, track->index_sid);
+ if (clip->source_track_id == 0 || (track->track_id == clip->source_track_id
+ && mxf_umid_is_equal (&clip->source_package_id,
+ &track->source_package_uid))) {
+ GST_DEBUG_OBJECT (pad,
+ "Found matching essence track body_sid:%d index_sid:%d",
+ track->body_sid, track->index_sid);
+ *etrack = track;
+ *position = material_position - sum;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Given a track+position for a given pad, figure out the resulting stream time */
+static gboolean
+gst_mxf_demux_pad_get_stream_time (GstMXFDemux * demux,
+ GstMXFDemuxPad * pad, GstMXFDemuxEssenceTrack * etrack,
+ gint64 position, GstClockTime * stream_time)
+{
+ guint i;
+ guint64 sum = 0;
+ MXFMetadataSourceClip *clip = NULL;
+
+ /* Find the component for that */
+ /* Find sequence component covering that position */
+ for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
+ i++) {
+ clip =
+ MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
+ structural_components[i]);
+ GST_LOG_OBJECT (pad,
+ "clip %d start_position:%" G_GINT64_FORMAT " duration %"
+ G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
+ clip->parent.duration);
+ if (etrack->track_id == clip->source_track_id
+ && mxf_umid_is_equal (&clip->source_package_id,
+ &etrack->source_package_uid)) {
+ /* This is the clip */
+ break;
+ }
+ /* Fetch in the next one */
+ sum += clip->parent.duration;
+ }
+
+ /* Theoretically impossible */
+ if (i == pad->material_track->parent.sequence->n_structural_components) {
+ /* Outside of current components ?? */
+ return FALSE;
+ }
+
+ *stream_time =
+ gst_util_uint64_scale (position + sum,
+ pad->material_track->edit_rate.d * GST_SECOND,
+ pad->material_track->edit_rate.n);
+
+ return TRUE;
+}
+
static void
gst_mxf_demux_pad_set_position (GstMXFDemux * demux, GstMXFDemuxPad * p,
GstClockTime start)
@@ -4565,6 +4685,8 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
return TRUE;
}
+ GST_DEBUG_OBJECT (demux, "Seek %" GST_PTR_FORMAT, event);
+
if (format != GST_FORMAT_TIME)
goto wrong_format;
@@ -4574,8 +4696,6 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
- keyunit_ts = start;
-
if (!demux->index_table_segments_collected) {
collect_index_table_segments (demux);
demux->index_table_segments_collected = TRUE;
@@ -4617,12 +4737,11 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
gst_segment_do_seek (&seeksegment, rate, format, flags,
start_type, start, stop_type, stop, &update);
- GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
- &seeksegment);
+ GST_DEBUG_OBJECT (demux,
+ "segment initially configured to %" GST_SEGMENT_FORMAT, &seeksegment);
+ /* Initialize and reset ourselves if needed */
if (flush || seeksegment.position != demux->segment.position) {
- guint64 new_offset = -1;
-
if (!demux->metadata_resolved || demux->update_metadata) {
if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
@@ -4630,19 +4749,70 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
}
}
+ }
+
+ keyunit_ts = seeksegment.position;
+
+ /* Do a first round without changing positions. This is needed to figure out
+ * the supporting keyframe position (if any) */
+ for (i = 0; i < demux->src->len; i++) {
+ GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
+ GstMXFDemuxEssenceTrack *etrack;
+ gint64 track_pos, seeked_pos;
+
+ /* Get track and track position for requested time, handles out of bound internally */
+ if (!gst_mxf_demux_pad_to_track_and_position (demux, p,
+ seeksegment.position, &etrack, &track_pos))
+ goto invalid_position;
+
+ GST_LOG_OBJECT (p,
+ "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT,
+ etrack->track_id, etrack->body_sid, etrack->index_sid, track_pos);
+
+ /* Find supporting keyframe entry */
+ seeked_pos = track_pos;
+ if (gst_mxf_demux_find_essence_element (demux, etrack, &seeked_pos,
+ TRUE) == -1) {
+ /* Couldn't find entry, ignore */
+ break;
+ }
+
+ GST_LOG_OBJECT (p,
+ "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT
+ " entry position %" G_GINT64_FORMAT, etrack->track_id, etrack->body_sid,
+ etrack->index_sid, track_pos, seeked_pos);
+
+ if (seeked_pos != track_pos) {
+ GstClockTime stream_time;
+ if (!gst_mxf_demux_pad_get_stream_time (demux, p, etrack, seeked_pos,
+ &stream_time))
+ goto invalid_position;
+ GST_LOG_OBJECT (p, "Need to seek to stream time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (stream_time));
+ keyunit_ts = MIN (seeksegment.position, stream_time);
+ }
+ }
+
+ if (keyframe && keyunit_ts != seeksegment.position) {
+ GST_INFO_OBJECT (demux, "key unit seek, adjusting segment start to "
+ "%" GST_TIME_FORMAT, GST_TIME_ARGS (keyunit_ts));
+ gst_segment_do_seek (&seeksegment, rate, format, flags,
+ start_type, keyunit_ts, stop_type, stop, &update);
+ }
+
+ /* Finally set the position to the calculated position */
+ if (flush || keyunit_ts != demux->segment.position) {
+ guint64 new_offset = -1;
+
/* Do the actual seeking */
for (i = 0; i < demux->src->len; i++) {
- MXFMetadataTrackType track_type = MXF_METADATA_TRACK_UNKNOWN;
GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
gint64 position;
guint64 off;
- if (p->material_track != NULL)
- track_type = p->material_track->parent.type;
-
/* Reset EOS flag on all pads */
p->eos = FALSE;
- gst_mxf_demux_pad_set_position (demux, p, start);
+ gst_mxf_demux_pad_set_position (demux, p, seeksegment.position);
/* we always want to send data starting with a key unit */
position = p->current_essence_track_position;
@@ -4671,11 +4841,6 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
p->current_essence_track->source_track->edit_rate.n);
}
p->current_essence_track_position = position;
-
- /* FIXME: what about DV + MPEG-TS container essence tracks? */
- if (track_type == MXF_METADATA_TRACK_PICTURE_ESSENCE) {
- keyunit_ts = MIN (p->position, keyunit_ts);
- }
}
p->discont = TRUE;
}
@@ -4710,13 +4875,6 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
gst_event_set_seqnum (demux->close_seg_event, demux->seqnum);
}
- if (keyframe && keyunit_ts != start) {
- GST_INFO_OBJECT (demux, "key unit seek, adjusting segment start to "
- "%" GST_TIME_FORMAT, GST_TIME_ARGS (keyunit_ts));
- gst_segment_do_seek (&seeksegment, rate, format, flags,
- start_type, keyunit_ts, stop_type, stop, &update);
- }
-
/* Ok seek succeeded, take the newly configured segment */
memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
@@ -4770,6 +4928,23 @@ unresolved_metadata:
GST_WARNING_OBJECT (demux, "metadata can't be resolved");
return FALSE;
}
+
+invalid_position:
+ {
+ if (flush) {
+ GstEvent *e;
+
+ /* Stop flushing, the sinks are at time 0 now */
+ e = gst_event_new_flush_stop (TRUE);
+ gst_event_set_seqnum (e, seqnum);
+ gst_mxf_demux_push_src_event (demux, e);
+ }
+ gst_pad_start_task (demux->sinkpad,
+ (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
+ GST_PAD_STREAM_UNLOCK (demux->sinkpad);
+ GST_WARNING_OBJECT (demux, "Requested seek position is not valid");
+ return FALSE;
+ }
}
static gboolean