mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-20 09:23:46 +00:00
qtdemux: support seeking in push based mode
This commit is contained in:
parent
d5120cda4b
commit
cc1a869a2c
1 changed files with 334 additions and 82 deletions
|
@ -484,6 +484,8 @@ gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
|
GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
|
||||||
|
|
||||||
switch (GST_QUERY_TYPE (query)) {
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
case GST_QUERY_POSITION:
|
case GST_QUERY_POSITION:
|
||||||
if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
|
if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
|
||||||
|
@ -509,14 +511,27 @@ gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
|
||||||
}
|
}
|
||||||
case GST_QUERY_SEEKING:{
|
case GST_QUERY_SEEKING:{
|
||||||
GstFormat fmt;
|
GstFormat fmt;
|
||||||
|
gboolean seekable;
|
||||||
|
|
||||||
gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
|
gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
|
||||||
if (fmt == GST_FORMAT_TIME) {
|
if (fmt == GST_FORMAT_TIME) {
|
||||||
gint64 duration = -1;
|
gint64 duration = -1;
|
||||||
|
|
||||||
gst_qtdemux_get_duration (qtdemux, &duration);
|
gst_qtdemux_get_duration (qtdemux, &duration);
|
||||||
gst_query_set_seeking (query, GST_FORMAT_TIME, qtdemux->pullbased,
|
seekable = TRUE;
|
||||||
0, duration);
|
if (!qtdemux->pullbased) {
|
||||||
|
GstQuery *q;
|
||||||
|
|
||||||
|
/* we might be able with help from upstream */
|
||||||
|
seekable = FALSE;
|
||||||
|
q = gst_query_new_seeking (GST_FORMAT_BYTES);
|
||||||
|
if ((res = gst_pad_peer_query (qtdemux->sinkpad, q))) {
|
||||||
|
gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
|
||||||
|
GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
|
||||||
|
}
|
||||||
|
gst_query_unref (q);
|
||||||
|
}
|
||||||
|
gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -688,6 +703,177 @@ gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
|
||||||
str->discont = TRUE;
|
str->discont = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
|
||||||
|
gint64 * key_time, gint64 * key_offset)
|
||||||
|
{
|
||||||
|
guint64 min_offset;
|
||||||
|
gint64 min_byte_offset = -1;
|
||||||
|
gint n;
|
||||||
|
|
||||||
|
min_offset = desired_time;
|
||||||
|
|
||||||
|
/* for each stream, find the index of the sample in the segment
|
||||||
|
* and move back to the previous keyframe. */
|
||||||
|
for (n = 0; n < qtdemux->n_streams; n++) {
|
||||||
|
QtDemuxStream *str;
|
||||||
|
guint32 index, kindex;
|
||||||
|
guint32 seg_idx;
|
||||||
|
guint64 media_start;
|
||||||
|
guint64 media_time;
|
||||||
|
guint64 seg_time;
|
||||||
|
QtDemuxSegment *seg;
|
||||||
|
|
||||||
|
str = qtdemux->streams[n];
|
||||||
|
|
||||||
|
seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
|
||||||
|
|
||||||
|
/* segment not found, continue with normal flow */
|
||||||
|
if (seg_idx == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* get segment and time in the segment */
|
||||||
|
seg = &str->segments[seg_idx];
|
||||||
|
seg_time = desired_time - seg->time;
|
||||||
|
|
||||||
|
/* get the media time in the segment */
|
||||||
|
media_start = seg->media_start + seg_time;
|
||||||
|
|
||||||
|
/* get the index of the sample with media time */
|
||||||
|
index = gst_qtdemux_find_index (qtdemux, str, media_start);
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
|
||||||
|
GST_TIME_ARGS (media_start), index);
|
||||||
|
|
||||||
|
/* find previous keyframe */
|
||||||
|
kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
|
||||||
|
|
||||||
|
/* if the keyframe is at a different position, we need to update the
|
||||||
|
* requested seek time */
|
||||||
|
if (index != kindex) {
|
||||||
|
index = kindex;
|
||||||
|
|
||||||
|
/* get timestamp of keyframe */
|
||||||
|
media_time = str->samples[kindex].timestamp;
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
|
||||||
|
kindex, GST_TIME_ARGS (media_time));
|
||||||
|
|
||||||
|
/* keyframes in the segment get a chance to change the
|
||||||
|
* desired_offset. keyframes out of the segment are
|
||||||
|
* ignored. */
|
||||||
|
if (media_time >= seg->media_start) {
|
||||||
|
guint64 seg_time;
|
||||||
|
|
||||||
|
/* this keyframe is inside the segment, convert back to
|
||||||
|
* segment time */
|
||||||
|
seg_time = (media_time - seg->media_start) + seg->time;
|
||||||
|
if (seg_time < min_offset)
|
||||||
|
min_offset = seg_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
|
||||||
|
min_byte_offset = str->samples[index].offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_time)
|
||||||
|
*key_time = min_offset;
|
||||||
|
if (key_offset)
|
||||||
|
*key_offset = min_byte_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
|
||||||
|
GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
|
||||||
|
{
|
||||||
|
gboolean res;
|
||||||
|
GstFormat fmt;
|
||||||
|
|
||||||
|
g_return_val_if_fail (format != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (cur != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (stop != NULL, FALSE);
|
||||||
|
|
||||||
|
if (*format == GST_FORMAT_TIME)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
fmt = GST_FORMAT_TIME;
|
||||||
|
res = TRUE;
|
||||||
|
if (cur_type != GST_SEEK_TYPE_NONE)
|
||||||
|
res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur);
|
||||||
|
if (res && stop_type != GST_SEEK_TYPE_NONE)
|
||||||
|
res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
*format = GST_FORMAT_TIME;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform seek in push based mode:
|
||||||
|
find BYTE position to move to based on time and delegate to upstream
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
|
||||||
|
{
|
||||||
|
gdouble rate;
|
||||||
|
GstFormat format;
|
||||||
|
GstSeekFlags flags;
|
||||||
|
GstSeekType cur_type, stop_type;
|
||||||
|
gint64 cur, stop;
|
||||||
|
gboolean res;
|
||||||
|
gint64 byte_cur;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
|
||||||
|
|
||||||
|
gst_event_parse_seek (event, &rate, &format, &flags,
|
||||||
|
&cur_type, &cur, &stop_type, &stop);
|
||||||
|
|
||||||
|
if (stop_type != GST_SEEK_TYPE_NONE)
|
||||||
|
goto unsupported_seek;
|
||||||
|
stop = -1;
|
||||||
|
|
||||||
|
/* convert to TIME if needed and possible */
|
||||||
|
if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
|
||||||
|
stop_type, &stop))
|
||||||
|
goto no_format;
|
||||||
|
|
||||||
|
/* find reasonable corresponding BYTE position,
|
||||||
|
* also try to mind about keyframes, since we can not go back a bit for them
|
||||||
|
* later on */
|
||||||
|
gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
|
||||||
|
|
||||||
|
if (byte_cur == -1)
|
||||||
|
goto abort_seek;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
|
||||||
|
"start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
|
||||||
|
stop);
|
||||||
|
/* BYTE seek event */
|
||||||
|
event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
|
||||||
|
stop_type, stop);
|
||||||
|
res = gst_pad_push_event (qtdemux->sinkpad, event);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
abort_seek:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
|
||||||
|
"seek aborted.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
unsupported_seek:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
no_format:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* perform the seek.
|
/* perform the seek.
|
||||||
*
|
*
|
||||||
* We set all segment_indexes in the streams to unknown and
|
* We set all segment_indexes in the streams to unknown and
|
||||||
|
@ -716,71 +902,11 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
|
||||||
GST_TIME_ARGS (desired_offset));
|
GST_TIME_ARGS (desired_offset));
|
||||||
|
|
||||||
if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
|
if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
|
||||||
guint64 min_offset;
|
gint64 min_offset;
|
||||||
|
|
||||||
min_offset = desired_offset;
|
gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
|
||||||
|
|
||||||
/* for each stream, find the index of the sample in the segment
|
|
||||||
* and move back to the previous keyframe. */
|
|
||||||
for (n = 0; n < qtdemux->n_streams; n++) {
|
|
||||||
QtDemuxStream *str;
|
|
||||||
guint32 index, kindex;
|
|
||||||
guint32 seg_idx;
|
|
||||||
guint64 media_start;
|
|
||||||
guint64 media_time;
|
|
||||||
guint64 seg_time;
|
|
||||||
QtDemuxSegment *seg;
|
|
||||||
|
|
||||||
str = qtdemux->streams[n];
|
|
||||||
|
|
||||||
seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_offset);
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
|
|
||||||
|
|
||||||
/* segment not found, continue with normal flow */
|
|
||||||
if (seg_idx == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* get segment and time in the segment */
|
|
||||||
seg = &str->segments[seg_idx];
|
|
||||||
seg_time = desired_offset - seg->time;
|
|
||||||
|
|
||||||
/* get the media time in the segment */
|
|
||||||
media_start = seg->media_start + seg_time;
|
|
||||||
|
|
||||||
/* get the index of the sample with media time */
|
|
||||||
index = gst_qtdemux_find_index (qtdemux, str, media_start);
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
|
|
||||||
GST_TIME_ARGS (media_start), index);
|
|
||||||
|
|
||||||
/* find previous keyframe */
|
|
||||||
kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
|
|
||||||
|
|
||||||
/* if the keyframe is at a different position, we need to update the
|
|
||||||
* requiested seek time */
|
|
||||||
if (index != kindex) {
|
|
||||||
index = kindex;
|
|
||||||
|
|
||||||
/* get timestamp of keyframe */
|
|
||||||
media_time = str->samples[kindex].timestamp;
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
|
|
||||||
kindex, GST_TIME_ARGS (media_time));
|
|
||||||
|
|
||||||
/* keyframes in the segment get a chance to change the
|
|
||||||
* desired_offset. keyframes out of the segment are
|
|
||||||
* ignored. */
|
|
||||||
if (media_time >= seg->media_start) {
|
|
||||||
guint64 seg_time;
|
|
||||||
|
|
||||||
/* this keyframe is inside the segment, convert back to
|
|
||||||
* segment time */
|
|
||||||
seg_time = (media_time - seg->media_start) + seg->time;
|
|
||||||
if (seg_time < min_offset)
|
|
||||||
min_offset = seg_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
|
GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (desired_offset));
|
GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
|
||||||
desired_offset = min_offset;
|
desired_offset = min_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,20 +952,9 @@ gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
|
||||||
|
|
||||||
/* we have to have a format as the segment format. Try to convert
|
/* we have to have a format as the segment format. Try to convert
|
||||||
* if not. */
|
* if not. */
|
||||||
if (format != GST_FORMAT_TIME) {
|
if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
|
||||||
GstFormat fmt;
|
stop_type, &stop))
|
||||||
|
|
||||||
fmt = GST_FORMAT_TIME;
|
|
||||||
res = TRUE;
|
|
||||||
if (cur_type != GST_SEEK_TYPE_NONE)
|
|
||||||
res = gst_pad_query_convert (pad, format, cur, &fmt, &cur);
|
|
||||||
if (res && stop_type != GST_SEEK_TYPE_NONE)
|
|
||||||
res = gst_pad_query_convert (pad, format, stop, &fmt, &stop);
|
|
||||||
if (!res)
|
|
||||||
goto no_format;
|
goto no_format;
|
||||||
|
|
||||||
format = fmt;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
|
GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
@ -947,8 +1062,11 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
if (qtdemux->pullbased) {
|
if (qtdemux->pullbased) {
|
||||||
res = gst_qtdemux_do_seek (qtdemux, pad, event);
|
res = gst_qtdemux_do_seek (qtdemux, pad, event);
|
||||||
|
} else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) {
|
||||||
|
res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (qtdemux, "cannot seek in streaming mode");
|
GST_DEBUG_OBJECT (qtdemux,
|
||||||
|
"ignoring seek in push mode in current state");
|
||||||
res = FALSE;
|
res = FALSE;
|
||||||
}
|
}
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
@ -968,18 +1086,151 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* stream/index return sample that is min/max w.r.t. byte position,
|
||||||
|
* time is min/max w.r.t. time of samples,
|
||||||
|
* the latter need not be time of the former sample */
|
||||||
|
static void
|
||||||
|
gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
|
||||||
|
gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
|
||||||
|
{
|
||||||
|
gint i, n, index;
|
||||||
|
gint64 time, min_time;
|
||||||
|
QtDemuxStream *stream;
|
||||||
|
|
||||||
|
min_time = -1;
|
||||||
|
stream = NULL;
|
||||||
|
index = -1;
|
||||||
|
|
||||||
|
for (n = 0; n < qtdemux->n_streams; ++n) {
|
||||||
|
QtDemuxStream *str;
|
||||||
|
gint inc;
|
||||||
|
|
||||||
|
str = qtdemux->streams[n];
|
||||||
|
|
||||||
|
if (fw) {
|
||||||
|
i = 0;
|
||||||
|
inc = 1;
|
||||||
|
} else {
|
||||||
|
i = str->n_samples - 1;
|
||||||
|
inc = -1;
|
||||||
|
}
|
||||||
|
for (; (i >= 0) && (i < str->n_samples); i += inc) {
|
||||||
|
if (str->samples[i].size &&
|
||||||
|
((fw && (str->samples[i].offset >= byte_pos)) ||
|
||||||
|
(!fw &&
|
||||||
|
(str->samples[i].offset + str->samples[i].size <=
|
||||||
|
byte_pos)))) {
|
||||||
|
/* move stream to first available sample */
|
||||||
|
if (set)
|
||||||
|
gst_qtdemux_move_stream (qtdemux, str, i);
|
||||||
|
/* determine min/max time */
|
||||||
|
time = str->samples[i].timestamp + str->samples[i].pts_offset;
|
||||||
|
if (min_time == -1 || (fw && min_time > time) ||
|
||||||
|
(!fw && min_time < time)) {
|
||||||
|
min_time = time;
|
||||||
|
}
|
||||||
|
/* determine stream with leading sample, to get its position */
|
||||||
|
/* only needed in fw case */
|
||||||
|
if (fw && (!stream ||
|
||||||
|
str->samples[i].offset < stream->samples[index].offset)) {
|
||||||
|
stream = str;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_time)
|
||||||
|
*_time = min_time;
|
||||||
|
if (_stream)
|
||||||
|
*_stream = stream;
|
||||||
|
if (_index)
|
||||||
|
*_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
|
gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
|
GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
|
||||||
gboolean res;
|
gboolean res;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_NEWSEGMENT:
|
case GST_EVENT_NEWSEGMENT:
|
||||||
/* We need to convert it to a GST_FORMAT_TIME new segment */
|
{
|
||||||
|
GstFormat format;
|
||||||
|
gdouble rate, arate;
|
||||||
|
gint64 start, stop, time, offset = 0;
|
||||||
|
QtDemuxStream *stream;
|
||||||
|
gint idx;
|
||||||
|
gboolean update;
|
||||||
|
GstSegment segment;
|
||||||
|
|
||||||
|
/* some debug output */
|
||||||
|
gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
|
||||||
|
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
|
||||||
|
&start, &stop, &time);
|
||||||
|
gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
|
||||||
|
start, stop, time);
|
||||||
|
GST_DEBUG_OBJECT (demux,
|
||||||
|
"received format %d newsegment %" GST_SEGMENT_FORMAT, format,
|
||||||
|
&segment);
|
||||||
|
|
||||||
|
/* chain will send initial newsegment after pads have been added */
|
||||||
|
if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
|
||||||
|
GST_DEBUG_OBJECT (demux, "still starting, eating event");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we only expect a BYTE segment, e.g. following a seek */
|
||||||
|
if (format == GST_FORMAT_BYTES) {
|
||||||
|
if (start > 0) {
|
||||||
|
offset = start;
|
||||||
|
gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
|
||||||
|
&start);
|
||||||
|
start = MAX (start, 0);
|
||||||
|
}
|
||||||
|
if (stop > 0) {
|
||||||
|
gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
|
||||||
|
&stop);
|
||||||
|
stop = MAX (stop, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* accept upstream's notion of segment and distribute along */
|
||||||
|
gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
|
||||||
|
GST_FORMAT_TIME, start, stop, start);
|
||||||
|
GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, "
|
||||||
|
"applied rate %g, format %d, start %" G_GINT64_FORMAT ", "
|
||||||
|
"stop %" G_GINT64_FORMAT, update, rate, arate, GST_FORMAT_TIME,
|
||||||
|
start, stop);
|
||||||
|
gst_qtdemux_push_event (demux,
|
||||||
|
gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
|
||||||
|
start, stop, start));
|
||||||
|
|
||||||
|
/* clear leftover in current segment, if any */
|
||||||
|
gst_adapter_clear (demux->adapter);
|
||||||
|
/* set up streaming thread */
|
||||||
|
gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
|
||||||
|
demux->offset = offset;
|
||||||
|
if (stream) {
|
||||||
|
demux->todrop = stream->samples[idx].offset - offset;
|
||||||
|
demux->neededbytes = demux->todrop + stream->samples[idx].size;
|
||||||
|
} else {
|
||||||
|
/* set up for EOS */
|
||||||
|
demux->neededbytes = -1;
|
||||||
|
demux->todrop = 0;
|
||||||
|
}
|
||||||
|
exit:
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
/* If we are in push mode, and get an EOS before we've seen any streams,
|
/* If we are in push mode, and get an EOS before we've seen any streams,
|
||||||
* then error out - we have nowhere to send the EOS */
|
* then error out - we have nowhere to send the EOS */
|
||||||
|
@ -2272,7 +2523,8 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
|
||||||
goto unknown_stream;
|
goto unknown_stream;
|
||||||
|
|
||||||
/* first buffer? */
|
/* first buffer? */
|
||||||
/* FIXME : this should be handled in sink_event */
|
/* initial newsegment sent here after having added pads,
|
||||||
|
* possible others in sink_event */
|
||||||
if (demux->last_ts == GST_CLOCK_TIME_NONE) {
|
if (demux->last_ts == GST_CLOCK_TIME_NONE) {
|
||||||
gst_qtdemux_push_event (demux,
|
gst_qtdemux_push_event (demux,
|
||||||
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
|
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
|
||||||
|
|
Loading…
Reference in a new issue