mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-08 21:28:45 +00:00
qtdemux: improve edts segment handling after seeks in push mode
Properly handle edts segments for push-based operation seeking. We only support edts that a single segment that has media at the end, being preceeded by any number of gap segments. This also allows the qt segment rate to be respected after seeks https://bugzilla.gnome.org/show_bug.cgi?id=765669
This commit is contained in:
parent
6604614dc5
commit
00f23053b1
1 changed files with 72 additions and 16 deletions
|
@ -530,6 +530,8 @@ static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
|
||||||
static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
|
static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
|
||||||
QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
|
QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
|
||||||
GstClockTime * _start, GstClockTime * _stop);
|
GstClockTime * _start, GstClockTime * _stop);
|
||||||
|
static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
|
||||||
|
QtDemuxStream * stream, gint segment_index, GstClockTime pos);
|
||||||
|
|
||||||
static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
|
static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
|
||||||
static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
|
static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
|
||||||
|
@ -2021,6 +2023,44 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Maps the @segment to the qt edts internal segments and pushes
|
||||||
|
* the correspnding segment event.
|
||||||
|
*
|
||||||
|
* If it ends up being at a empty segment, a gap will be pushed and the next
|
||||||
|
* edts segment will be activated in sequence.
|
||||||
|
*
|
||||||
|
* To be used in push-mode only */
|
||||||
|
static void
|
||||||
|
gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
|
||||||
|
{
|
||||||
|
gint n, i;
|
||||||
|
|
||||||
|
for (n = 0; n < qtdemux->n_streams; n++) {
|
||||||
|
QtDemuxStream *stream = qtdemux->streams[n];
|
||||||
|
|
||||||
|
stream->time_position = segment->start;
|
||||||
|
|
||||||
|
/* in push mode we should be guaranteed that we will have empty segments
|
||||||
|
* at the beginning and then one segment after, other scenarios are not
|
||||||
|
* supported and are discarded when parsing the edts */
|
||||||
|
for (i = 0; i < stream->n_segments; i++) {
|
||||||
|
if (stream->segments[i].stop_time > segment->start) {
|
||||||
|
gst_qtdemux_activate_segment (qtdemux, stream, i,
|
||||||
|
stream->time_position);
|
||||||
|
if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
|
||||||
|
/* push the empty segment and move to the next one */
|
||||||
|
gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
|
||||||
|
stream->time_position);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (i == stream->n_segments - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
|
gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
|
||||||
GstEvent * event)
|
GstEvent * event)
|
||||||
|
@ -2116,11 +2156,19 @@ gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
|
||||||
|
|
||||||
gst_segment_copy_into (&segment, &demux->segment);
|
gst_segment_copy_into (&segment, &demux->segment);
|
||||||
GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
|
GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
|
||||||
segment_event = gst_event_new_segment (&segment);
|
|
||||||
gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
|
|
||||||
/* erase any previously set segment */
|
/* erase any previously set segment */
|
||||||
gst_event_replace (&demux->pending_newsegment, NULL);
|
gst_event_replace (&demux->pending_newsegment, NULL);
|
||||||
gst_qtdemux_push_event (demux, segment_event);
|
|
||||||
|
/* For pull mode, segment activation will be handled in the looping task
|
||||||
|
* For push mode, need to do it here */
|
||||||
|
if (demux->pullbased) {
|
||||||
|
segment_event = gst_event_new_segment (&segment);
|
||||||
|
gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
|
||||||
|
gst_qtdemux_push_event (demux, segment_event);
|
||||||
|
} else {
|
||||||
|
/* map segment to internal qt segments and push on each stream */
|
||||||
|
gst_qtdemux_map_and_push_segments (demux, &segment);
|
||||||
|
}
|
||||||
|
|
||||||
/* clear leftover in current segment, if any */
|
/* clear leftover in current segment, if any */
|
||||||
gst_adapter_clear (demux->adapter);
|
gst_adapter_clear (demux->adapter);
|
||||||
|
@ -5920,6 +5968,25 @@ gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
|
||||||
|
QtDemuxStream * stream, gint segment_index, GstClockTime pos)
|
||||||
|
{
|
||||||
|
GstClockTime ts, dur;
|
||||||
|
GstEvent *gap;
|
||||||
|
|
||||||
|
ts = pos;
|
||||||
|
dur =
|
||||||
|
stream->segments[segment_index].duration - (pos -
|
||||||
|
stream->segments[segment_index].time);
|
||||||
|
gap = gst_event_new_gap (ts, dur);
|
||||||
|
stream->time_position += dur;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
|
||||||
|
"segment: %" GST_PTR_FORMAT, gap);
|
||||||
|
gst_pad_push_event (stream->pad, gap);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
|
gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
|
||||||
QtDemuxStream * stream)
|
QtDemuxStream * stream)
|
||||||
|
@ -5932,19 +5999,8 @@ gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
|
||||||
gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
|
gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
|
||||||
|
|
||||||
if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
|
if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
|
||||||
GstClockTime ts, dur;
|
gst_qtdemux_send_gap_for_segment (demux, stream, i,
|
||||||
GstEvent *gap;
|
stream->time_position);
|
||||||
|
|
||||||
ts = stream->time_position;
|
|
||||||
dur =
|
|
||||||
stream->segments[i].duration - (stream->time_position -
|
|
||||||
stream->segments[i].time);
|
|
||||||
gap = gst_event_new_gap (ts, dur);
|
|
||||||
stream->time_position += dur;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
|
|
||||||
"segment: %" GST_PTR_FORMAT, gap);
|
|
||||||
gst_pad_push_event (stream->pad, gap);
|
|
||||||
} else {
|
} else {
|
||||||
/* Only support empty segment at the beginning followed by
|
/* Only support empty segment at the beginning followed by
|
||||||
* one non-empty segment, this was checked when parsing the
|
* one non-empty segment, this was checked when parsing the
|
||||||
|
|
Loading…
Reference in a new issue