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,
GstMatroskaDemuxClass * klass)
{
demux->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
gst_pad_set_activate_function (demux->sinkpad,
demux->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
"sink");
gst_pad_set_activate_function (demux->common.sinkpad,
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_pad_set_chain_function (demux->sinkpad,
gst_pad_set_chain_function (demux->common.sinkpad,
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_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
gst_element_add_pad (GST_ELEMENT (demux), demux->common.sinkpad);
/* initial stream no. */
demux->common.src = NULL;
@ -417,7 +418,7 @@ gst_matroska_demux_reset (GstElement * element)
demux->last_stop_end = GST_CLOCK_TIME_NONE;
demux->seek_block = 0;
demux->offset = 0;
demux->common.offset = 0;
demux->cluster_time = GST_CLOCK_TIME_NONE;
demux->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 ();
if (demux->cached_buffer) {
gst_buffer_unref (demux->cached_buffer);
demux->cached_buffer = NULL;
if (demux->common.cached_buffer) {
gst_buffer_unref (demux->common.cached_buffer);
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 *
gst_matroska_demux_peek_pull (GstMatroskaDemux * demux, guint peek)
{
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;
}
@ -560,7 +477,7 @@ gst_matroska_demux_peek_id_length_pull (GstMatroskaDemux * demux, guint32 * _id,
{
return gst_ebml_peek_id_length (_id, _length, _needed,
(GstPeekData) gst_matroska_demux_peek_pull, (gpointer) demux,
GST_ELEMENT_CAST (demux), demux->offset);
GST_ELEMENT_CAST (demux), demux->common.offset);
}
static gint64
@ -569,7 +486,7 @@ gst_matroska_demux_get_length (GstMatroskaDemux * demux)
GstFormat fmt = GST_FORMAT_BYTES;
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)
GST_DEBUG_OBJECT (demux, "no upstream length");
@ -1885,7 +1802,7 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
/* seek (relative to matroska segment) */
/* 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, "
"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;
guint needed;
orig_offset = demux->offset;
orig_offset = demux->common.offset;
GST_LOG_OBJECT (demux, "searching cluster following offset %" G_GINT64_FORMAT,
*pos);
@ -1956,7 +1873,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
if (cpos) {
GST_DEBUG_OBJECT (demux,
"cluster reported at offset %" G_GINT64_FORMAT, *cpos);
demux->offset = *cpos;
demux->common.offset = *cpos;
ret =
gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed);
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;
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)
break;
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");
break;
}
demux->offset = newpos;
demux->common.offset = newpos;
ret =
gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed);
if (ret != GST_FLOW_OK)
@ -2010,7 +1927,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
break;
}
/* skip cluster */
demux->offset += length + needed;
demux->common.offset += length + needed;
ret =
gst_matroska_demux_peek_id_length_pull (demux, &id, &length, &needed);
if (ret != GST_FLOW_OK)
@ -2035,7 +1952,7 @@ gst_matroska_demux_search_cluster (GstMatroskaDemux * demux, gint64 * pos)
}
exit:
demux->offset = orig_offset;
demux->common.offset = orig_offset;
*pos = newpos;
return ret;
}
@ -2069,13 +1986,13 @@ gst_matroska_demux_search_pos (GstMatroskaDemux * demux, GstClockTime time)
current_cluster_offset = demux->cluster_offset;
current_cluster_time = demux->cluster_time;
current_offset = demux->offset;
current_offset = demux->common.offset;
demux->common.state = GST_MATROSKA_READ_STATE_SCANNING;
/* estimate using start and current position */
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;
GST_OBJECT_UNLOCK (demux);
@ -2121,7 +2038,7 @@ retry:
/* then start scanning and parsing for cluster time,
* 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;
while (1) {
guint64 cluster_size = 0;
@ -2131,7 +2048,7 @@ retry:
if (ret != GST_FLOW_OK)
goto error;
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);
ret = gst_matroska_demux_parse_id (demux, id, length, needed);
if (ret != GST_FLOW_OK)
@ -2178,7 +2095,7 @@ retry:
* otherwise will be skippingly parsed into */
if (cluster_size) {
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;
} else {
GST_DEBUG_OBJECT (demux, "parsing/skipping cluster elements");
@ -2208,7 +2125,7 @@ exit:
/* restore some state */
demux->cluster_offset = current_cluster_offset;
demux->cluster_time = current_cluster_time;
demux->offset = current_offset;
demux->common.offset = current_offset;
demux->common.state = current_state;
return entry;
@ -2283,24 +2200,24 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
if (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 ());
} else {
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
* non flushing seeks when the element is in PAUSED this could block
* forever. */
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 */
if (!demux->streaming && !demux->common.index) {
/* need to stop flushing upstream as we need it next */
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);
/* keep local copy */
if (entry) {
@ -2325,7 +2242,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
if (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 ());
} else if (demux->segment_running) {
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
* flush. */
demux->segment_running = TRUE;
gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_matroska_demux_loop,
demux->sinkpad);
gst_pad_start_task (demux->common.sinkpad,
(GstTaskFunction) gst_matroska_demux_loop, demux->common.sinkpad);
/* streaming can continue now */
GST_PAD_STREAM_UNLOCK (demux->sinkpad);
GST_PAD_STREAM_UNLOCK (demux->common.sinkpad);
return TRUE;
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"));
return FALSE;
}
@ -2519,7 +2436,7 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstEvent * event)
case GST_EVENT_LATENCY:
default:
res = gst_pad_push_event (demux->sinkpad, event);
res = gst_pad_push_event (demux->common.sinkpad, event);
break;
}
@ -4673,7 +4590,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
/* remember */
length = gst_matroska_demux_get_length (demux);
before_pos = demux->offset;
before_pos = demux->common.offset;
if (length == (guint64) - 1) {
GST_DEBUG_OBJECT (demux, "no upstream length, skipping SeakHead entry");
@ -4701,7 +4618,7 @@ gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
}
/* seek */
demux->offset = seek_pos + demux->common.ebml_segment_start;
demux->common.offset = seek_pos + demux->common.ebml_segment_start;
/* check ID */
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:
/* seek back */
demux->offset = before_pos;
demux->common.offset = before_pos;
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 */
GST_WARNING_OBJECT (demux, "parse error, trying next cluster expected at %"
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;
return FALSE;
} else {
@ -4831,7 +4748,7 @@ gst_matroska_demux_check_parse_error (GstMatroskaDemux * demux)
/* sigh, one last attempt above and beyond call of duty ...;
* search for cluster mark following current pos */
pos = demux->offset;
pos = demux->common.offset;
GST_WARNING_OBJECT (demux, "parse error, looking for next cluster");
if (gst_matroska_demux_search_cluster (demux, &pos) != GST_FLOW_OK) {
/* did not work, give up */
@ -4839,7 +4756,7 @@ gst_matroska_demux_check_parse_error (GstMatroskaDemux * demux)
} else {
GST_DEBUG_OBJECT (demux, "... found at %" G_GUINT64_FORMAT, pos);
/* try that position */
demux->offset = pos;
demux->common.offset = pos;
return FALSE;
}
}
@ -4849,7 +4766,7 @@ static inline GstFlowReturn
gst_matroska_demux_flush (GstMatroskaDemux * demux, guint flush)
{
GST_LOG_OBJECT (demux, "skipping %d bytes", flush);
demux->offset += flush;
demux->common.offset += flush;
if (demux->streaming) {
GstFlowReturn ret;
@ -4895,11 +4812,12 @@ gst_matroska_demux_take (GstMatroskaDemux * demux, guint64 bytes,
else
ret = GST_FLOW_UNEXPECTED;
} else
ret = gst_matroska_demux_peek_bytes (demux, demux->offset, bytes, &buffer,
NULL);
ret = gst_matroska_read_common_peek_bytes (&demux->common,
demux->common.offset, bytes, &buffer, NULL);
if (G_LIKELY (buffer)) {
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (demux), buffer, demux->offset);
demux->offset += bytes;
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (demux), buffer,
demux->common.offset);
demux->common.offset += bytes;
}
exit:
return ret;
@ -4913,7 +4831,7 @@ gst_matroska_demux_check_seekability (GstMatroskaDemux * demux)
gint64 start = -1, stop = -1;
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");
goto done;
}
@ -4925,7 +4843,7 @@ gst_matroska_demux_check_seekability (GstMatroskaDemux * demux)
GstFormat fmt = GST_FORMAT_BYTES;
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
@ -4956,7 +4874,7 @@ gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
"Found Cluster element before Tracks, searching Tracks");
/* remember */
before_pos = demux->offset;
before_pos = demux->common.offset;
/* Search Tracks element */
while (TRUE) {
@ -4971,8 +4889,8 @@ gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
ret = gst_matroska_demux_check_read_size (demux, length);
break;
} else {
demux->offset += needed;
demux->offset += length;
demux->common.offset += needed;
demux->common.offset += length;
}
continue;
}
@ -4983,7 +4901,7 @@ gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
}
/* seek back */
demux->offset = before_pos;
demux->common.offset = before_pos;
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_DEBUG_OBJECT (demux,
"Found Segment start at offset %" G_GUINT64_FORMAT,
demux->offset);
demux->common.offset);
/* seeks are from the beginning of the segment,
* 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;
break;
default:
@ -5092,7 +5010,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
if (G_UNLIKELY (demux->common.state
== GST_MATROSKA_READ_STATE_HEADER)) {
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_element_no_more_pads (GST_ELEMENT (demux));
/* send initial newsegment */
@ -5103,7 +5021,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
0) ? demux->segment.duration : -1, 0));
}
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)) {
GST_DEBUG_OBJECT (demux, "seek target block %" G_GUINT64_FORMAT
" 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, "
"size %" G_GUINT64_FORMAT ", needed %d", demux->offset, id,
"size %" G_GUINT64_FORMAT ", needed %d", demux->common.offset, id,
length, needed);
ret = gst_matroska_demux_parse_id (demux, id, length, needed);
@ -5335,7 +5253,8 @@ gst_matroska_demux_loop (GstPad * pad)
}
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");
ret = GST_FLOW_UNEXPECTED;
goto eos;
@ -5360,7 +5279,7 @@ pause:
GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
demux->segment_running = FALSE;
gst_pad_pause_task (demux->sinkpad);
gst_pad_pause_task (demux->common.sinkpad);
if (ret == GST_FLOW_UNEXPECTED) {
/* 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_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 */
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,
(GstPeekData) gst_matroska_demux_peek_adapter, (gpointer) demux,
GST_ELEMENT_CAST (demux), demux->offset);
GST_ELEMENT_CAST (demux), demux->common.offset);
}
static GstFlowReturn
@ -5478,8 +5397,8 @@ next:
return ret;
GST_LOG_OBJECT (demux, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
"size %" G_GUINT64_FORMAT ", needed %d, available %d", demux->offset, id,
length, needed, available);
"size %" G_GUINT64_FORMAT ", needed %d, available %d",
demux->common.offset, id, length, needed, available);
if (needed > available)
return GST_FLOW_OK;
@ -5538,7 +5457,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstEvent * event)
/* clear current segment leftover */
gst_adapter_clear (demux->adapter);
/* and some streaming setup */
demux->offset = start;
demux->common.offset = start;
/* do not know where we are;
* need to come across a cluster and generate newsegment */
demux->segment.last_stop = GST_CLOCK_TIME_NONE;

