ext/wavpack/gstwavpackparse.*: Make wavpackparse also work in push-mode (not seekable yet though); some small clean-u...

Original commit message from CVS:
* ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_class_init),
(gst_wavpack_parse_reset), (gst_wavpack_parse_get_src_query_types),
(gst_wavpack_parse_src_query),
(gst_wavpack_parse_handle_seek_event),
(gst_wavpack_parse_sink_event), (gst_wavpack_parse_init),
(gst_wavpack_parse_create_src_pad),
(gst_wavpack_parse_push_buffer), (gst_wavpack_parse_loop),
(gst_wavpack_parse_chain), (gst_wavpack_parse_sink_activate),
(gst_wavpack_parse_sink_activate_pull):
* ext/wavpack/gstwavpackparse.h:
Patch by: Sebastian Dröge <slomo at circular-chaos.org>
Make wavpackparse also work in push-mode (not seekable yet though);
some small clean-ups along the way; add support for SEEKING query
and query types function. (#351495).
This commit is contained in:
Sebastian Dröge 2006-08-15 20:29:45 +00:00 committed by Tim-Philipp Müller
parent 4843f92356
commit 058dec01f1
3 changed files with 208 additions and 50 deletions

View file

@ -1,3 +1,21 @@
2006-08-15 Tim-Philipp Müller <tim at centricular dot net>
* ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_class_init),
(gst_wavpack_parse_reset), (gst_wavpack_parse_get_src_query_types),
(gst_wavpack_parse_src_query),
(gst_wavpack_parse_handle_seek_event),
(gst_wavpack_parse_sink_event), (gst_wavpack_parse_init),
(gst_wavpack_parse_create_src_pad),
(gst_wavpack_parse_push_buffer), (gst_wavpack_parse_loop),
(gst_wavpack_parse_chain), (gst_wavpack_parse_sink_activate),
(gst_wavpack_parse_sink_activate_pull):
* ext/wavpack/gstwavpackparse.h:
Patch by: Sebastian Dröge <slomo at circular-chaos.org>
Make wavpackparse also work in push-mode (not seekable yet though);
some small clean-ups along the way; add support for SEEKING query
and query types function. (#351495).
2006-08-15 Tim-Philipp Müller <tim at centricular dot net> 2006-08-15 Tim-Philipp Müller <tim at centricular dot net>
* ext/libfame/gstlibfame.c: (gst_fameenc_get_property): * ext/libfame/gstlibfame.c: (gst_fameenc_get_property):

View file

@ -57,9 +57,9 @@ static GstStaticPadTemplate wvc_src_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc",
GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true") GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true")
); );
static gboolean gst_wavepack_parse_sink_activate (GstPad * sinkpad); static gboolean gst_wavpack_parse_sink_activate (GstPad * sinkpad);
static gboolean static gboolean
gst_wavepack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active); gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active);
static void gst_wavpack_parse_loop (GstElement * element); static void gst_wavpack_parse_loop (GstElement * element);
static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement * static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement *
@ -68,6 +68,7 @@ static void gst_wavpack_parse_reset (GstWavpackParse * wavpackparse);
static gint64 gst_wavpack_parse_get_upstream_length (GstWavpackParse * wvparse); static gint64 gst_wavpack_parse_get_upstream_length (GstWavpackParse * wvparse);
static GstBuffer *gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse, static GstBuffer *gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse,
gint64 offset, guint size, GstFlowReturn * flow); gint64 offset, guint size, GstFlowReturn * flow);
static GstFlowReturn gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf);
GST_BOILERPLATE (GstWavpackParse, gst_wavpack_parse, GstElement, GST_BOILERPLATE (GstWavpackParse, gst_wavpack_parse, GstElement,
GST_TYPE_ELEMENT); GST_TYPE_ELEMENT);
@ -108,7 +109,7 @@ gst_wavpack_parse_class_init (GstWavpackParseClass * klass)
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass; gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = gst_wavpack_parse_finalize; gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_wavpack_parse_finalize);
gstelement_class->change_state = gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_wavpack_parse_change_state); GST_DEBUG_FUNCPTR (gst_wavpack_parse_change_state);
} }
@ -188,7 +189,7 @@ gst_wavpack_parse_index_append_entry (GstWavpackParse * wvparse,
static void static void
gst_wavpack_parse_reset (GstWavpackParse * wavpackparse) gst_wavpack_parse_reset (GstWavpackParse * wavpackparse)
{ {
wavpackparse->total_samples = 0; wavpackparse->total_samples = -1;
wavpackparse->samplerate = 0; wavpackparse->samplerate = 0;
wavpackparse->channels = 0; wavpackparse->channels = 0;
@ -203,6 +204,12 @@ gst_wavpack_parse_reset (GstWavpackParse * wavpackparse)
wavpackparse->entries = NULL; wavpackparse->entries = NULL;
} }
if (wavpackparse->adapter) {
gst_adapter_clear (wavpackparse->adapter);
g_object_unref (wavpackparse->adapter);
wavpackparse->adapter = NULL;
}
if (wavpackparse->srcpad != NULL) { if (wavpackparse->srcpad != NULL) {
gboolean res; gboolean res;
@ -220,6 +227,19 @@ gst_wavpack_parse_reset (GstWavpackParse * wavpackparse)
wavpackparse->queued_events = NULL; wavpackparse->queued_events = NULL;
} }
static const GstQueryType *
gst_wavpack_parse_get_src_query_types (GstPad * pad)
{
static const GstQueryType types[] = {
GST_QUERY_POSITION,
GST_QUERY_DURATION,
GST_QUERY_SEEKING,
0
};
return types;
}
static gboolean static gboolean
gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query) gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query)
{ {
@ -268,10 +288,12 @@ gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query)
GST_OBJECT_LOCK (wavpackparse); GST_OBJECT_LOCK (wavpackparse);
rate = wavpackparse->samplerate; rate = wavpackparse->samplerate;
len = wavpackparse->total_samples; /* FIXME: return 0 if we work in push based mode to let totem
* recognize that we can't seek */
len = (wavpackparse->adapter) ? 0 : wavpackparse->total_samples;
GST_OBJECT_UNLOCK (wavpackparse); GST_OBJECT_UNLOCK (wavpackparse);
if (len <= 0 || rate == 0) { if (len < 0 || rate == 0) {
GST_DEBUG_OBJECT (wavpackparse, "haven't read header yet"); GST_DEBUG_OBJECT (wavpackparse, "haven't read header yet");
break; break;
} }
@ -295,6 +317,24 @@ gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query)
} }
break; break;
} }
case GST_QUERY_SEEKING:{
gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) {
gboolean seekable;
gint64 duration = -1;
gst_pad_query_duration (pad, &format, &duration);
/* can't seek in streaming mode yet */
GST_OBJECT_LOCK (wavpackparse);
seekable = (wavpackparse->adapter != NULL);
GST_OBJECT_UNLOCK (wavpackparse);
gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
ret = TRUE;
}
break;
}
default:{ default:{
ret = gst_pad_query_default (pad, query); ret = gst_pad_query_default (pad, query);
break; break;
@ -433,6 +473,11 @@ gst_wavpack_parse_handle_seek_event (GstWavpackParse * wvparse,
gint64 chunk_start; /* first sample in chunk we seek to */ gint64 chunk_start; /* first sample in chunk we seek to */
guint rate; guint rate;
if (wvparse->adapter) {
GST_DEBUG_OBJECT (wvparse, "seeking in streaming mode not implemented yet");
return FALSE;
}
gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type, gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type,
&start, &stop_type, &stop); &start, &stop_type, &stop);
@ -544,14 +589,41 @@ gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
/* stream lock is recursive, should be fine for all events */ switch (GST_EVENT_TYPE (event)) {
GST_PAD_STREAM_LOCK (pad); case GST_EVENT_FLUSH_STOP:{
if (parse->srcpad == NULL) { if (parse->adapter) {
parse->queued_events = g_list_append (parse->queued_events, event); gst_adapter_clear (parse->adapter);
} else { }
ret = gst_pad_push_event (parse->srcpad, event); ret = gst_pad_push_event (pad, event);
break;
}
case GST_EVENT_NEWSEGMENT:{
parse->need_newsegment = TRUE;
gst_event_unref (event);
ret = TRUE;
break;
}
case GST_EVENT_EOS:{
if (parse->adapter) {
/* remove all bytes that are left in the adapter after EOS. They can't
* be a complete Wavpack block and we can't do anything with them */
gst_adapter_clear (parse->adapter);
}
ret = gst_pad_push_event (pad, event);
break;
}
default:{
/* stream lock is recursive, should be fine for all events */
GST_PAD_STREAM_LOCK (pad);
if (parse->srcpad == NULL) {
parse->queued_events = g_list_append (parse->queued_events, event);
} else {
ret = gst_pad_push_event (parse->srcpad, event);
}
GST_PAD_STREAM_UNLOCK (pad);
}
} }
GST_PAD_STREAM_UNLOCK (pad);
gst_object_unref (parse); gst_object_unref (parse);
return ret; return ret;
@ -589,11 +661,13 @@ gst_wavpack_parse_init (GstWavpackParse * wavpackparse,
wavpackparse->sinkpad = gst_pad_new_from_template (tmpl, "sink"); wavpackparse->sinkpad = gst_pad_new_from_template (tmpl, "sink");
gst_pad_set_activate_function (wavpackparse->sinkpad, gst_pad_set_activate_function (wavpackparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_wavepack_parse_sink_activate)); GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate));
gst_pad_set_activatepull_function (wavpackparse->sinkpad, gst_pad_set_activatepull_function (wavpackparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_wavepack_parse_sink_activate_pull)); GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate_pull));
gst_pad_set_event_function (wavpackparse->sinkpad, gst_pad_set_event_function (wavpackparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_event)); GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_event));
gst_pad_set_chain_function (wavpackparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_wavpack_parse_chain));
gst_element_add_pad (GST_ELEMENT (wavpackparse), wavpackparse->sinkpad); gst_element_add_pad (GST_ELEMENT (wavpackparse), wavpackparse->sinkpad);
@ -738,6 +812,8 @@ gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
gst_pad_set_query_function (wvparse->srcpad, gst_pad_set_query_function (wvparse->srcpad,
GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query)); GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query));
gst_pad_set_query_type_function (wvparse->srcpad,
GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types));
gst_pad_set_event_function (wvparse->srcpad, gst_pad_set_event_function (wvparse->srcpad,
GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event)); GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event));
@ -752,6 +828,43 @@ gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
return TRUE; return TRUE;
} }
static GstFlowReturn
gst_wavpack_parse_push_buffer (GstWavpackParse * wvparse, GstBuffer * buf,
WavpackHeader * header)
{
wvparse->current_offset += header->ckSize + 8;
wvparse->segment.last_stop = header->block_index;
if (wvparse->need_newsegment) {
if (gst_wavpack_parse_send_newsegment (wvparse, FALSE))
wvparse->need_newsegment = FALSE;
}
/* send any queued events */
if (wvparse->queued_events) {
GList *l;
for (l = wvparse->queued_events; l != NULL; l = l->next) {
gst_pad_push_event (wvparse->srcpad, GST_EVENT (l->data));
}
g_list_free (wvparse->queued_events);
wvparse->queued_events = NULL;
}
GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (header->block_index,
GST_SECOND, wvparse->samplerate);
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (header->block_samples,
GST_SECOND, wvparse->samplerate);
GST_BUFFER_OFFSET (buf) = header->block_index;
gst_buffer_set_caps (buf, GST_PAD_CAPS (wvparse->srcpad));
GST_LOG_OBJECT (wvparse, "Pushing buffer with time %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
return gst_pad_push (wvparse->srcpad, buf);
}
static void static void
gst_wavpack_parse_loop (GstElement * element) gst_wavpack_parse_loop (GstElement * element)
{ {
@ -797,37 +910,7 @@ gst_wavpack_parse_loop (GstElement * element)
gst_wavpack_parse_index_append_entry (wavpackparse, gst_wavpack_parse_index_append_entry (wavpackparse,
wavpackparse->current_offset, header.block_index, header.block_samples); wavpackparse->current_offset, header.block_index, header.block_samples);
wavpackparse->current_offset += header.ckSize + 8; flow_ret = gst_wavpack_parse_push_buffer (wavpackparse, buf, &header);
wavpackparse->segment.last_stop = header.block_index;
if (wavpackparse->need_newsegment) {
if (gst_wavpack_parse_send_newsegment (wavpackparse, FALSE))
wavpackparse->need_newsegment = FALSE;
}
/* send any queued events */
if (wavpackparse->queued_events) {
GList *l;
for (l = wavpackparse->queued_events; l != NULL; l = l->next) {
gst_pad_push_event (wavpackparse->srcpad, GST_EVENT (l->data));
}
g_list_free (wavpackparse->queued_events);
wavpackparse->queued_events = NULL;
}
GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (header.block_index,
GST_SECOND, wavpackparse->samplerate);
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (header.block_samples,
GST_SECOND, wavpackparse->samplerate);
GST_BUFFER_OFFSET (buf) = header.block_index;
gst_buffer_set_caps (buf, GST_PAD_CAPS (wavpackparse->srcpad));
GST_LOG_OBJECT (wavpackparse, "Pushing buffer with time %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
flow_ret = gst_pad_push (wavpackparse->srcpad, buf);
if (flow_ret != GST_FLOW_OK) { if (flow_ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (wavpackparse, "Push failed, flow: %s", GST_DEBUG_OBJECT (wavpackparse, "Push failed, flow: %s",
gst_flow_get_name (flow_ret)); gst_flow_get_name (flow_ret));
@ -852,6 +935,61 @@ pause:
} }
} }
static GstFlowReturn
gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf)
{
GstWavpackParse *wvparse = GST_WAVPACK_PARSE (GST_PAD_PARENT (pad));
GstFlowReturn ret = GST_FLOW_OK;
WavpackHeader wph;
const guint8 *tmp_buf;
if (!wvparse->adapter) {
wvparse->adapter = gst_adapter_new ();
}
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
gst_adapter_clear (wvparse->adapter);
}
gst_adapter_push (wvparse->adapter, buf);
if (gst_adapter_available (wvparse->adapter) < sizeof (WavpackHeader))
return ret;
tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
/* FIXME: should check for wavpack marker here and re-sync if not */
while (gst_adapter_available (wvparse->adapter) >= wph.ckSize + 4 * 1 + 4) {
GstBuffer *outbuf =
gst_adapter_take_buffer (wvparse->adapter, wph.ckSize + 4 * 1 + 4);
if (!outbuf)
return GST_FLOW_ERROR;
if (wvparse->srcpad == NULL) {
if (!gst_wavpack_parse_create_src_pad (wvparse, outbuf, &wph)) {
GST_ELEMENT_ERROR (wvparse, STREAM, DECODE, (NULL), (NULL));
ret = GST_FLOW_ERROR;
break;
}
}
ret = gst_wavpack_parse_push_buffer (wvparse, outbuf, &wph);
if (ret != GST_FLOW_OK)
break;
if (gst_adapter_available (wvparse->adapter) >= sizeof (WavpackHeader)) {
tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
}
}
return ret;
}
static GstStateChangeReturn static GstStateChangeReturn
gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition) gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition)
{ {
@ -880,19 +1018,18 @@ gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition)
return ret; return ret;
} }
static gboolean static gboolean
gst_wavepack_parse_sink_activate (GstPad * sinkpad) gst_wavpack_parse_sink_activate (GstPad * sinkpad)
{ {
if (gst_pad_check_pull_range (sinkpad)) { if (gst_pad_check_pull_range (sinkpad)) {
return gst_pad_activate_pull (sinkpad, TRUE); return gst_pad_activate_pull (sinkpad, TRUE);
} else { } else {
return FALSE; return gst_pad_activate_push (sinkpad, TRUE);
} }
} }
static gboolean static gboolean
gst_wavepack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active) gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
{ {
gboolean result; gboolean result;

View file

@ -23,6 +23,7 @@
#define __GST_WAVPACK_PARSE_H__ #define __GST_WAVPACK_PARSE_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -67,6 +68,8 @@ struct _GstWavpackParse
GstSegment segment; /* the currently configured segment, in GstSegment segment; /* the currently configured segment, in
* samples/audio frames (DEFAULT format) */ * samples/audio frames (DEFAULT format) */
GstAdapter *adapter; /* when operating chain-based, otherwise NULL */
/* Array of GstWavpackParseIndexEntry structs, mapping known /* Array of GstWavpackParseIndexEntry structs, mapping known
* sample offsets to byte offsets. Is kept increasing without * sample offsets to byte offsets. Is kept increasing without
* gaps (ie. append only and consecutive entries must always * gaps (ie. append only and consecutive entries must always