mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
qtdemux: make seeking in push mode work
Move sample position checks into qtdemux_parse_samples where we can protect it with a lock. Refactor and make an qtdemux_ensure_index function. Rename qtdemux_do_push_seek to qtdemux_seek_offset in order to avoid confusion with gst_qtdemux_do_push_seek.
This commit is contained in:
parent
3b643817be
commit
86021857c5
1 changed files with 50 additions and 19 deletions
|
@ -776,8 +776,7 @@ gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
|
||||||
|
|
||||||
result++;
|
result++;
|
||||||
while (index < str->n_samples - 1) {
|
while (index < str->n_samples - 1) {
|
||||||
if (index + 1 > str->stbl_index
|
if (!qtdemux_parse_samples (qtdemux, str, index + 1))
|
||||||
&& !qtdemux_parse_samples (qtdemux, str, index + 1))
|
|
||||||
goto parse_failed;
|
goto parse_failed;
|
||||||
|
|
||||||
if (media_time < result->timestamp)
|
if (media_time < result->timestamp)
|
||||||
|
@ -1026,6 +1025,7 @@ gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
|
||||||
gst_event_parse_seek (event, &rate, &format, &flags,
|
gst_event_parse_seek (event, &rate, &format, &flags,
|
||||||
&cur_type, &cur, &stop_type, &stop);
|
&cur_type, &cur, &stop_type, &stop);
|
||||||
|
|
||||||
|
/* FIXME, always play to the end */
|
||||||
stop = -1;
|
stop = -1;
|
||||||
|
|
||||||
/* only forward streaming and seeking is possible */
|
/* only forward streaming and seeking is possible */
|
||||||
|
@ -1048,6 +1048,7 @@ gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
|
||||||
GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
|
GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
|
||||||
"start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
|
"start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
|
||||||
stop);
|
stop);
|
||||||
|
|
||||||
/* BYTE seek event */
|
/* BYTE seek event */
|
||||||
event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
|
event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
|
||||||
stop_type, stop);
|
stop_type, stop);
|
||||||
|
@ -1252,26 +1253,40 @@ no_format:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
qtdemux_ensure_index (GstQTDemux * qtdemux)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
/* Build complete index */
|
||||||
|
for (i = 0; i < qtdemux->n_streams; i++) {
|
||||||
|
if (!qtdemux_parse_samples (qtdemux, qtdemux->streams[i],
|
||||||
|
qtdemux->streams[i]->n_samples - 1))
|
||||||
|
goto parse_error;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
parse_error:
|
||||||
|
{
|
||||||
|
GST_LOG_OBJECT (qtdemux,
|
||||||
|
"Building complete index of stream %u for seeking failed!", i);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
|
gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
gboolean res = TRUE;
|
gboolean res = TRUE;
|
||||||
GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
|
GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
|
||||||
guint i;
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
/* Build complete index for seeking */
|
/* Build complete index for seeking */
|
||||||
for (i = 0; i < qtdemux->n_streams; i++) {
|
if (!qtdemux_ensure_index (qtdemux))
|
||||||
if (!qtdemux_parse_samples (qtdemux, qtdemux->streams[i],
|
goto index_failed;
|
||||||
qtdemux->streams[i]->n_samples - 1)) {
|
|
||||||
GST_LOG_OBJECT (qtdemux,
|
|
||||||
"Building complete index of stream %u for seeking failed!", i);
|
|
||||||
res = FALSE;
|
|
||||||
gst_event_unref (event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
} else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) {
|
||||||
|
@ -1296,6 +1311,14 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
|
||||||
gst_object_unref (qtdemux);
|
gst_object_unref (qtdemux);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
index_failed:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (qtdemux, "Index failed");
|
||||||
|
gst_event_unref (event);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stream/index return sample that is min/max w.r.t. byte position,
|
/* stream/index return sample that is min/max w.r.t. byte position,
|
||||||
|
@ -2820,8 +2843,7 @@ next_entry_size (GstQTDemux * demux)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((stream->sample_index > stream->stbl_index)
|
if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
|
||||||
&& !qtdemux_parse_samples (demux, stream, stream->sample_index)) {
|
|
||||||
GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
|
GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
|
||||||
stream->sample_index);
|
stream->sample_index);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2872,7 +2894,7 @@ gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
qtdemux_do_push_seek (GstQTDemux * demux, guint64 offset)
|
qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
|
||||||
{
|
{
|
||||||
GstEvent *event;
|
GstEvent *event;
|
||||||
gboolean res = 0;
|
gboolean res = 0;
|
||||||
|
@ -2957,7 +2979,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
|
||||||
target = old + size;
|
target = old + size;
|
||||||
|
|
||||||
/* try to jump over the atom with a seek */
|
/* try to jump over the atom with a seek */
|
||||||
res = qtdemux_do_push_seek (demux, target);
|
res = qtdemux_seek_offset (demux, target);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
GST_DEBUG_OBJECT (demux, "seek success");
|
GST_DEBUG_OBJECT (demux, "seek success");
|
||||||
|
@ -3063,7 +3085,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
|
||||||
gboolean res;
|
gboolean res;
|
||||||
|
|
||||||
/* we need to seek back */
|
/* we need to seek back */
|
||||||
res = qtdemux_do_push_seek (demux, demux->first_mdat);
|
res = qtdemux_seek_offset (demux, demux->first_mdat);
|
||||||
if (res) {
|
if (res) {
|
||||||
demux->offset = demux->first_mdat;
|
demux->offset = demux->first_mdat;
|
||||||
} else {
|
} else {
|
||||||
|
@ -4117,6 +4139,9 @@ corrupt_file:
|
||||||
|
|
||||||
/* collect samples from the next sample to be parsed up to sample @n for @stream
|
/* collect samples from the next sample to be parsed up to sample @n for @stream
|
||||||
* by reading the info from @stbl
|
* by reading the info from @stbl
|
||||||
|
*
|
||||||
|
* This code can be executed from both the streaming thread and the seeking
|
||||||
|
* thread so it takes the object lock to protect itself
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
||||||
|
@ -4127,6 +4152,7 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
|
||||||
if (n >= stream->n_samples)
|
if (n >= stream->n_samples)
|
||||||
goto out_of_samples;
|
goto out_of_samples;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (qtdemux);
|
||||||
if (n <= stream->stbl_index)
|
if (n <= stream->stbl_index)
|
||||||
goto already_parsed;
|
goto already_parsed;
|
||||||
|
|
||||||
|
@ -4390,6 +4416,7 @@ ctts:
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
stream->stbl_index = n;
|
stream->stbl_index = n;
|
||||||
|
GST_OBJECT_UNLOCK (qtdemux);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -4399,6 +4426,7 @@ already_parsed:
|
||||||
GST_LOG_OBJECT (qtdemux,
|
GST_LOG_OBJECT (qtdemux,
|
||||||
"Tried to parse up to sample %u but this sample has already been parsed",
|
"Tried to parse up to sample %u but this sample has already been parsed",
|
||||||
n);
|
n);
|
||||||
|
GST_OBJECT_UNLOCK (qtdemux);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -4407,12 +4435,15 @@ out_of_samples:
|
||||||
GST_LOG_OBJECT (qtdemux,
|
GST_LOG_OBJECT (qtdemux,
|
||||||
"Tried to parse up to sample %u but there are only %u samples", n + 1,
|
"Tried to parse up to sample %u but there are only %u samples", n + 1,
|
||||||
stream->n_samples);
|
stream->n_samples);
|
||||||
goto corrupt_file;
|
GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
|
||||||
|
(_("This file is corrupt and cannot be played.")), (NULL));
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
corrupt_file:
|
corrupt_file:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
|
GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
|
||||||
(_("This file is corrupt and cannot be played.")), (NULL));
|
(_("This file is corrupt and cannot be played.")), (NULL));
|
||||||
|
GST_OBJECT_UNLOCK (qtdemux);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue