summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2009-02-01 16:59:25 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2009-02-01 17:00:33 +0100
commit0ac0645de6c9746db81b50cfe13622de0fee1631 (patch)
treecc01a8880507a2339af74dd6d8eec095ca7ee7a3
parent99298da3d50f5d0881008d3fa690df9ad708e467 (diff)
downloadgst-plugins-bad-0ac0645de6c9746db81b50cfe13622de0fee1631.tar.gz
gst-plugins-bad-0ac0645de6c9746db81b50cfe13622de0fee1631.tar.bz2
gst-plugins-bad-0ac0645de6c9746db81b50cfe13622de0fee1631.zip
Add initial support for seeking in push mode
-rw-r--r--gst/mxf/mxfdemux.c279
1 files changed, 216 insertions, 63 deletions
diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c
index 70b89135..8bf3d343 100644
--- a/gst/mxf/mxfdemux.c
+++ b/gst/mxf/mxfdemux.c
@@ -2243,86 +2243,113 @@ from_index:
}
GST_DEBUG_OBJECT (demux, "Not found in index");
- demux->offset = demux->run_in;
- if (etrack->offsets && etrack->offsets->len) {
- for (i = etrack->offsets->len - 1; i >= 0; i--) {
- GstMXFDemuxIndex *idx =
- &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
-
- if (idx->offset != 0 && i <= *position) {
- demux->offset = idx->offset + demux->run_in;
- break;
+ if (!demux->random_access) {
+ guint64 new_offset = -1;
+ gint64 new_position = -1;
+
+ if (etrack->offsets && etrack->offsets->len) {
+ for (i = etrack->offsets->len - 1; i >= 0; i--) {
+ GstMXFDemuxIndex *idx =
+ &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
+
+ if (idx->offset != 0 && i <= *position && (!keyframe || idx->keyframe)) {
+ new_offset = idx->offset;
+ new_position = i;
+ break;
+ }
}
}
- }
- gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
- for (i = 0; i < demux->essence_tracks->len; i++) {
- GstMXFDemuxEssenceTrack *t =
- &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
+ if (new_offset != -1) {
+ *position = new_position;
+ return new_offset;
+ }
+ } else if (demux->random_access) {
+ demux->offset = demux->run_in;
+ if (etrack->offsets && etrack->offsets->len) {
+ for (i = etrack->offsets->len - 1; i >= 0; i--) {
+ GstMXFDemuxIndex *idx =
+ &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
- t->position = (demux->offset == demux->run_in) ? 0 : -1;
- }
+ if (idx->offset != 0 && i <= *position) {
+ demux->offset = idx->offset + demux->run_in;
+ break;
+ }
+ }
+ }
+ gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
- /* Else peek at all essence elements and complete our
- * index until we find the requested element
- */
- while (ret == GST_FLOW_OK) {
- GstBuffer *buffer = NULL;
- MXFUL key;
- guint read = 0;
+ for (i = 0; i < demux->essence_tracks->len; i++) {
+ GstMXFDemuxEssenceTrack *t =
+ &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
- ret =
- gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
- &read);
+ t->position = (demux->offset == demux->run_in) ? 0 : -1;
+ }
- if (ret == GST_FLOW_UNEXPECTED) {
- for (i = 0; i < demux->essence_tracks->len; i++) {
- GstMXFDemuxEssenceTrack *t =
- &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
+ /* Else peek at all essence elements and complete our
+ * index until we find the requested element
+ */
+ while (ret == GST_FLOW_OK) {
+ GstBuffer *buffer = NULL;
+ MXFUL key;
+ guint read = 0;
- if (t->position > 0)
- t->duration = t->position;
- }
- /* For the searched track this is really our position */
- etrack->duration = etrack->position;
+ ret =
+ gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
+ &read);
- for (i = 0; i < demux->src->len; i++) {
- GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
+ if (ret == GST_FLOW_UNEXPECTED) {
+ for (i = 0; i < demux->essence_tracks->len; i++) {
+ GstMXFDemuxEssenceTrack *t =
+ &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
+ i);
- if (!p->eos
- && p->current_essence_track_position >=
- p->current_essence_track->duration) {
- p->eos = TRUE;
- gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
+ if (t->position > 0)
+ t->duration = t->position;
+ }
+ /* For the searched track this is really our position */
+ etrack->duration = etrack->position;
+
+ for (i = 0; i < demux->src->len; i++) {
+ GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
+
+ if (!p->eos
+ && p->current_essence_track_position >=
+ p->current_essence_track->duration) {
+ p->eos = TRUE;
+ gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
+ }
}
}
- }
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- break;
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ demux->offset = old_offset;
+ demux->current_partition = old_partition;
+ break;
+ }
- ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer, TRUE);
+ ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer, TRUE);
- gst_buffer_unref (buffer);
+ gst_buffer_unref (buffer);
- /* If we found the position read it from the index again */
- if (ret == GST_FLOW_OK && etrack->position == *position + 1 &&
- etrack->offsets && etrack->offsets->len > *position &&
- g_array_index (etrack->offsets, GstMXFDemuxIndex,
- *position).offset != 0) {
- GST_DEBUG_OBJECT (demux, "Found at offset %" G_GUINT64_FORMAT,
- demux->offset);
- demux->offset = old_offset;
- demux->current_partition = old_partition;
- goto from_index;
+ /* If we found the position read it from the index again */
+ if (ret == GST_FLOW_OK && etrack->position == *position + 1 &&
+ etrack->offsets && etrack->offsets->len > *position &&
+ g_array_index (etrack->offsets, GstMXFDemuxIndex,
+ *position).offset != 0) {
+ GST_DEBUG_OBJECT (demux, "Found at offset %" G_GUINT64_FORMAT,
+ demux->offset);
+ demux->offset = old_offset;
+ demux->current_partition = old_partition;
+ goto from_index;
+ }
+ demux->offset += read;
}
- demux->offset += read;
- }
+ demux->offset = old_offset;
+ demux->current_partition = old_partition;
- GST_DEBUG_OBJECT (demux, "Not found in this file");
- demux->offset = old_offset;
- demux->current_partition = old_partition;
+ GST_DEBUG_OBJECT (demux, "Not found in this file");
+ }
return -1;
}
@@ -2796,6 +2823,132 @@ gst_mxf_demux_pad_set_position (GstMXFDemux * demux, GstMXFDemuxPad * p,
}
static gboolean
+gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event)
+{
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType start_type, stop_type;
+ gint64 start, stop;
+ gdouble rate;
+ gboolean update, flush, keyframe;
+ GstSegment seeksegment;
+ guint i;
+
+ gst_event_parse_seek (event, &rate, &format, &flags,
+ &start_type, &start, &stop_type, &stop);
+
+ if (rate <= 0.0)
+ goto wrong_rate;
+
+ if (format != GST_FORMAT_TIME)
+ goto wrong_format;
+
+ flush = !!(flags & GST_SEEK_FLAG_FLUSH);
+ keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
+
+ /* Work on a copy until we are sure the seek succeeded. */
+ memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
+
+ GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
+ &demux->segment);
+
+ /* Apply the seek to our segment */
+ gst_segment_set_seek (&seeksegment, rate, format, flags,
+ start_type, start, stop_type, stop, &update);
+
+ GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
+ &seeksegment);
+
+ if (flush || seeksegment.last_stop != demux->segment.last_stop) {
+ gboolean ret;
+ guint64 new_offset = -1;
+
+ if (!demux->metadata_resolved) {
+ if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK)
+ goto unresolved_metadata;
+ }
+
+ /* Do the actual seeking */
+ for (i = 0; i < demux->src->len; i++) {
+ GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
+ gint64 position;
+ guint64 off;
+
+ /* Reset EOS flag on all pads */
+ p->eos = FALSE;
+ p->last_flow = GST_FLOW_OK;
+ gst_mxf_demux_pad_set_position (demux, p, start);
+
+ position = p->current_essence_track_position;
+ off = gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
+ &position, keyframe);
+ new_offset = MIN (off, new_offset);
+ p->discont = TRUE;
+ }
+
+ if (new_offset == -1)
+ goto no_new_offset;
+
+ new_offset += demux->run_in;
+
+ GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
+ G_GUINT64_FORMAT, new_offset);
+ ret = gst_pad_push_event (demux->sinkpad,
+ gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
+ seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
+ new_offset, GST_SEEK_TYPE_NONE, 0));
+
+ if (G_UNLIKELY (!ret)) {
+ goto seek_failed;
+ }
+ }
+
+ /* Tell all the stream a new segment is needed */
+ for (i = 0; i < demux->src->len; i++) {
+ GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
+ p->need_segment = TRUE;
+ }
+
+ for (i = 0; i < demux->essence_tracks->len; i++) {
+ GstMXFDemuxEssenceTrack *t =
+ &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
+ t->position = -1;
+ }
+
+ /* Ok seek succeeded, take the newly configured segment */
+ memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
+
+ return TRUE;
+
+/* ERRORS */
+wrong_format:
+ {
+ GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
+ return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
+ }
+wrong_rate:
+ {
+ GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
+ return FALSE;
+ }
+unresolved_metadata:
+ {
+ GST_WARNING_OBJECT (demux, "metadata can't be resolved");
+ return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
+ }
+seek_failed:
+ {
+ GST_WARNING_OBJECT (demux, "upstream seek failed");
+ return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
+ }
+no_new_offset:
+ {
+ GST_WARNING_OBJECT (demux, "can't find new offset");
+ return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
+ }
+}
+
+static gboolean
gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
{
GstFormat format;
@@ -2974,7 +3127,7 @@ gst_mxf_demux_src_event (GstPad * pad, GstEvent * event)
if (demux->random_access)
ret = gst_mxf_demux_seek_pull (demux, event);
else
- ret = FALSE;
+ ret = gst_mxf_demux_seek_push (demux, event);
gst_event_unref (event);
break;
default: