1 /* GStreamer Wavpack plugin
2 * (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
4 * gstwavpackdec.c: raw Wavpack bitstream decoder
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
27 #include <wavpack/wavpack.h>
28 #include "gstwavpackdec.h"
29 #include "gstwavpackcommon.h"
31 GST_DEBUG_CATEGORY_STATIC (gst_wavpack_dec_debug);
32 #define GST_CAT_DEFAULT gst_wavpack_dec_debug
34 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
37 GST_STATIC_CAPS ("audio/x-wavpack, "
38 "width = (int) { 8, 16, 24, 32 }, "
39 "channels = (int) { 1, 2 }, "
40 "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
43 static GstStaticPadTemplate wvc_sink_factory =
44 GST_STATIC_PAD_TEMPLATE ("wvcsink",
47 GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true")
50 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
53 GST_STATIC_CAPS ("audio/x-raw-int, "
54 "width = (int) { 8, 16, 24, 32 }, "
55 "depth = (int) { 8, 16, 24, 32 }, "
56 "channels = (int) { 1, 2 }, "
57 "rate = (int) [ 6000, 192000 ], "
58 "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) true")
62 "channels = (int) { 1, 2 }, "
63 "rate = (int) [ 6000, 192000 ], " "endianness = (int) LITTLE_ENDIAN"
67 static GstFlowReturn gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buffer);
68 static gboolean gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event);
70 GST_BOILERPLATE (GstWavpackDec, gst_wavpack_dec, GstElement, GST_TYPE_ELEMENT)
72 static gboolean gst_wavpack_dec_setcaps (GstPad * pad, GstCaps * caps)
74 GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
75 GstStructure *structure;
77 gint bits, rate, channels;
79 structure = gst_caps_get_structure (caps, 0);
80 if (!gst_structure_get_int (structure, "rate", &rate) ||
81 !gst_structure_get_int (structure, "channels", &channels) ||
82 !gst_structure_get_int (structure, "width", &bits)) {
86 wavpackdec->samplerate = rate;
87 wavpackdec->channels = channels;
88 wavpackdec->width = bits;
90 /* 32-bit output seems to be in fact 32 bit int (e.g. Prod_Girls.wv) */
91 /* if (bits != 32) { */
92 srccaps = gst_caps_new_simple ("audio/x-raw-int",
93 "rate", G_TYPE_INT, wavpackdec->samplerate,
94 "channels", G_TYPE_INT, wavpackdec->channels,
95 "depth", G_TYPE_INT, bits,
96 "width", G_TYPE_INT, bits,
97 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
98 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
101 srccaps = gst_caps_new_simple ("audio/x-raw-float",
102 "rate", G_TYPE_INT, wavpackdec->samplerate,
103 "channels", G_TYPE_INT, wavpackdec->channels,
104 "width", G_TYPE_INT, 32,
105 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
108 /* gst_pad_set_caps (wavpackdec->sinkpad, caps); */
110 gst_pad_set_caps (wavpackdec->srcpad, srccaps);
111 gst_pad_use_fixed_caps (wavpackdec->srcpad);
117 static GstPadLinkReturn
118 gst_wavpack_dec_wvclink (GstPad * pad, GstPad * peer)
120 if (!gst_caps_is_fixed (GST_PAD_CAPS (peer)))
121 return GST_PAD_LINK_REFUSED;
123 return GST_PAD_LINK_OK;
128 gst_wavpack_dec_base_init (gpointer klass)
130 static const GstElementDetails plugin_details =
131 GST_ELEMENT_DETAILS ("WavePack audio decoder",
132 "Codec/Decoder/Audio",
133 "Decode Wavpack audio data",
134 "Arwed v. Merkatz <v.merkatz@gmx.net>");
135 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
137 gst_element_class_add_pad_template (element_class,
138 gst_static_pad_template_get (&src_factory));
139 gst_element_class_add_pad_template (element_class,
140 gst_static_pad_template_get (&sink_factory));
141 gst_element_class_add_pad_template (element_class,
142 gst_static_pad_template_get (&wvc_sink_factory));
143 gst_element_class_set_details (element_class, &plugin_details);
147 gst_wavpack_dec_dispose (GObject * object)
149 GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (object);
151 g_free (wavpackdec->decodebuf);
152 wavpackdec->decodebuf = NULL;
154 /* FIXME: what about wavpackdec->stream and wavpackdec->context? (tpm) */
156 G_OBJECT_CLASS (parent_class)->dispose (object);
160 gst_wavpack_dec_class_init (GstWavpackDecClass * klass)
162 GObjectClass *gobject_class;
163 GstElementClass *gstelement_class;
165 gobject_class = (GObjectClass *) klass;
166 gstelement_class = (GstElementClass *) klass;
168 gobject_class->dispose = gst_wavpack_dec_dispose;
172 gst_wavpack_dec_src_query (GstPad * pad, GstQuery * query)
174 return gst_pad_query_default (pad, query);
178 gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event)
182 dec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
184 GST_LOG_OBJECT (dec, "Received %s event", GST_EVENT_TYPE_NAME (event));
185 switch (GST_EVENT_TYPE (event)) {
186 case GST_EVENT_NEWSEGMENT:{
187 /* TODO: save current segment so we can do clipping, for now
188 * we'll just leave the clipping to the audio sink */
195 gst_object_unref (dec);
197 return gst_pad_event_default (pad, event);
201 gst_wavpack_dec_init (GstWavpackDec * wavpackdec, GstWavpackDecClass * gklass)
203 GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavpackdec);
205 wavpackdec->sinkpad =
206 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
208 gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->sinkpad);
210 gst_pad_set_chain_function (wavpackdec->sinkpad,
211 GST_DEBUG_FUNCPTR (gst_wavpack_dec_chain));
212 gst_pad_set_setcaps_function (wavpackdec->sinkpad,
213 GST_DEBUG_FUNCPTR (gst_wavpack_dec_setcaps));
214 gst_pad_set_event_function (wavpackdec->sinkpad,
215 GST_DEBUG_FUNCPTR (gst_wavpack_dec_sink_event));
218 wavpackdec->wvcsinkpad =
219 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
220 "wvcsink"), "wvcsink");
221 gst_pad_set_link_function (wavpackdec->wvcsinkpad, gst_wavpack_dec_wvclink);
222 gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->wvcsinkpad);
227 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
229 gst_pad_use_fixed_caps (wavpackdec->srcpad);
231 gst_pad_set_query_function (wavpackdec->srcpad,
232 GST_DEBUG_FUNCPTR (gst_wavpack_dec_src_query));
234 gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->srcpad);
236 wavpackdec->decodebuf = NULL;
237 wavpackdec->decodebuf_size = 0;
238 wavpackdec->stream = (WavpackStream *) g_malloc0 (sizeof (WavpackStream));
239 wavpackdec->context = (WavpackContext *) g_malloc0 (sizeof (WavpackContext));
243 gst_wavpack_dec_setup_context (GstWavpackDec * wavpackdec, guchar * data,
246 WavpackContext *context = wavpackdec->context;
247 WavpackStream *stream = wavpackdec->stream;
250 memset (context, 0, sizeof (context));
252 context->open_flags = 0;
253 context->current_stream = 0;
254 context->num_streams = 1;
256 memset (stream, 0, sizeof (stream));
257 context->streams[0] = stream;
259 gst_wavpack_read_header (&stream->wphdr, data);
260 stream->blockbuff = data;
263 context->wvc_flag = TRUE;
264 gst_wavpack_read_header (&stream->wphdr, cdata);
265 stream->block2buff = cdata;
267 context->wvc_flag = FALSE;
271 stream->wphdr.block_samples * wavpackdec->channels * sizeof (int32_t);
272 if (wavpackdec->decodebuf_size < buffer_size) {
273 wavpackdec->decodebuf =
274 (int32_t *) g_realloc (wavpackdec->decodebuf, buffer_size);
275 wavpackdec->decodebuf_size = buffer_size;
278 unpack_init (context);
282 gst_wavpack_dec_format_samples (GstWavpackDec * wavpackdec, int32_t * samples,
291 gst_buffer_new_and_alloc (num_samples * wavpackdec->width / 8 *
292 wavpackdec->channels);
294 dst = (guint8 *) GST_BUFFER_DATA (buf);
296 switch (wavpackdec->width) {
298 for (i = 0; i < num_samples * wavpackdec->channels; ++i)
299 *dst++ = *samples++ + 128;
302 for (i = 0; i < num_samples * wavpackdec->channels; ++i) {
303 *dst++ = (guint8) (temp = *samples++);
304 *dst++ = (guint8) (temp >> 8);
308 for (i = 0; i < num_samples * wavpackdec->channels; ++i) {
309 *dst++ = (guint8) (temp = *samples++);
310 *dst++ = (guint8) (temp >> 8);
311 *dst++ = (guint8) (temp >> 16);
315 for (i = 0; i < num_samples * wavpackdec->channels; ++i) {
316 *dst++ = (guint8) (temp = *samples++);
317 *dst++ = (guint8) (temp >> 8);
318 *dst++ = (guint8) (temp >> 16);
319 *dst++ = (guint8) (temp >> 24);
330 gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
333 GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
334 GstBuffer *outbuf, *cbuf = NULL;
335 GstFlowReturn ret = GST_FLOW_OK;
338 if (gst_pad_is_linked (wavpackdec->wvcsinkpad)) {
339 if (GST_FLOW_OK != gst_pad_pull_range (wavpackdec->wvcsinkpad,
340 wavpackdec->wvcflushed_bytes, -1, &cbuf)) {
343 wavpackdec->wvcflushed_bytes += GST_BUFFER_SIZE (cbuf);
349 gst_wavpack_dec_setup_context (wavpackdec, GST_BUFFER_DATA (buf),
350 cbuf ? GST_BUFFER_DATA (cbuf) : NULL);
351 unpack_samples (wavpackdec->context, wavpackdec->decodebuf,
352 wavpackdec->context->streams[0]->wphdr.block_samples);
354 gst_wavpack_dec_format_samples (wavpackdec, wavpackdec->decodebuf,
355 wavpackdec->context->streams[0]->wphdr.block_samples);
357 gst_buffer_stamp (outbuf, buf);
359 gst_buffer_unref (buf);
361 gst_buffer_unref (cbuf);
364 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (wavpackdec->srcpad));
366 GST_LOG_OBJECT (wavpackdec, "pushing buffer with time %" GST_TIME_FORMAT,
367 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
369 ret = gst_pad_push (wavpackdec->srcpad, outbuf);
370 if (ret != GST_FLOW_OK) {
371 GST_DEBUG_OBJECT (wavpackdec, "pad_push: %s", gst_flow_get_name (ret));
378 gst_wavpack_dec_plugin_init (GstPlugin * plugin)
380 if (!gst_element_register (plugin, "wavpackdec",
381 GST_RANK_PRIMARY, GST_TYPE_WAVPACK_DEC))
384 GST_DEBUG_CATEGORY_INIT (gst_wavpack_dec_debug, "wavpackdec", 0,