matroska: refactor code common to matroskademux and matroskaparse

Move the following function to matroska-read-common.[ch] from
matroska-demux.c and matroska-parse.c:
    - gst_matroska_{demux,parse}_peek_bytes

https://bugzilla.gnome.org/show_bug.cgi?id=650877
This commit is contained in:
Debarshi Ray 2011-05-23 18:06:44 +03:00 committed by Sebastian Dröge
parent f885e2721a
commit 72d969b360
6 changed files with 201 additions and 282 deletions

View file

@ -242,16 +242,17 @@ static void
gst_matroska_demux_init (GstMatroskaDemux * demux, gst_matroska_demux_init (GstMatroskaDemux * demux,
GstMatroskaDemuxClass * klass) GstMatroskaDemuxClass * klass)
{ {
demux->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink"); demux->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
gst_pad_set_activate_function (demux->sinkpad, "sink");
gst_pad_set_activate_function (demux->common.sinkpad,
GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate)); GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate));
gst_pad_set_activatepull_function (demux->sinkpad, gst_pad_set_activatepull_function (demux->common.sinkpad,
GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate_pull)); GST_DEBUG_FUNCPTR (gst_matroska_demux_sink_activate_pull));
gst_pad_set_chain_function (demux->sinkpad, gst_pad_set_chain_function (demux->common.sinkpad,
GST_DEBUG_FUNCPTR (gst_matroska_demux_chain)); GST_DEBUG_FUNCPTR (gst_matroska_demux_chain));
gst_pad_set_event_function (demux->sinkpad, gst_pad_set_event_function (demux->common.sinkpad,
GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_event)); GST_DEBUG_FUNCPTR (gst_matroska_demux_handle_sink_event));
gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); gst_element_add_pad (GST_ELEMENT (demux), demux->common.sinkpad);
/* initial stream no. */ /* initial stream no. */
demux->common.src = NULL; demux->common.src = NULL;
@ -417,7 +418,7 @@ gst_matroska_demux_reset (GstElement * element)
demux->last_stop_end = GST_CLOCK_TIME_NONE; demux->last_stop_end = GST_CLOCK_TIME_NONE;
demux->seek_block = 0; demux->seek_block = 0;
demux->offset = 0; demux->common.offset = 0;
demux->cluster_time = GST_CLOCK_TIME_NONE; demux->cluster_time = GST_CLOCK_TIME_NONE;
demux->cluster_offset = 0; demux->cluster_offset = 0;
demux->next_cluster_offset = 0; demux->next_cluster_offset = 0;
@ -454,103 +455,19 @@ gst_matroska_demux_reset (GstElement * element)
} }
demux->global_tags = gst_tag_list_new (); demux->global_tags = gst_tag_list_new ();
if (demux->cached_buffer) { if (demux->common.cached_buffer) {
gst_buffer_unref (demux->cached_buffer); gst_buffer_unref (demux->common.cached_buffer);
demux->cached_buffer = NULL; demux->common.cached_buffer = NULL;
} }
} }
/*
* Calls pull_range for (offset,size) without advancing our offset
*/
static GstFlowReturn
gst_matroska_demux_peek_bytes (GstMatroskaDemux * demux, guint64 offset,
guint size, GstBuffer ** p_buf, guint8 ** bytes)
{
GstFlowReturn ret;
/* Caching here actually makes much less difference than one would expect.
* We do it mainly to avoid pulling buffers of 1 byte all the time */
if (demux->cached_buffer) {
guint64 cache_offset = GST_BUFFER_OFFSET (demux->cached_buffer);
guint cache_size = GST_BUFFER_SIZE (demux->cached_buffer);
if (cache_offset <= demux->offset &&
(demux->offset + size) <= (cache_offset + cache_size)) {
if (p_buf)
*p_buf = gst_buffer_create_sub (demux->cached_buffer,
demux->offset - cache_offset, size);
if (bytes)
*bytes = GST_BUFFER_DATA (demux->cached_buffer) + demux->offset -
cache_offset;
return GST_FLOW_OK;
}
/* not enough data in the cache, free cache and get a new one */
gst_buffer_unref (demux->cached_buffer);
demux->cached_buffer = NULL;
}
/* refill the cache */
ret = gst_pad_pull_range (demux->sinkpad, demux->offset,
MAX (size, 64 * 1024), &demux->cached_buffer);
if (ret != GST_FLOW_OK) {
demux->cached_buffer = NULL;
return ret;
}
if (GST_BUFFER_SIZE (demux->cached_buffer) >= size) {
if (p_buf)
*p_buf = gst_buffer_create_sub (demux->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (demux->cached_buffer);
return GST_FLOW_OK;
}
/* Not possible to get enough data, try a last time with
* requesting exactly the size we need */
gst_buffer_unref (demux->cached_buffer);
demux->cached_buffer = NULL;
ret =
gst_pad_pull_range (demux->sinkpad, demux->offset, size,
&demux->cached_buffer);
if (ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (demux, "pull_range returned %d", ret);
if (p_buf)
*p_buf = NULL;
if (bytes)
*bytes = NULL;
return ret;
}
if (GST_BUFFER_SIZE (demux->cached_buffer) < size) {
GST_WARNING_OBJECT (demux, "Dropping short buffer at offset %"
G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", demux->offset,
size, GST_BUFFER_SIZE (demux->cached_buffer));
gst_buffer_unref (demux->cached_buffer);
demux->cached_buffer = NULL;
if (p_buf)
*p_buf = NULL;
if (bytes)
*bytes = NULL;
return GST_FLOW_UNEXPECTED;
}
if (p_buf)
*p_buf = gst_buffer_create_sub (demux->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (demux->cached_buffer);
return GST_FLOW_OK;
}
static const guint8 * static const guint8 *
gst_matroska_demux_peek_pull (GstMatroskaDemux * demux, guint peek) gst_matroska_demux_peek_pull (GstMatroskaDemux * demux, guint peek)
{ {
guint8 *data = NULL; guint8 *data = NULL;
gst_matroska_demux_peek_bytes (demux, demux->offset, peek, NULL, &data); gst_matroska_read_common_peek_bytes (&demux->common, demux->common.offset,
peek, NULL, &data);
return data; return data;
} }
@ -560,7 +477,7 @@ gst_matroska_demux_peek_id_length_pull (GstMatroskaDemux * demux, guint32 * _id,
{ {
return gst_ebml_peek_id_length (_id, _length, _needed, return gst_ebml_peek_id_length (_id, _length, _needed,
(GstPeekData) gst_matroska_demux_peek_pull, (gpointer) demux, (GstPeekData) gst_matroska_demux_peek_pull, (gpointer) demux,
GST_ELEMENT_CAST (demux), demux->offset); GST_ELEMENT_CAST (demux), demux->common.offset);
} }
static gint64 static gint64
@ -569,7 +486,7 @@ gst_matroska_demux_get_length (GstMatroskaDemux * demux)
GstFormat fmt = GST_FORMAT_BYTES; GstFormat fmt = GST_FORMAT_BYTES;
gint64 end = -1; gint64 end = -1;
if (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &end) || if (!gst_pad_query_peer_duration (demux->common.sinkpad, &fmt, &end) ||
fmt != GST_FORMAT_BYTES || end < 0) fmt != GST_FORMAT_BYTES || end < 0)
GST_DEBUG_OBJECT (demux, "no upstream length"); GST_DEBUG_OBJECT (demux, "no upstream length");
@ -1885,7 +1802,7 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
/* seek (relative to matroska segment) */ /* seek (relative to matroska segment) */
/* position might be invalid; will error when streaming resumes ... */ /* position might be invalid; will error when streaming resumes ... */
demux->offset = entry->pos + demux->common.ebml_segment_start; demux->common.offset = entry->pos + demux->common.ebml_segment_start;
GST_DEBUG_OBJECT (demux, "Seeked to offset %" G_GUINT64_FORMAT ", block %d, " GST_DEBUG_OBJECT (demux, "Seeked to offset %" G_GUINT64_FORMAT ", block %d, "
"time %" GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start, "time %" GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start,
@ -1940,7 +1857,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
guint32 id; guint32 id;
guint needed; guint needed;
orig_offset = demux->offset; orig_offset = demux->common.offset;
GST_LOG_OBJECT (demux, "searching cluster following offset %" G_GINT64_FORMAT, GST_LOG_OBJECT (demux, "searching cluster following offset %" G_GINT64_FORMAT,
*pos); *pos);
@ -1956,7 +1873,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
if (cpos) { if (cpos) {
GST_DEBUG_OBJECT (demux, GST_DEBUG_OBJECT (demux,
"cluster reported at offset %" G_GINT64_FORMAT, *cpos); "cluster reported at offset %" G_GINT64_FORMAT, *cpos);
demux->offset = *cpos; demux->common.offset = *cpos;
ret = ret =
gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed); gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed);
if (ret == GST_FLOW_OK && id == GST_MATROSKA_ID_CLUSTER) { if (ret == GST_FLOW_OK && id == GST_MATROSKA_ID_CLUSTER) {
@ -1971,7 +1888,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
GstByteReader reader; GstByteReader reader;
gint cluster_pos; gint cluster_pos;
ret = gst_pad_pull_range (demux->sinkpad, newpos, chunk, &buf); ret = gst_pad_pull_range (demux->common.sinkpad, newpos, chunk, &buf);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
break; break;
GST_DEBUG_OBJECT (demux, "read buffer size %d at offset %" G_GINT64_FORMAT, GST_DEBUG_OBJECT (demux, "read buffer size %d at offset %" G_GINT64_FORMAT,
@ -1996,7 +1913,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
GST_DEBUG_OBJECT (demux, "cluster is first cluster -> OK"); GST_DEBUG_OBJECT (demux, "cluster is first cluster -> OK");
break; break;
} }
demux->offset = newpos; demux->common.offset = newpos;
ret = ret =
gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed); gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
@ -2010,7 +1927,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
break; break;
} }
/* skip cluster */ /* skip cluster */
demux->offset += length + needed; demux->common.offset += length + needed;
ret = ret =
gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed); gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
@ -2035,7 +1952,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
} }
exit: exit:
demux->offset = orig_offset; demux->common.offset = orig_offset;
*pos = newpos; *pos = newpos;
return ret; return ret;
} }
@ -2069,13 +1986,13 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time)
current_cluster_offset = demux->cluster_offset; current_cluster_offset = demux->cluster_offset;
current_cluster_time = demux->cluster_time; current_cluster_time = demux->cluster_time;
current_offset = demux->offset; current_offset = demux->common.offset;
demux->common.state = GST_MATROSKA_READ_STATE_SCANNING; demux->common.state = GST_MATROSKA_READ_STATE_SCANNING;
/* estimate using start and current position */ /* estimate using start and current position */
GST_OBJECT_LOCK (demux); GST_OBJECT_LOCK (demux);
opos = demux->offset - demux->common.ebml_segment_start; opos = demux->common.offset - demux->common.ebml_segment_start;
otime = demux->segment.last_stop; otime = demux->segment.last_stop;
GST_OBJECT_UNLOCK (demux); GST_OBJECT_UNLOCK (demux);
@ -2121,7 +2038,7 @@ retry:
/* then start scanning and parsing for cluster time, /* then start scanning and parsing for cluster time,
* re-estimate if overshoot, otherwise next cluster and so on */ * re-estimate if overshoot, otherwise next cluster and so on */
demux->offset = newpos; demux->common.offset = newpos;
demux->cluster_time = cluster_time = GST_CLOCK_TIME_NONE; demux->cluster_time = cluster_time = GST_CLOCK_TIME_NONE;
while (1) { while (1) {
guint64 cluster_size = 0; guint64 cluster_size = 0;
@ -2131,7 +2048,7 @@ retry:
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
goto error; goto error;
GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, " GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
"size %" G_GUINT64_FORMAT ", needed %d", demux->offset, id, "size %" G_GUINT64_FORMAT ", needed %d", demux->common.offset, id,
length, needed); length, needed);
ret = gst_matroska_demux_parse_id (demux, id, length, needed); ret = gst_matroska_demux_parse_id (demux, id, length, needed);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
@ -2178,7 +2095,7 @@ retry:
* otherwise will be skippingly parsed into */ * otherwise will be skippingly parsed into */
if (cluster_size) { if (cluster_size) {
GST_DEBUG_OBJECT (demux, "skipping to next cluster"); GST_DEBUG_OBJECT (demux, "skipping to next cluster");
demux->offset = cluster_offset + cluster_size; demux->common.offset = cluster_offset + cluster_size;
demux->cluster_time = GST_CLOCK_TIME_NONE; demux->cluster_time = GST_CLOCK_TIME_NONE;
} else { } else {
GST_DEBUG_OBJECT (demux, "parsing/skipping cluster elements"); GST_DEBUG_OBJECT (demux, "parsing/skipping cluster elements");
@ -2208,7 +2125,7 @@ exit:
/* restore some state */ /* restore some state */
demux->cluster_offset = current_cluster_offset; demux->cluster_offset = current_cluster_offset;
demux->cluster_time = current_cluster_time; demux->cluster_time = current_cluster_time;
demux->offset = current_offset; demux->common.offset = current_offset;
demux->common.state = current_state; demux->common.state = current_state;
return entry; return entry;
@ -2283,24 +2200,24 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
if (flush) { if (flush) {
GST_DEBUG_OBJECT (demux, "Starting flush"); GST_DEBUG_OBJECT (demux, "Starting flush");
gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ()); gst_pad_push_event (demux->common.sinkpad, gst_event_new_flush_start ());
gst_matroska_demux_send_event (demux, gst_event_new_flush_start ()); gst_matroska_demux_send_event (demux, gst_event_new_flush_start ());
} else { } else {
GST_DEBUG_OBJECT (demux, "Non-flushing seek, pausing task"); GST_DEBUG_OBJECT (demux, "Non-flushing seek, pausing task");
gst_pad_pause_task (demux->sinkpad); gst_pad_pause_task (demux->common.sinkpad);
} }
/* now grab the stream lock so that streaming cannot continue, for /* now grab the stream lock so that streaming cannot continue, for
* non flushing seeks when the element is in PAUSED this could block * non flushing seeks when the element is in PAUSED this could block
* forever. */ * forever. */
GST_DEBUG_OBJECT (demux, "Waiting for streaming to stop"); GST_DEBUG_OBJECT (demux, "Waiting for streaming to stop");
GST_PAD_STREAM_LOCK (demux->sinkpad); GST_PAD_STREAM_LOCK (demux->common.sinkpad);
/* pull mode without index can do some scanning */ /* pull mode without index can do some scanning */
if (!demux->streaming && !demux->common.index) { if (!demux->streaming && !demux->common.index) {
/* need to stop flushing upstream as we need it next */ /* need to stop flushing upstream as we need it next */
if (flush) if (flush)
gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ()); gst_pad_push_event (demux->common.sinkpad, gst_event_new_flush_stop ());
entry = gst_matroska_demux_search_pos (demux, seeksegment.last_stop); entry = gst_matroska_demux_search_pos (demux, seeksegment.last_stop);
/* keep local copy */ /* keep local copy */
if (entry) { if (entry) {
@ -2325,7 +2242,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
if (flush) { if (flush) {
GST_DEBUG_OBJECT (demux, "Stopping flush"); GST_DEBUG_OBJECT (demux, "Stopping flush");
gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ()); gst_pad_push_event (demux->common.sinkpad, gst_event_new_flush_stop ());
gst_matroska_demux_send_event (demux, gst_event_new_flush_stop ()); gst_matroska_demux_send_event (demux, gst_event_new_flush_stop ());
} else if (demux->segment_running) { } else if (demux->segment_running) {
GST_DEBUG_OBJECT (demux, "Closing currently running segment"); GST_DEBUG_OBJECT (demux, "Closing currently running segment");
@ -2370,17 +2287,17 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
/* restart our task since it might have been stopped when we did the /* restart our task since it might have been stopped when we did the
* flush. */ * flush. */
demux->segment_running = TRUE; demux->segment_running = TRUE;
gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_matroska_demux_loop, gst_pad_start_task (demux->common.sinkpad,
demux->sinkpad); (GstTaskFunction) gst_matroska_demux_loop, demux->common.sinkpad);
/* streaming can continue now */ /* streaming can continue now */
GST_PAD_STREAM_UNLOCK (demux->sinkpad); GST_PAD_STREAM_UNLOCK (demux->common.sinkpad);
return TRUE; return TRUE;
seek_error: seek_error:
{ {
GST_PAD_STREAM_UNLOCK (demux->sinkpad); GST_PAD_STREAM_UNLOCK (demux->common.sinkpad);
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Got a seek error")); GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Got a seek error"));
return FALSE; return FALSE;
} }
@ -2519,7 +2436,7 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstEvent * event)
case GST_EVENT_LATENCY: case GST_EVENT_LATENCY:
default: default:
res = gst_pad_push_event (demux->sinkpad, event); res = gst_pad_push_event (demux->common.sinkpad, event);
break; break;
} }
@ -4673,7 +4590,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
/* remember */ /* remember */
length = gst_matroska_demux_get_length (demux); length = gst_matroska_demux_get_length (demux);
before_pos = demux->offset; before_pos = demux->common.offset;
if (length == (guint64) - 1) { if (length == (guint64) - 1) {
GST_DEBUG_OBJECT (demux, "no upstream length, skipping SeakHead entry"); GST_DEBUG_OBJECT (demux, "no upstream length, skipping SeakHead entry");
@ -4701,7 +4618,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
} }
/* seek */ /* seek */
demux->offset = seek_pos + demux->common.ebml_segment_start; demux->common.offset = seek_pos + demux->common.ebml_segment_start;
/* check ID */ /* check ID */
if ((ret = gst_matroska_demux_peek_id_length_pull (demux, &id, &length, if ((ret = gst_matroska_demux_peek_id_length_pull (demux, &id, &length,
@ -4719,7 +4636,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
finish: finish:
/* seek back */ /* seek back */
demux->offset = before_pos; demux->common.offset = before_pos;
break; break;
} }
@ -4823,7 +4740,7 @@ gst_matroska_demux_check_parse_error (GstMatroskaDemux * demux)
/* just repositioning to where next cluster should be and try from there */ /* just repositioning to where next cluster should be and try from there */
GST_WARNING_OBJECT (demux, "parse error, trying next cluster expected at %" GST_WARNING_OBJECT (demux, "parse error, trying next cluster expected at %"
G_GUINT64_FORMAT, demux->next_cluster_offset); G_GUINT64_FORMAT, demux->next_cluster_offset);
demux->offset = demux->next_cluster_offset; demux->common.offset = demux->next_cluster_offset;
demux->next_cluster_offset = 0; demux->next_cluster_offset = 0;
return FALSE; return FALSE;
} else { } else {
@ -4831,7 +4748,7 @@ gst_matroska_demux_check_parse_error (GstMatroskaDemux * demux)
/* sigh, one last attempt above and beyond call of duty ...; /* sigh, one last attempt above and beyond call of duty ...;
* search for cluster mark following current pos */ * search for cluster mark following current pos */
pos = demux->offset; pos = demux->common.offset;
GST_WARNING_OBJECT (demux, "parse error, looking for next cluster"); GST_WARNING_OBJECT (demux, "parse error, looking for next cluster");
if (gst_matroska_demux_search_cluster (demux, &pos) != GST_FLOW_OK) { if (gst_matroska_demux_search_cluster (demux, &pos) != GST_FLOW_OK) {
/* did not work, give up */ /* did not work, give up */
@ -4839,7 +4756,7 @@ gst_matroska_demux_check_parse_error (GstMatroskaDemux * demux)
} else { } else {
GST_DEBUG_OBJECT (demux, "... found at %" G_GUINT64_FORMAT, pos); GST_DEBUG_OBJECT (demux, "... found at %" G_GUINT64_FORMAT, pos);
/* try that position */ /* try that position */
demux->offset = pos; demux->common.offset = pos;
return FALSE; return FALSE;
} }
} }
@ -4849,7 +4766,7 @@ static inline GstFlowReturn
gst_matroska_demux_flush (GstMatroskaDemux * demux, guint flush) gst_matroska_demux_flush (GstMatroskaDemux * demux, guint flush)
{ {
GST_LOG_OBJECT (demux, "skipping %d bytes", flush); GST_LOG_OBJECT (demux, "skipping %d bytes", flush);
demux->offset += flush; demux->common.offset += flush;
if (demux->streaming) { if (demux->streaming) {
GstFlowReturn ret; GstFlowReturn ret;
@ -4895,11 +4812,12 @@ gst_matroska_demux_take (GstMatroskaDemux * demux, guint64 bytes,
else else
ret = GST_FLOW_UNEXPECTED; ret = GST_FLOW_UNEXPECTED;
} else } else
ret = gst_matroska_demux_peek_bytes (demux, demux->offset, bytes, &buffer, ret = gst_matroska_read_common_peek_bytes (&demux->common,
NULL); demux->common.offset, bytes, &buffer, NULL);
if (G_LIKELY (buffer)) { if (G_LIKELY (buffer)) {
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (demux), buffer, demux->offset); gst_ebml_read_init (ebml, GST_ELEMENT_CAST (demux), buffer,
demux->offset += bytes; demux->common.offset);
demux->common.offset += bytes;
} }
exit: exit:
return ret; return ret;
@ -4913,7 +4831,7 @@ gst_matroska_demux_check_seekability (GstMatroskaDemux * demux)
gint64 start = -1, stop = -1; gint64 start = -1, stop = -1;
query = gst_query_new_seeking (GST_FORMAT_BYTES); query = gst_query_new_seeking (GST_FORMAT_BYTES);
if (!gst_pad_peer_query (demux->sinkpad, query)) { if (!gst_pad_peer_query (demux->common.sinkpad, query)) {
GST_DEBUG_OBJECT (demux, "seeking query failed"); GST_DEBUG_OBJECT (demux, "seeking query failed");
goto done; goto done;
} }
@ -4925,7 +4843,7 @@ gst_matroska_demux_check_seekability (GstMatroskaDemux * demux)
GstFormat fmt = GST_FORMAT_BYTES; GstFormat fmt = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop"); GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop); gst_pad_query_peer_duration (demux->common.sinkpad, &fmt, &stop);
} }
/* if upstream doesn't know the size, it's likely that it's not seekable in /* if upstream doesn't know the size, it's likely that it's not seekable in
@ -4956,7 +4874,7 @@ gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
"Found Cluster element before Tracks, searching Tracks"); "Found Cluster element before Tracks, searching Tracks");
/* remember */ /* remember */
before_pos = demux->offset; before_pos = demux->common.offset;
/* Search Tracks element */ /* Search Tracks element */
while (TRUE) { while (TRUE) {
@ -4971,8 +4889,8 @@ gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
ret = gst_matroska_demux_check_read_size (demux, length); ret = gst_matroska_demux_check_read_size (demux, length);
break; break;
} else { } else {
demux->offset += needed; demux->common.offset += needed;
demux->offset += length; demux->common.offset += length;
} }
continue; continue;
} }
@ -4983,7 +4901,7 @@ gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
} }
/* seek back */ /* seek back */
demux->offset = before_pos; demux->common.offset = before_pos;
return ret; return ret;
} }
@ -5039,10 +4957,10 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
GST_READ_CHECK (gst_matroska_demux_flush (demux, needed)); GST_READ_CHECK (gst_matroska_demux_flush (demux, needed));
GST_DEBUG_OBJECT (demux, GST_DEBUG_OBJECT (demux,
"Found Segment start at offset %" G_GUINT64_FORMAT, "Found Segment start at offset %" G_GUINT64_FORMAT,
demux->offset); demux->common.offset);
/* seeks are from the beginning of the segment, /* seeks are from the beginning of the segment,
* after the segment ID/length */ * after the segment ID/length */
demux->common.ebml_segment_start = demux->offset; demux->common.ebml_segment_start = demux->common.offset;
demux->common.state = GST_MATROSKA_READ_STATE_HEADER; demux->common.state = GST_MATROSKA_READ_STATE_HEADER;
break; break;
default: default:
@ -5092,7 +5010,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
if (G_UNLIKELY (demux->common.state if (G_UNLIKELY (demux->common.state
== GST_MATROSKA_READ_STATE_HEADER)) { == GST_MATROSKA_READ_STATE_HEADER)) {
demux->common.state = GST_MATROSKA_READ_STATE_DATA; demux->common.state = GST_MATROSKA_READ_STATE_DATA;
demux->first_cluster_offset = demux->offset; demux->first_cluster_offset = demux->common.offset;
GST_DEBUG_OBJECT (demux, "signaling no more pads"); GST_DEBUG_OBJECT (demux, "signaling no more pads");
gst_element_no_more_pads (GST_ELEMENT (demux)); gst_element_no_more_pads (GST_ELEMENT (demux));
/* send initial newsegment */ /* send initial newsegment */
@ -5103,7 +5021,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
0) ? demux->segment.duration : -1, 0)); 0) ? demux->segment.duration : -1, 0));
} }
demux->cluster_time = GST_CLOCK_TIME_NONE; demux->cluster_time = GST_CLOCK_TIME_NONE;
demux->cluster_offset = demux->offset; demux->cluster_offset = demux->common.offset;
if (G_UNLIKELY (!demux->seek_first && demux->seek_block)) { if (G_UNLIKELY (!demux->seek_first && demux->seek_block)) {
GST_DEBUG_OBJECT (demux, "seek target block %" G_GUINT64_FORMAT GST_DEBUG_OBJECT (demux, "seek target block %" G_GUINT64_FORMAT
" not found in Cluster, trying next Cluster's first block instead", " not found in Cluster, trying next Cluster's first block instead",
@ -5306,7 +5224,7 @@ gst_matroska_demux_loop (GstPad * pad)
} }
GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, " GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
"size %" G_GUINT64_FORMAT ", needed %d", demux->offset, id, "size %" G_GUINT64_FORMAT ", needed %d", demux->common.offset, id,
length, needed); length, needed);
ret = gst_matroska_demux_parse_id (demux, id, length, needed); ret = gst_matroska_demux_parse_id (demux, id, length, needed);
@ -5335,7 +5253,8 @@ gst_matroska_demux_loop (GstPad * pad)
} }
next: next:
if (G_UNLIKELY (demux->offset == gst_matroska_demux_get_length (demux))) { if (G_UNLIKELY (demux->common.offset ==
gst_matroska_demux_get_length (demux))) {
GST_LOG_OBJECT (demux, "Reached end of stream"); GST_LOG_OBJECT (demux, "Reached end of stream");
ret = GST_FLOW_UNEXPECTED; ret = GST_FLOW_UNEXPECTED;
goto eos; goto eos;
@ -5360,7 +5279,7 @@ pause:
GST_LOG_OBJECT (demux, "pausing task, reason %s", reason); GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
demux->segment_running = FALSE; demux->segment_running = FALSE;
gst_pad_pause_task (demux->sinkpad); gst_pad_pause_task (demux->common.sinkpad);
if (ret == GST_FLOW_UNEXPECTED) { if (ret == GST_FLOW_UNEXPECTED) {
/* perform EOS logic */ /* perform EOS logic */
@ -5428,7 +5347,7 @@ perform_seek_to_offset (GstMatroskaDemux * demux, guint64 offset)
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
GST_SEEK_TYPE_NONE, -1); GST_SEEK_TYPE_NONE, -1);
res = gst_pad_push_event (demux->sinkpad, event); res = gst_pad_push_event (demux->common.sinkpad, event);
/* newsegment event will update offset */ /* newsegment event will update offset */
return res; return res;
@ -5446,7 +5365,7 @@ gst_matroska_demux_peek_id_length_push (GstMatroskaDemux * demux, guint32 * _id,
{ {
return gst_ebml_peek_id_length (_id, _length, _needed, return gst_ebml_peek_id_length (_id, _length, _needed,
(GstPeekData) gst_matroska_demux_peek_adapter, (gpointer) demux, (GstPeekData) gst_matroska_demux_peek_adapter, (gpointer) demux,
GST_ELEMENT_CAST (demux), demux->offset); GST_ELEMENT_CAST (demux), demux->common.offset);
} }
static GstFlowReturn static GstFlowReturn
@ -5478,8 +5397,8 @@ next:
return ret; return ret;
GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, " GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
"size %" G_GUINT64_FORMAT ", needed %d, available %d", demux->offset, id, "size %" G_GUINT64_FORMAT ", needed %d, available %d",
length, needed, available); demux->common.offset, id, length, needed, available);
if (needed > available) if (needed > available)
return GST_FLOW_OK; return GST_FLOW_OK;
@ -5538,7 +5457,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event)
/* clear current segment leftover */ /* clear current segment leftover */
gst_adapter_clear (demux->adapter); gst_adapter_clear (demux->adapter);
/* and some streaming setup */ /* and some streaming setup */
demux->offset = start; demux->common.offset = start;
/* do not know where we are; /* do not know where we are;
* need to come across a cluster and generate newsegment */ * need to come across a cluster and generate newsegment */
demux->segment.last_stop = GST_CLOCK_TIME_NONE; demux->segment.last_stop = GST_CLOCK_TIME_NONE;

