ext/wavpack/gstwavpackparse.c: Fix resyncing in push mode not stopping re-syncing at embedded zeroes; skip garbage be...

Original commit message from CVS:
Based on patch by: Sebastian Dröge <slomo at circular-chaos.org>
* ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_sink_event),
(gst_wavpack_parse_get_upstream_length),
(gst_wavpack_parse_find_marker), (gst_wavpack_parse_resync_loop),
(gst_wavpack_parse_loop), (gst_wavpack_parse_resync_adapter):
Fix resyncing in push mode not stopping re-syncing at embedded
zeroes; skip garbage between frames in pull mode as well if
necessary; use gst_pad_query_peer_duration(); push EOS and
NEWSEGMENT event in right direction (#351659).
This commit is contained in:
Sebastian Dröge 2006-08-18 21:39:00 +00:00 committed by Tim-Philipp Müller
parent 8938587f17
commit 611b2dd11b

View file

@ -594,7 +594,7 @@ gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
if (parse->adapter) { if (parse->adapter) {
gst_adapter_clear (parse->adapter); gst_adapter_clear (parse->adapter);
} }
ret = gst_pad_push_event (pad, event); ret = gst_pad_push_event (parse->srcpad, event);
break; break;
} }
case GST_EVENT_NEWSEGMENT:{ case GST_EVENT_NEWSEGMENT:{
@ -609,7 +609,7 @@ gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
* be a complete Wavpack block and we can't do anything with them */ * be a complete Wavpack block and we can't do anything with them */
gst_adapter_clear (parse->adapter); gst_adapter_clear (parse->adapter);
} }
ret = gst_pad_push_event (pad, event); ret = gst_pad_push_event (parse->srcpad, event);
break; break;
} }
default:{ default:{
@ -678,23 +678,15 @@ gst_wavpack_parse_init (GstWavpackParse * wavpackparse,
static gint64 static gint64
gst_wavpack_parse_get_upstream_length (GstWavpackParse * wavpackparse) gst_wavpack_parse_get_upstream_length (GstWavpackParse * wavpackparse)
{ {
GstPad *peer;
gint64 length = -1; gint64 length = -1;
peer = gst_pad_get_peer (wavpackparse->sinkpad); GstFormat format = GST_FORMAT_BYTES;
if (peer) {
GstFormat format = GST_FORMAT_BYTES;
if (!gst_pad_query_duration (peer, &format, &length)) { if (!gst_pad_query_peer_duration (wavpackparse->sinkpad, &format, &length)) {
length = -1; length = -1;
} else {
GST_DEBUG ("upstream length: %" G_GINT64_FORMAT, length);
}
gst_object_unref (peer);
} else { } else {
GST_DEBUG ("no peer!"); GST_DEBUG ("upstream length: %" G_GINT64_FORMAT, length);
} }
return length; return length;
} }
@ -865,6 +857,89 @@ gst_wavpack_parse_push_buffer (GstWavpackParse * wvparse, GstBuffer * buf,
return gst_pad_push (wvparse->srcpad, buf); return gst_pad_push (wvparse->srcpad, buf);
} }
static guint8 *
gst_wavpack_parse_find_marker (guint8 * buf, guint size)
{
int i;
guint8 *ret = NULL;
if (G_UNLIKELY (size < 4))
return NULL;
for (i = 0; i < size - 4; i++) {
if (memcmp (buf + i, "wvpk", 4) == 0) {
ret = buf + i;
break;
}
}
return ret;
}
static GstFlowReturn
gst_wavpack_parse_resync_loop (GstWavpackParse * parse, WavpackHeader * header)
{
GstFlowReturn flow_ret = GST_FLOW_UNEXPECTED;
GstBuffer *buf = NULL;
/* loop until we have a frame header or reach the end of the stream */
while (1) {
guint8 *data, *marker;
guint len, size;
if (buf) {
gst_buffer_unref (buf);
buf = NULL;
}
if (parse->upstream_length == 0 ||
parse->upstream_length <= parse->current_offset) {
parse->upstream_length = gst_wavpack_parse_get_upstream_length (parse);
if (parse->upstream_length == 0 ||
parse->upstream_length <= parse->current_offset) {
break;
}
}
len = MIN (parse->upstream_length - parse->current_offset, 2048);
GST_LOG_OBJECT (parse, "offset: %" G_GINT64_FORMAT, parse->current_offset);
buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
len, &flow_ret);
/* whatever the problem is, there's nothing more for us to do for now */
if (buf == NULL)
break;
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
/* not enough data for a header? */
if (size < sizeof (WavpackHeader))
break;
/* got a header right where we are at now? */
if (gst_wavpack_read_header (header, data))
break;
/* nope, let's see if we can find one */
marker = gst_wavpack_parse_find_marker (data + 1, size - 1);
if (marker) {
parse->current_offset += marker - data;
/* do one more loop iteration to make sure we pull enough
* data for a full header, we'll bail out then */
} else {
parse->current_offset += len - 4;
}
}
if (buf)
gst_buffer_unref (buf);
return flow_ret;
}
static void static void
gst_wavpack_parse_loop (GstElement * element) gst_wavpack_parse_loop (GstElement * element)
{ {
@ -873,21 +948,14 @@ gst_wavpack_parse_loop (GstElement * element)
WavpackHeader header = { {0,}, 0, }; WavpackHeader header = { {0,}, 0, };
GstBuffer *buf = NULL; GstBuffer *buf = NULL;
GST_LOG_OBJECT (wavpackparse, "Current offset: %" G_GINT64_FORMAT, flow_ret = gst_wavpack_parse_resync_loop (wavpackparse, &header);
wavpackparse->current_offset);
buf = gst_wavpack_parse_pull_buffer (wavpackparse, if (flow_ret == GST_FLOW_UNEXPECTED) {
wavpackparse->current_offset, sizeof (WavpackHeader), &flow_ret);
if (buf == NULL && flow_ret == GST_FLOW_UNEXPECTED) {
goto eos; goto eos;
} else if (buf == NULL) { } else if (flow_ret != GST_FLOW_OK) {
goto pause; goto pause;
} }
gst_wavpack_read_header (&header, GST_BUFFER_DATA (buf));
gst_buffer_unref (buf);
GST_LOG_OBJECT (wavpackparse, "Read header at offset %" G_GINT64_FORMAT GST_LOG_OBJECT (wavpackparse, "Read header at offset %" G_GINT64_FORMAT
": chunk size = %u+8", wavpackparse->current_offset, header.ckSize); ": chunk size = %u+8", wavpackparse->current_offset, header.ckSize);
@ -938,9 +1006,8 @@ pause:
static gboolean static gboolean
gst_wavpack_parse_resync_adapter (GstAdapter * adapter) gst_wavpack_parse_resync_adapter (GstAdapter * adapter)
{ {
const guint8 *buf; const guint8 *buf, *marker;
guint avail = gst_adapter_available (adapter); guint avail = gst_adapter_available (adapter);
gchar *marker;
if (avail < 4) if (avail < 4)
return FALSE; return FALSE;
@ -955,11 +1022,15 @@ gst_wavpack_parse_resync_adapter (GstAdapter * adapter)
/* search for the marker in the complete content of the adapter */ /* search for the marker in the complete content of the adapter */
buf = gst_adapter_peek (adapter, avail); buf = gst_adapter_peek (adapter, avail);
if (buf && (marker = g_strstr_len ((gchar *) buf, avail, "wvpk"))) { if (buf && (marker = gst_wavpack_parse_find_marker ((guint8 *) buf, avail))) {
gst_adapter_flush (adapter, marker - (gchar *) buf); gst_adapter_flush (adapter, marker - buf);
return TRUE; return TRUE;
} }
/* flush everything except the last 4 bytes. they could contain
* the start of a new marker */
gst_adapter_flush (adapter, avail - 4);
return FALSE; return FALSE;
} }