View file

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

View file

@ -204,12 +204,13 @@ static void
gst_matroska_parse_init (GstMatroskaParse * parse,
GstMatroskaParseClass * klass)
{
parse->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
gst_pad_set_chain_function (parse->sinkpad,
parse->common.sinkpad = gst_pad_new_from_static_template (&sink_templ,
"sink");
gst_pad_set_chain_function (parse->common.sinkpad,
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_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");
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->seek_block = 0;
parse->offset = 0;
parse->common.offset = 0;
parse->cluster_time = GST_CLOCK_TIME_NONE;
parse->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 ();
if (parse->cached_buffer) {
gst_buffer_unref (parse->cached_buffer);
parse->cached_buffer = NULL;
if (parse->common.cached_buffer) {
gst_buffer_unref (parse->common.cached_buffer);
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 *
gst_matroska_parse_peek_pull (GstMatroskaParse * parse, guint peek)
{
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;
}
@ -483,7 +400,7 @@ gst_matroska_parse_peek_id_length_pull (GstMatroskaParse * parse, guint32 * _id,
{
return gst_ebml_peek_id_length (_id, _length, _needed,
(GstPeekData) gst_matroska_parse_peek_pull, (gpointer) parse,
GST_ELEMENT_CAST (parse), parse->offset);
GST_ELEMENT_CAST (parse), parse->common.offset);
}
static gint64
@ -492,7 +409,7 @@ gst_matroska_parse_get_length (GstMatroskaParse * parse)
GstFormat fmt = GST_FORMAT_BYTES;
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)
GST_DEBUG_OBJECT (parse, "no upstream length");
@ -1608,14 +1525,14 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
guint32 id;
guint needed;
orig_offset = parse->offset;
orig_offset = parse->common.offset;
/* read in at newpos and scan for ebml cluster id */
while (1) {
GstByteReader reader;
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)
break;
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");
break;
}
parse->offset = newpos;
parse->common.offset = newpos;
ret =
gst_matroska_parse_peek_id_length_pull (parse, &id, &length, &needed);
if (ret != GST_FLOW_OK)
@ -1654,7 +1571,7 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
break;
}
/* skip cluster */
parse->offset += length + needed;
parse->common.offset += length + needed;
ret =
gst_matroska_parse_peek_id_length_pull (parse, &id, &length, &needed);
if (ret != GST_FLOW_OK)
@ -1678,7 +1595,7 @@ gst_matroska_parse_search_cluster (GstMatroskaParse * parse, gint64 * pos)
buf = NULL;
}
parse->offset = orig_offset;
parse->common.offset = orig_offset;
*pos = newpos;
return ret;
}
@ -1874,7 +1791,7 @@ gst_matroska_parse_handle_src_event (GstPad * pad, GstEvent * event)
case GST_EVENT_LATENCY:
default:
res = gst_pad_push_event (parse->sinkpad, event);
res = gst_pad_push_event (parse->common.sinkpad, event);
break;
}
@ -3455,7 +3372,7 @@ gst_matroska_parse_check_parse_error (GstMatroskaParse * parse)
/* sigh, one last attempt above and beyond call of duty ...;
* search for cluster mark following current pos */
pos = parse->offset;
pos = parse->common.offset;
GST_WARNING_OBJECT (parse, "parse error, looking for next cluster");
if (gst_matroska_parse_search_cluster (parse, &pos) != GST_FLOW_OK) {
/* did not work, give up */
@ -3463,7 +3380,7 @@ gst_matroska_parse_check_parse_error (GstMatroskaParse * parse)
} else {
GST_DEBUG_OBJECT (parse, "... found at %" G_GUINT64_FORMAT, pos);
/* try that position */
parse->offset = pos;
parse->common.offset = pos;
return FALSE;
}
}
@ -3491,8 +3408,9 @@ gst_matroska_parse_take (GstMatroskaParse * parse, guint64 bytes,
else
ret = GST_FLOW_UNEXPECTED;
if (G_LIKELY (buffer)) {
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (parse), buffer, parse->offset);
parse->offset += bytes;
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (parse), buffer,
parse->common.offset);
parse->common.offset += bytes;
}
exit:
return ret;
@ -3506,7 +3424,7 @@ gst_matroska_parse_check_seekability (GstMatroskaParse * parse)
gint64 start = -1, stop = -1;
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");
goto done;
}
@ -3518,7 +3436,7 @@ gst_matroska_parse_check_seekability (GstMatroskaParse * parse)
GstFormat fmt = GST_FORMAT_BYTES;
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
@ -3550,7 +3468,7 @@ gst_matroska_parse_find_tracks (GstMatroskaParse * parse)
"Found Cluster element before Tracks, searching Tracks");
/* remember */
before_pos = parse->offset;
before_pos = parse->common.offset;
/* Search Tracks element */
while (TRUE) {
@ -3565,7 +3483,7 @@ gst_matroska_parse_find_tracks (GstMatroskaParse * parse)
ret = gst_matroska_parse_check_read_size (parse, length);
break;
} else {
parse->offset += needed;
parse->common.offset += needed;
parse->offset += length;
}
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_DEBUG_OBJECT (parse,
"Found Segment start at offset %" G_GUINT64_FORMAT,
parse->offset);
parse->common.offset);
/* seeks are from the beginning of the segment,
* 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;
gst_matroska_parse_accumulate_streamheader (parse, ebml.buf);
break;
@ -3770,11 +3688,11 @@ gst_matroska_parse_parse_id (GstMatroskaParse * parse, guint32 id,
if (G_UNLIKELY (parse->common.state
== GST_MATROSKA_READ_STATE_HEADER)) {
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");
}
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)) {
GST_DEBUG_OBJECT (parse, "seek target block %" G_GUINT64_FORMAT
" 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);
parse->segment_running = FALSE;
gst_pad_pause_task (parse->sinkpad);
gst_pad_pause_task (parse->common.sinkpad);
if (ret == GST_FLOW_UNEXPECTED) {
/* 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_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 */
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,
(GstPeekData) gst_matroska_parse_peek_adapter, (gpointer) parse,
GST_ELEMENT_CAST (parse), parse->offset);
GST_ELEMENT_CAST (parse), parse->common.offset);
}
static GstFlowReturn
@ -4159,8 +4077,8 @@ next:
return ret;
GST_LOG_OBJECT (parse, "Offset %" G_GUINT64_FORMAT ", Element id 0x%x, "
"size %" G_GUINT64_FORMAT ", needed %d, available %d", parse->offset, id,
length, needed, available);
"size %" G_GUINT64_FORMAT ", needed %d, available %d",
parse->common.offset, id, length, needed, available);
if (needed > available)
return GST_FLOW_OK;
@ -4218,7 +4136,7 @@ gst_matroska_parse_handle_sink_event (GstPad * pad, GstEvent * event)
/* clear current segment leftover */
gst_adapter_clear (parse->adapter);
/* and some streaming setup */
parse->offset = start;
parse->common.offset = start;
/* do not know where we are;
* need to come across a cluster and generate newsegment */
parse->segment.last_stop = GST_CLOCK_TIME_NONE;

View file

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

View file

@ -624,6 +624,91 @@ gst_matroska_read_common_parse_index (GstMatroskaReadCommon * common,
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
gst_matroska_read_common_read_track_encoding (GstMatroskaReadCommon * common,
GstEbmlRead * ebml, GstMatroskaTrackContext * context)

View file

@ -44,6 +44,7 @@ typedef struct _GstMatroskaReadCommon {
gint element_index_writer_id;
/* pads */
GstPad *sinkpad;
GPtrArray *src;
guint num_streams;
@ -61,6 +62,12 @@ typedef struct _GstMatroskaReadCommon {
/* timescale in the file */
guint64 time_scale;
/* pull mode caching */
GstBuffer *cached_buffer;
/* push and pull mode */
guint64 offset;
} GstMatroskaReadCommon;
GstFlowReturn gst_matroska_decode_content_encodings (GArray * encodings);
@ -71,6 +78,8 @@ GstFlowReturn gst_matroska_read_common_parse_index (GstMatroskaReadCommon *
common, GstEbmlRead * ebml);
GstFlowReturn gst_matroska_read_common_parse_skip (GstMatroskaReadCommon *
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,
guint track_num);
GstFlowReturn gst_matroska_read_common_read_track_encoding (