View file

@ -51,7 +51,6 @@ typedef struct _GstMatroskaDemux {
GstMatroskaReadCommon common; GstMatroskaReadCommon common;
/* pads */ /* pads */
GstPad *sinkpad;
GstClock *clock; GstClock *clock;
guint num_v_streams; guint num_v_streams;
guint num_a_streams; guint num_a_streams;
@ -87,11 +86,6 @@ typedef struct _GstMatroskaDemux {
GstEvent *new_segment; GstEvent *new_segment;
GstTagList *global_tags; GstTagList *global_tags;
/* pull mode caching */
GstBuffer *cached_buffer;
/* push and pull mode */
guint64 offset;
/* some state saving */ /* some state saving */
GstClockTime cluster_time; GstClockTime cluster_time;
guint64 cluster_offset; guint64 cluster_offset;

View file

@ -204,12 +204,13 @@ static void
gst_matroska_parse_init (GstMatroskaParse * parse, gst_matroska_parse_init (GstMatroskaParse * parse,
GstMatroskaParseClass * klass) GstMatroskaParseClass * klass)
{ {
parse->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink"); parse->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
gst_pad_set_chain_function (parse->sinkpad, "sink");
gst_pad_set_chain_function (parse->common.sinkpad,
GST_DEBUG_FUNCPTR (gst_matroska_parse_chain)); GST_DEBUG_FUNCPTR (gst_matroska_parse_chain));
gst_pad_set_event_function (parse->sinkpad, gst_pad_set_event_function (parse->common.sinkpad,
GST_DEBUG_FUNCPTR (gst_matroska_parse_handle_sink_event)); GST_DEBUG_FUNCPTR (gst_matroska_parse_handle_sink_event));
gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); gst_element_add_pad (GST_ELEMENT (parse), parse->common.sinkpad);
parse->srcpad = gst_pad_new_from_static_template (&src_templ, "src"); parse->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
gst_pad_set_event_function (parse->srcpad, gst_pad_set_event_function (parse->srcpad,
@ -340,7 +341,7 @@ gst_matroska_parse_reset (GstElement * element)
parse->last_stop_end = GST_CLOCK_TIME_NONE; parse->last_stop_end = GST_CLOCK_TIME_NONE;
parse->seek_block = 0; parse->seek_block = 0;
parse->offset = 0; parse->common.offset = 0;
parse->cluster_time = GST_CLOCK_TIME_NONE; parse->cluster_time = GST_CLOCK_TIME_NONE;
parse->cluster_offset = 0; parse->cluster_offset = 0;
parse->next_cluster_offset = 0; parse->next_cluster_offset = 0;
@ -377,103 +378,19 @@ gst_matroska_parse_reset (GstElement * element)
} }
parse->global_tags = gst_tag_list_new (); parse->global_tags = gst_tag_list_new ();
if (parse->cached_buffer) { if (parse->common.cached_buffer) {
gst_buffer_unref (parse->cached_buffer); gst_buffer_unref (parse->common.cached_buffer);
parse->cached_buffer = NULL; parse->common.cached_buffer = NULL;
} }
} }
/*
* Calls pull_range for (offset,size) without advancing our offset
*/
static GstFlowReturn
gst_matroska_parse_peek_bytes (GstMatroskaParse * parse, guint64 offset,
guint size, GstBuffer ** p_buf, guint8 ** bytes)
{
GstFlowReturn ret;
/* Caching here actually makes much less difference than one would expect.
* We do it mainly to avoid pulling buffers of 1 byte all the time */
if (parse->cached_buffer) {
guint64 cache_offset = GST_BUFFER_OFFSET (parse->cached_buffer);
guint cache_size = GST_BUFFER_SIZE (parse->cached_buffer);
if (cache_offset <= parse->offset &&
(parse->offset + size) <= (cache_offset + cache_size)) {
if (p_buf)
*p_buf = gst_buffer_create_sub (parse->cached_buffer,
parse->offset - cache_offset, size);
if (bytes)
*bytes = GST_BUFFER_DATA (parse->cached_buffer) + parse->offset -
cache_offset;
return GST_FLOW_OK;
}
/* not enough data in the cache, free cache and get a new one */
gst_buffer_unref (parse->cached_buffer);
parse->cached_buffer = NULL;
}
/* refill the cache */
ret = gst_pad_pull_range (parse->sinkpad, parse->offset,
MAX (size, 64 * 1024), &parse->cached_buffer);
if (ret != GST_FLOW_OK) {
parse->cached_buffer = NULL;
return ret;
}
if (GST_BUFFER_SIZE (parse->cached_buffer) >= size) {
if (p_buf)
*p_buf = gst_buffer_create_sub (parse->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (parse->cached_buffer);
return GST_FLOW_OK;
}
/* Not possible to get enough data, try a last time with
* requesting exactly the size we need */
gst_buffer_unref (parse->cached_buffer);
parse->cached_buffer = NULL;
ret =
gst_pad_pull_range (parse->sinkpad, parse->offset, size,
&parse->cached_buffer);
if (ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (parse, "pull_range returned %d", ret);
if (p_buf)
*p_buf = NULL;
if (bytes)
*bytes = NULL;
return ret;
}
if (GST_BUFFER_SIZE (parse->cached_buffer) < size) {
GST_WARNING_OBJECT (parse, "Dropping short buffer at offset %"
G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", parse->offset,
size, GST_BUFFER_SIZE (parse->cached_buffer));
gst_buffer_unref (parse->cached_buffer);
parse->cached_buffer = NULL;
if (p_buf)
*p_buf = NULL;
if (bytes)
*bytes = NULL;
return GST_FLOW_UNEXPECTED;
}
if (p_buf)
*p_buf = gst_buffer_create_sub (parse->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (parse->cached_buffer);
return GST_FLOW_OK;
}
static const guint8 * static const guint8 *
gst_matroska_parse_peek_pull (GstMatroskaParse * parse, guint peek) gst_matroska_parse_peek_pull (GstMatroskaParse * parse, guint peek)
{ {
guint8 *data = NULL; guint8 *data = NULL;
gst_matroska_parse_peek_bytes (parse, parse->offset, peek, NULL, &data); gst_matroska_read_common_peek_bytes (&parse->common, parse->common.offset,
peek, NULL, &data);
return data; return data;
} }
@ -483,7 +400,7 @@ gst_matroska_parse_peek_id_length_pull (GstMatroskaParse * parse, guint32 * _id,
{ {
return gst_ebml_peek_id_length (_id, _length, _needed, return gst_ebml_peek_id_length (_id, _length, _needed,
(GstPeekData) gst_matroska_parse_peek_pull, (gpointer) parse, (GstPeekData) gst_matroska_parse_peek_pull, (gpointer) parse,
GST_ELEMENT_CAST (parse), parse->offset); GST_ELEMENT_CAST (parse), parse->common.offset);
} }
static gint64 static gint64
@ -492,7 +409,7 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse)
GstFormat fmt = GST_FORMAT_BYTES; GstFormat fmt = GST_FORMAT_BYTES;
gint64 end = -1; gint64 end = -1;
if (!gst_pad_query_peer_duration (parse->sinkpad, &fmt, &end) || if (!gst_pad_query_peer_duration (parse->common.sinkpad, &fmt, &end) ||
fmt != GST_FORMAT_BYTES || end < 0) fmt != GST_FORMAT_BYTES || end < 0)
GST_DEBUG_OBJECT (parse, "no upstream length"); GST_DEBUG_OBJECT (parse, "no upstream length");
@ -1608,14 +1525,14 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
guint32 id; guint32 id;
guint needed; guint needed;
orig_offset = parse->offset; orig_offset = parse->common.offset;
/* read in at newpos and scan for ebml cluster id */ /* read in at newpos and scan for ebml cluster id */
while (1) { while (1) {
GstByteReader reader; GstByteReader reader;
gint cluster_pos; gint cluster_pos;
ret = gst_pad_pull_range (parse->sinkpad, newpos, chunk, &buf); ret = gst_pad_pull_range (parse->common.sinkpad, newpos, chunk, &buf);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
break; break;
GST_DEBUG_OBJECT (parse, "read buffer size %d at offset %" G_GINT64_FORMAT, GST_DEBUG_OBJECT (parse, "read buffer size %d at offset %" G_GINT64_FORMAT,
@ -1640,7 +1557,7 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
GST_DEBUG_OBJECT (parse, "cluster is first cluster -> OK"); GST_DEBUG_OBJECT (parse, "cluster is first cluster -> OK");
break; break;
} }
parse->offset = newpos; parse->common.offset = newpos;
ret = ret =
gst_matroska_parse_peek_id_length_pull (parse, &id, &length, &needed); gst_matroska_parse_peek_id_length_pull (parse, &id, &length, &needed);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
@ -1654,7 +1571,7 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
break; break;
} }
/* skip cluster */ /* skip cluster */
parse->offset += length + needed; parse->common.offset += length + needed;
ret = ret =
gst_matroska_parse_peek_id_length_pull (parse, &id, &length, &needed); gst_matroska_parse_peek_id_length_pull (parse, &id, &length, &needed);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
@ -1678,7 +1595,7 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
buf = NULL; buf = NULL;
} }
parse->offset = orig_offset; parse->common.offset = orig_offset;
*pos = newpos; *pos = newpos;
return ret; return ret;
} }
@ -1874,7 +1791,7 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
case GST_EVENT_LATENCY: case GST_EVENT_LATENCY:
default: default:
res = gst_pad_push_event (parse->sinkpad, event); res = gst_pad_push_event (parse->common.sinkpad, event);
break; break;
} }
@ -3455,7 +3372,7 @@ gst_matroska_parse_check_parse_error (GstMatroskaParse * parse)
/* sigh, one last attempt above and beyond call of duty ...; /* sigh, one last attempt above and beyond call of duty ...;
* search for cluster mark following current pos */ * search for cluster mark following current pos */
pos = parse->offset; pos = parse->common.offset;
GST_WARNING_OBJECT (parse, "parse error, looking for next cluster"); GST_WARNING_OBJECT (parse, "parse error, looking for next cluster");
if (gst_matroska_parse_search_cluster (parse, &pos) != GST_FLOW_OK) { if (gst_matroska_parse_search_cluster (parse, &pos) != GST_FLOW_OK) {
/* did not work, give up */ /* did not work, give up */
@ -3463,7 +3380,7 @@ gst_matroska_parse_check_parse_error (GstMatroskaParse * parse)
} else { } else {
GST_DEBUG_OBJECT (parse, "... found at %" G_GUINT64_FORMAT, pos); GST_DEBUG_OBJECT (parse, "... found at %" G_GUINT64_FORMAT, pos);
/* try that position */ /* try that position */
parse->offset = pos; parse->common.offset = pos;
return FALSE; return FALSE;
} }
} }
@ -3491,8 +3408,9 @@ gst_matroska_parse_take (GstMatroskaParse * parse, guint64 bytes,
else else
ret = GST_FLOW_UNEXPECTED; ret = GST_FLOW_UNEXPECTED;
if (G_LIKELY (buffer)) { if (G_LIKELY (buffer)) {
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (parse), buffer, parse->offset); gst_ebml_read_init (ebml, GST_ELEMENT_CAST (parse), buffer,
parse->offset += bytes; parse->common.offset);
parse->common.offset += bytes;
} }
exit: exit:
return ret; return ret;
@ -3506,7 +3424,7 @@ gst_matroska_parse_check_seekability (GstMatroskaParse * parse)
gint64 start = -1, stop = -1; gint64 start = -1, stop = -1;
query = gst_query_new_seeking (GST_FORMAT_BYTES); query = gst_query_new_seeking (GST_FORMAT_BYTES);
if (!gst_pad_peer_query (parse->sinkpad, query)) { if (!gst_pad_peer_query (parse->common.sinkpad, query)) {
GST_DEBUG_OBJECT (parse, "seeking query failed"); GST_DEBUG_OBJECT (parse, "seeking query failed");
goto done; goto done;
} }
@ -3518,7 +3436,7 @@ gst_matroska_parse_check_seekability (GstMatroskaParse * parse)
GstFormat fmt = GST_FORMAT_BYTES; GstFormat fmt = GST_FORMAT_BYTES;
GST_DEBUG_OBJECT (parse, "doing duration query to fix up unset stop"); GST_DEBUG_OBJECT (parse, "doing duration query to fix up unset stop");
gst_pad_query_peer_duration (parse->sinkpad, &fmt, &stop); gst_pad_query_peer_duration (parse->common.sinkpad, &fmt, &stop);
} }
/* if upstream doesn't know the size, it's likely that it's not seekable in /* if upstream doesn't know the size, it's likely that it's not seekable in
@ -3550,7 +3468,7 @@ gst_matroska_parse_find_tracks (GstMatroskaParse * parse)
"Found Cluster element before Tracks, searching Tracks"); "Found Cluster element before Tracks, searching Tracks");
/* remember */ /* remember */
before_pos = parse->offset; before_pos = parse->common.offset;
/* Search Tracks element */ /* Search Tracks element */
while (TRUE) { while (TRUE) {
@ -3565,7 +3483,7 @@ gst_matroska_parse_find_tracks (GstMatroskaParse * parse)
ret = gst_matroska_parse_check_read_size (parse, length); ret = gst_matroska_parse_check_read_size (parse, length);
break; break;
} else { } else {
parse->offset += needed; parse->common.offset += needed;
parse->offset += length; parse->offset += length;
} }
continue; continue;
@ -3723,10 +3641,10 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
GST_READ_CHECK (gst_matroska_parse_take (parse, needed, &ebml)); GST_READ_CHECK (gst_matroska_parse_take (parse, needed, &ebml));
GST_DEBUG_OBJECT (parse, GST_DEBUG_OBJECT (parse,
"Found Segment start at offset %" G_GUINT64_FORMAT, "Found Segment start at offset %" G_GUINT64_FORMAT,
parse->offset); parse->common.offset);
/* seeks are from the beginning of the segment, /* seeks are from the beginning of the segment,
* after the segment ID/length */ * after the segment ID/length */
parse->common.ebml_segment_start = parse->offset; parse->common.ebml_segment_start = parse->common.offset;
parse->common.state = GST_MATROSKA_READ_STATE_HEADER; parse->common.state = GST_MATROSKA_READ_STATE_HEADER;
gst_matroska_parse_accumulate_streamheader (parse, ebml.buf); gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
break; break;
@ -3770,11 +3688,11 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
if (G_UNLIKELY (parse->common.state if (G_UNLIKELY (parse->common.state
== GST_MATROSKA_READ_STATE_HEADER)) { == GST_MATROSKA_READ_STATE_HEADER)) {
parse->common.state = GST_MATROSKA_READ_STATE_DATA; parse->common.state = GST_MATROSKA_READ_STATE_DATA;
parse->first_cluster_offset = parse->offset; parse->first_cluster_offset = parse->common.offset;
GST_DEBUG_OBJECT (parse, "signaling no more pads"); GST_DEBUG_OBJECT (parse, "signaling no more pads");
} }
parse->cluster_time = GST_CLOCK_TIME_NONE; parse->cluster_time = GST_CLOCK_TIME_NONE;
parse->cluster_offset = parse->offset; parse->cluster_offset = parse->common.offset;
if (G_UNLIKELY (!parse->seek_first && parse->seek_block)) { if (G_UNLIKELY (!parse->seek_first && parse->seek_block)) {
GST_DEBUG_OBJECT (parse, "seek target block %" G_GUINT64_FORMAT GST_DEBUG_OBJECT (parse, "seek target block %" G_GUINT64_FORMAT
" not found in Cluster, trying next Cluster's first block instead", " not found in Cluster, trying next Cluster's first block instead",
@ -4040,7 +3958,7 @@ pause:
GST_LOG_OBJECT (parse, "pausing task, reason %s", reason); GST_LOG_OBJECT (parse, "pausing task, reason %s", reason);
parse->segment_running = FALSE; parse->segment_running = FALSE;
gst_pad_pause_task (parse->sinkpad); gst_pad_pause_task (parse->common.sinkpad);
if (ret == GST_FLOW_UNEXPECTED) { if (ret == GST_FLOW_UNEXPECTED) {
/* perform EOS logic */ /* perform EOS logic */
@ -4109,7 +4027,7 @@ perform_seek_to_offset (GstMatroskaParse * parse, guint64 offset)
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
GST_SEEK_TYPE_NONE, -1); GST_SEEK_TYPE_NONE, -1);
res = gst_pad_push_event (parse->sinkpad, event); res = gst_pad_push_event (parse->common.sinkpad, event);
/* newsegment event will update offset */ /* newsegment event will update offset */
return res; return res;
@ -4127,7 +4045,7 @@ gst_matroska_parse_peek_id_length_push (GstMatroskaParse * parse, guint32 * _id,
{ {
return gst_ebml_peek_id_length (_id, _length, _needed, return gst_ebml_peek_id_length (_id, _length, _needed,
(GstPeekData) gst_matroska_parse_peek_adapter, (gpointer) parse, (GstPeekData) gst_matroska_parse_peek_adapter, (gpointer) parse,
GST_ELEMENT_CAST (parse), parse->offset); GST_ELEMENT_CAST (parse), parse->common.offset);
} }
static GstFlowReturn static GstFlowReturn
@ -4159,8 +4077,8 @@ next:
return ret; return ret;
GST_LOG_OBJECT (parse, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, " GST_LOG_OBJECT (parse, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
"size %" G_GUINT64_FORMAT ", needed %d, available %d", parse->offset, id, "size %" G_GUINT64_FORMAT ", needed %d, available %d",
length, needed, available); parse->common.offset, id, length, needed, available);
if (needed > available) if (needed > available)
return GST_FLOW_OK; return GST_FLOW_OK;
@ -4218,7 +4136,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
/* clear current segment leftover */ /* clear current segment leftover */
gst_adapter_clear (parse->adapter); gst_adapter_clear (parse->adapter);
/* and some streaming setup */ /* and some streaming setup */
parse->offset = start; parse->common.offset = start;
/* do not know where we are; /* do not know where we are;
* need to come across a cluster and generate newsegment */ * need to come across a cluster and generate newsegment */
parse->segment.last_stop = GST_CLOCK_TIME_NONE; parse->segment.last_stop = GST_CLOCK_TIME_NONE;

View file

@ -51,7 +51,6 @@ typedef struct _GstMatroskaParse {
GstMatroskaReadCommon common; GstMatroskaReadCommon common;
/* pads */ /* pads */
GstPad *sinkpad;
GstPad *srcpad; GstPad *srcpad;
GstClock *clock; GstClock *clock;
guint num_v_streams; guint num_v_streams;
@ -89,11 +88,6 @@ typedef struct _GstMatroskaParse {
GstEvent *new_segment; GstEvent *new_segment;
GstTagList *global_tags; GstTagList *global_tags;
/* pull mode caching */
GstBuffer *cached_buffer;
/* push and pull mode */
guint64 offset;
/* some state saving */ /* some state saving */
GstClockTime cluster_time; GstClockTime cluster_time;
guint64 cluster_offset; guint64 cluster_offset;

View file

@ -624,6 +624,91 @@ gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
return ret; return ret;
} }
/*
* Calls pull_range for (offset,size) without advancing our offset
*/
GstFlowReturn
gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon * common, guint64
offset, guint size, GstBuffer ** p_buf, guint8 ** bytes)
{
GstFlowReturn ret;
/* Caching here actually makes much less difference than one would expect.
* We do it mainly to avoid pulling buffers of 1 byte all the time */
if (common->cached_buffer) {
guint64 cache_offset = GST_BUFFER_OFFSET (common->cached_buffer);
guint cache_size = GST_BUFFER_SIZE (common->cached_buffer);
if (cache_offset <= common->offset &&
(common->offset + size) <= (cache_offset + cache_size)) {
if (p_buf)
*p_buf = gst_buffer_create_sub (common->cached_buffer,
common->offset - cache_offset, size);
if (bytes)
*bytes = GST_BUFFER_DATA (common->cached_buffer) + common->offset -
cache_offset;
return GST_FLOW_OK;
}
/* not enough data in the cache, free cache and get a new one */
gst_buffer_unref (common->cached_buffer);
common->cached_buffer = NULL;
}
/* refill the cache */
ret = gst_pad_pull_range (common->sinkpad, common->offset,
MAX (size, 64 * 1024), &common->cached_buffer);
if (ret != GST_FLOW_OK) {
common->cached_buffer = NULL;
return ret;
}
if (GST_BUFFER_SIZE (common->cached_buffer) >= size) {
if (p_buf)
*p_buf = gst_buffer_create_sub (common->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (common->cached_buffer);
return GST_FLOW_OK;
}
/* Not possible to get enough data, try a last time with
* requesting exactly the size we need */
gst_buffer_unref (common->cached_buffer);
common->cached_buffer = NULL;
ret =
gst_pad_pull_range (common->sinkpad, common->offset, size,
&common->cached_buffer);
if (ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (common, "pull_range returned %d", ret);
if (p_buf)
*p_buf = NULL;
if (bytes)
*bytes = NULL;
return ret;
}
if (GST_BUFFER_SIZE (common->cached_buffer) < size) {
GST_WARNING_OBJECT (common, "Dropping short buffer at offset %"
G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", common->offset,
size, GST_BUFFER_SIZE (common->cached_buffer));
gst_buffer_unref (common->cached_buffer);
common->cached_buffer = NULL;
if (p_buf)
*p_buf = NULL;
if (bytes)
*bytes = NULL;
return GST_FLOW_UNEXPECTED;
}
if (p_buf)
*p_buf = gst_buffer_create_sub (common->cached_buffer, 0, size);
if (bytes)
*bytes = GST_BUFFER_DATA (common->cached_buffer);
return GST_FLOW_OK;
}
GstFlowReturn GstFlowReturn
gst_matroska_read_common_read_track_encoding (GstMatroskaReadCommon * common, gst_matroska_read_common_read_track_encoding (GstMatroskaReadCommon * common,
GstEbmlRead * ebml, GstMatroskaTrackContext * context) GstEbmlRead * ebml, GstMatroskaTrackContext * context)

View file

@ -44,6 +44,7 @@ typedef struct _GstMatroskaReadCommon {
gint element_index_writer_id; gint element_index_writer_id;
/* pads */ /* pads */
GstPad *sinkpad;
GPtrArray *src; GPtrArray *src;
guint num_streams; guint num_streams;
@ -61,6 +62,12 @@ typedef struct _GstMatroskaReadCommon {
/* timescale in the file */ /* timescale in the file */
guint64 time_scale; guint64 time_scale;
/* pull mode caching */
GstBuffer *cached_buffer;
/* push and pull mode */
guint64 offset;
} GstMatroskaReadCommon; } GstMatroskaReadCommon;
GstFlowReturn gst_matroska_decode_content_encodings (GArray * encodings); GstFlowReturn gst_matroska_decode_content_encodings (GArray * encodings);
@ -71,6 +78,8 @@ GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
common, GstEbmlRead * ebml); common, GstEbmlRead * ebml);
GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon * GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
common, GstEbmlRead * ebml, const gchar * parent_name, guint id); common, GstEbmlRead * ebml, const gchar * parent_name, guint id);
GstFlowReturn gst_matroska_read_common_peek_bytes (GstMatroskaReadCommon *
common, guint64 offset, guint size, GstBuffer ** p_buf, guint8 ** bytes);
gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common, gint gst_matroska_read_common_stream_from_num (GstMatroskaReadCommon * common,
guint track_num); guint track_num);
GstFlowReturn gst_matroska_read_common_read_track_encoding ( GstFlowReturn gst_matroska_read_common_read_track_encoding (