1 /* GStreamer Wavpack plugin
2 * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
3 * Copyright (c) 2006 Edward Hervey <bilboed@gmail.com>
4 * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
6 * gstwavpackdec.c: raw Wavpack bitstream decoder
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 #include <gst/audio/audio.h>
30 #include <wavpack/wavpack.h>
31 #include "gstwavpackdec.h"
32 #include "gstwavpackcommon.h"
33 #include "gstwavpackstreamreader.h"
36 #define WAVPACK_DEC_MAX_ERRORS 16
38 GST_DEBUG_CATEGORY_STATIC (gst_wavpack_dec_debug);
39 #define GST_CAT_DEFAULT gst_wavpack_dec_debug
41 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
44 GST_STATIC_CAPS ("audio/x-wavpack, "
45 "width = (int) { 8, 16, 24, 32 }, "
46 "channels = (int) [ 1, 2 ], "
47 "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
51 static GstStaticPadTemplate wvc_sink_factory =
52 GST_STATIC_PAD_TEMPLATE ("wvcsink",
55 GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true")
59 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
62 GST_STATIC_CAPS ("audio/x-raw-int, "
63 "width = (int) { 8, 16, 24, 32 }, "
64 "depth = (int) { 8, 16, 24, 32 }, "
65 "channels = (int) [ 1, 2 ], "
66 "rate = (int) [ 6000, 192000 ], "
67 "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) true")
70 static GstFlowReturn gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buffer);
71 static gboolean gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event);
72 static void gst_wavpack_dec_finalize (GObject * object);
73 static GstStateChangeReturn gst_wavpack_dec_change_state (GstElement * element,
74 GstStateChange transition);
75 static gboolean gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event);
78 static GstPad *gst_wavpack_dec_request_new_pad (GstElement * element,
79 GstPadTemplate * templ, const gchar * name);
82 GST_BOILERPLATE (GstWavpackDec, gst_wavpack_dec, GstElement, GST_TYPE_ELEMENT);
85 static GstPadLinkReturn
86 gst_wavpack_dec_wvclink (GstPad * pad, GstPad * peer)
88 if (!gst_caps_is_fixed (GST_PAD_CAPS (peer)))
89 return GST_PAD_LINK_REFUSED;
91 return GST_PAD_LINK_OK;
96 gst_wavpack_dec_base_init (gpointer klass)
98 static const GstElementDetails plugin_details =
99 GST_ELEMENT_DETAILS ("WavePack audio decoder",
100 "Codec/Decoder/Audio",
101 "Decode Wavpack audio data",
102 "Arwed v. Merkatz <v.merkatz@gmx.net>, "
103 "Sebastian Dröge <slomo@circular-chaos.org>");
104 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
106 gst_element_class_add_pad_template (element_class,
107 gst_static_pad_template_get (&src_factory));
108 gst_element_class_add_pad_template (element_class,
109 gst_static_pad_template_get (&sink_factory));
111 gst_element_class_add_pad_template (element_class,
112 gst_static_pad_template_get (&wvc_sink_factory));
114 gst_element_class_set_details (element_class, &plugin_details);
118 gst_wavpack_dec_class_init (GstWavpackDecClass * klass)
120 GObjectClass *gobject_class = (GObjectClass *) klass;
121 GstElementClass *gstelement_class = (GstElementClass *) klass;
123 gstelement_class->change_state =
124 GST_DEBUG_FUNCPTR (gst_wavpack_dec_change_state);
126 gstelement_class->request_new_pad =
127 GST_DEBUG_FUNCPTR (gst_wavpack_dec_request_new_pad);
129 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_wavpack_dec_finalize);
133 gst_wavpack_dec_init (GstWavpackDec * wavpackdec, GstWavpackDecClass * gklass)
135 GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavpackdec);
137 wavpackdec->sinkpad =
138 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
140 gst_pad_set_chain_function (wavpackdec->sinkpad,
141 GST_DEBUG_FUNCPTR (gst_wavpack_dec_chain));
142 gst_pad_set_event_function (wavpackdec->sinkpad,
143 GST_DEBUG_FUNCPTR (gst_wavpack_dec_sink_event));
144 gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->sinkpad);
147 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
149 gst_pad_use_fixed_caps (wavpackdec->srcpad);
150 gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->srcpad);
152 wavpackdec->context = NULL;
153 wavpackdec->stream_reader = gst_wavpack_stream_reader_new ();
155 wavpackdec->wv_id.buffer = NULL;
156 wavpackdec->wv_id.position = wavpackdec->wv_id.length = 0;
159 wavpackdec->wvc_id.buffer = NULL;
160 wavpackdec->wvc_id.position = wavpackdec->wvc_id.length = 0;
161 wavpackdec->wvcsinkpad = NULL;
164 wavpackdec->error_count = 0;
167 wavpackdec->channels = 0;
168 wavpackdec->sample_rate = 0;
169 wavpackdec->width = 0;
171 gst_segment_init (&wavpackdec->segment, GST_FORMAT_UNDEFINED);
175 gst_wavpack_dec_finalize (GObject * object)
177 GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (object);
179 g_free (wavpackdec->stream_reader);
180 wavpackdec->stream_reader = NULL;
182 G_OBJECT_CLASS (parent_class)->finalize (object);
186 gst_wavpack_dec_format_samples (GstWavpackDec * wavpackdec, guint8 * dst,
187 int32_t * samples, guint num_samples)
192 switch (wavpackdec->width) {
194 for (i = 0; i < num_samples * wavpackdec->channels; ++i)
195 *dst++ = (guint8) (*samples++);
198 for (i = 0; i < num_samples * wavpackdec->channels; ++i) {
199 *dst++ = (guint8) (temp = *samples++);
200 *dst++ = (guint8) (temp >> 8);
204 for (i = 0; i < num_samples * wavpackdec->channels; ++i) {
205 *dst++ = (guint8) (temp = *samples++);
206 *dst++ = (guint8) (temp >> 8);
207 *dst++ = (guint8) (temp >> 16);
211 for (i = 0; i < num_samples * wavpackdec->channels; ++i) {
212 *dst++ = (guint8) (temp = *samples++);
213 *dst++ = (guint8) (temp >> 8);
214 *dst++ = (guint8) (temp >> 16);
215 *dst++ = (guint8) (temp >> 24);
224 gst_wavpack_dec_clip_outgoing_buffer (GstWavpackDec * wavpackdec,
227 gint64 start, stop, cstart, cstop, diff;
229 if (wavpackdec->segment.format != GST_FORMAT_TIME)
232 start = GST_BUFFER_TIMESTAMP (buf);
233 stop = start + GST_BUFFER_DURATION (buf);
235 if (gst_segment_clip (&wavpackdec->segment, GST_FORMAT_TIME,
236 start, stop, &cstart, &cstop)) {
238 diff = cstart - start;
240 GST_BUFFER_TIMESTAMP (buf) = cstart;
241 GST_BUFFER_DURATION (buf) -= diff;
243 diff = ((wavpackdec->width + 7) >> 3) * wavpackdec->channels
244 * GST_CLOCK_TIME_TO_FRAMES (diff, wavpackdec->sample_rate);
245 GST_BUFFER_DATA (buf) += diff;
246 GST_BUFFER_SIZE (buf) -= diff;
251 GST_BUFFER_DURATION (buf) -= diff;
253 diff = ((wavpackdec->width + 7) >> 3) * wavpackdec->channels
254 * GST_CLOCK_TIME_TO_FRAMES (diff, wavpackdec->sample_rate);
255 GST_BUFFER_SIZE (buf) -= diff;
258 GST_DEBUG_OBJECT (wavpackdec, "buffer is outside configured segment");
266 gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
269 GstWavpackDec *wavpackdec;
271 GstBuffer *cbuf = NULL;
272 GstFlowReturn ret = GST_FLOW_OK;
275 int32_t unpacked_sample_count;
277 wavpackdec = GST_WAVPACK_DEC (GST_PAD_PARENT (pad));
279 /* we only accept framed input with complete chunks */
280 g_assert (GST_BUFFER_SIZE (buf) >= sizeof (WavpackHeader));
281 gst_wavpack_read_header (&wph, GST_BUFFER_DATA (buf));
282 g_assert (GST_BUFFER_SIZE (buf) ==
283 wph.ckSize + 4 * sizeof (char) + sizeof (uint32_t));
285 wavpackdec->wv_id.buffer = GST_BUFFER_DATA (buf);
286 wavpackdec->wv_id.length = GST_BUFFER_SIZE (buf);
287 wavpackdec->wv_id.position = 0;
290 /* check whether the correction pad is linked and we can get
291 * the correction chunk that corresponds to our current data */
292 if (gst_pad_is_linked (wavpackdec->wvcsinkpad)) {
293 if (GST_FLOW_OK != gst_pad_pull_range (wavpackdec->wvcsinkpad,
294 GST_BUFFER_OFFSET (buf), -1, &cbuf)) {
297 /* this won't work (tpm) */
298 if (!(GST_BUFFER_TIMESTAMP (cbuf) == GST_BUFFER_TIMESTAMP (buf)) ||
299 !(GST_BUFFER_DURATION (cbuf) == GST_BUFFER_DURATION (buf)) ||
300 !(GST_BUFFER_OFFSET (cbuf) == GST_BUFFER_OFFSET (buf)) ||
301 !(GST_BUFFER_OFFSET_END (cbuf) == GST_BUFFER_OFFSET (buf))) {
302 gst_buffer_unref (cbuf);
305 wavpackdec->wvc_id.buffer = GST_BUFFER_DATA (cbuf);
306 wavpackdec->wvc_id.length = GST_BUFFER_SIZE (cbuf);
307 wavpackdec->wvc_id.position = 0;
313 /* create a new wavpack context if there is none yet but if there
314 * was already one (i.e. caps were set on the srcpad) check whether
315 * the new one has the same caps */
316 if (!wavpackdec->context) {
320 wavpackdec->context =
321 WavpackOpenFileInputEx (wavpackdec->stream_reader, &wavpackdec->wv_id,
322 (cbuf) ? &wavpackdec->wvc_id : NULL, error_msg, OPEN_STREAMING, 0);
325 wavpackdec->context = WavpackOpenFileInputEx (wavpackdec->stream_reader,
326 &wavpackdec->wv_id, NULL, error_msg, OPEN_STREAMING, 0);
328 if (!wavpackdec->context) {
329 wavpackdec->error_count++;
330 GST_ELEMENT_WARNING (wavpackdec, LIBRARY, INIT, (NULL),
331 ("Couldn't open buffer for decoding: %s", error_msg));
332 if (wavpackdec->error_count <= WAVPACK_DEC_MAX_ERRORS) {
335 ret = GST_FLOW_ERROR;
337 gst_buffer_unref (buf);
339 gst_buffer_unref (cbuf);
344 if (GST_PAD_CAPS (wavpackdec->srcpad)) {
345 if ((wavpackdec->sample_rate !=
346 WavpackGetSampleRate (wavpackdec->context))
347 || (wavpackdec->channels !=
348 WavpackGetNumChannels (wavpackdec->context))
349 || (wavpackdec->width !=
350 WavpackGetBitsPerSample (wavpackdec->context))) {
351 gst_buffer_unref (buf);
353 gst_buffer_unref (cbuf);
356 /* FIXME: use the right error */
357 GST_ELEMENT_ERROR (wavpackdec, LIBRARY, INIT, (NULL),
358 ("Got Wavpack chunk with changed format settings!"));
359 return GST_FLOW_ERROR;
363 wavpackdec->error_count = 0;
365 if (!GST_PAD_CAPS (wavpackdec->srcpad)) {
368 g_assert (wavpackdec->context);
370 wavpackdec->sample_rate = WavpackGetSampleRate (wavpackdec->context);
371 wavpackdec->channels = WavpackGetNumChannels (wavpackdec->context);
372 wavpackdec->width = WavpackGetBitsPerSample (wavpackdec->context);
373 caps = gst_caps_new_simple ("audio/x-raw-int",
374 "rate", G_TYPE_INT, wavpackdec->sample_rate,
375 "channels", G_TYPE_INT, wavpackdec->channels,
376 "depth", G_TYPE_INT, wavpackdec->width,
377 "width", G_TYPE_INT, wavpackdec->width,
378 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
379 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
381 if (!gst_pad_set_caps (wavpackdec->srcpad, caps)) {
382 gst_caps_unref (caps);
383 WavpackCloseFile (wavpackdec->context);
384 wavpackdec->context = NULL;
385 gst_buffer_unref (buf);
387 gst_buffer_unref (cbuf);
389 /* FIXME: use the right error */
390 GST_ELEMENT_ERROR (wavpackdec, LIBRARY, INIT, (NULL),
391 ("Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps));
392 return GST_FLOW_ERROR;
394 gst_caps_unref (caps);
395 gst_pad_use_fixed_caps (wavpackdec->srcpad);
398 g_assert (wavpackdec->context);
400 (int32_t *) g_malloc (sizeof (int32_t) * wph.block_samples *
401 wavpackdec->channels);
402 unpacked_sample_count =
403 WavpackUnpackSamples (wavpackdec->context, unpack_buf, wph.block_samples);
404 g_assert (unpacked_sample_count == wph.block_samples);
407 gst_pad_alloc_buffer_and_set_caps (wavpackdec->srcpad,
408 GST_BUFFER_OFFSET (buf),
409 wph.block_samples * ((wavpackdec->width +
410 7) >> 3) * wavpackdec->channels,
411 GST_PAD_CAPS (wavpackdec->srcpad), &outbuf);
413 if (GST_FLOW_IS_FATAL (ret)) {
414 WavpackCloseFile (wavpackdec->context);
415 wavpackdec->context = NULL;
417 gst_buffer_unref (buf);
419 gst_buffer_unref (cbuf);
422 } else if (ret != GST_FLOW_OK) {
424 gst_buffer_unref (buf);
426 gst_buffer_unref (cbuf);
431 gst_wavpack_dec_format_samples (wavpackdec, GST_BUFFER_DATA (outbuf),
432 unpack_buf, wph.block_samples);
434 gst_buffer_stamp (outbuf, buf);
435 gst_buffer_unref (buf);
437 gst_buffer_unref (cbuf);
440 if (gst_wavpack_dec_clip_outgoing_buffer (wavpackdec, outbuf)) {
441 GST_LOG_OBJECT (wavpackdec, "pushing buffer with time %" GST_TIME_FORMAT,
442 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
443 ret = gst_pad_push (wavpackdec->srcpad, outbuf);
444 if (ret != GST_FLOW_OK) {
445 GST_DEBUG_OBJECT (wavpackdec, "pad_push: %s", gst_flow_get_name (ret));
448 gst_buffer_unref (outbuf);
455 gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event)
457 GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
459 GST_LOG_OBJECT (wavpackdec, "Received %s event", GST_EVENT_TYPE_NAME (event));
460 switch (GST_EVENT_TYPE (event)) {
461 case GST_EVENT_NEWSEGMENT:{
464 gint64 start, end, base;
467 gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start,
469 if (fmt == GST_FORMAT_TIME) {
470 GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
471 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
472 GST_TIME_ARGS (end));
473 gst_segment_set_newsegment (&wavpackdec->segment, is_update, rate, fmt,
476 gst_segment_init (&wavpackdec->segment, GST_FORMAT_UNDEFINED);
484 gst_object_unref (wavpackdec);
485 return gst_pad_event_default (pad, event);
488 static GstStateChangeReturn
489 gst_wavpack_dec_change_state (GstElement * element, GstStateChange transition)
491 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
492 GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (element);
494 switch (transition) {
495 case GST_STATE_CHANGE_NULL_TO_READY:
497 case GST_STATE_CHANGE_READY_TO_PAUSED:
498 gst_segment_init (&wavpackdec->segment, GST_FORMAT_UNDEFINED);
500 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
506 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
508 switch (transition) {
509 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
511 case GST_STATE_CHANGE_PAUSED_TO_READY:
512 if (wavpackdec->context) {
513 WavpackCloseFile (wavpackdec->context);
514 wavpackdec->context = NULL;
516 wavpackdec->wv_id.buffer = NULL;
517 wavpackdec->wv_id.position = 0;
518 wavpackdec->wv_id.length = 0;
520 wavpackdec->wvc_id.buffer = NULL;
521 wavpackdec->wvc_id.position = 0;
522 wavpackdec->wvc_id.length = 0;
523 wavpackdec->error_count = 0;
524 wavpackdec->wvcsinkpad = NULL;
526 wavpackdec->channels = 0;
527 wavpackdec->sample_rate = 0;
528 wavpackdec->width = 0;
530 case GST_STATE_CHANGE_READY_TO_NULL:
541 gst_wavpack_dec_request_new_pad (GstElement * element,
542 GstPadTemplate * templ, const gchar * name)
544 GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (element);
547 if (wavpackdec->wvcsinkpad == NULL) {
548 wavpackdec->wvcsinkpad = gst_pad_new_from_template (template, name);
549 gst_pad_set_link_function (wavpackdec->wvcsinkpad, gst_wavpack_dec_wvclink);
550 gst_pad_use_fixed_caps (wavpackdec->wvcsinkpad);
551 gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->wvcsinkpad);
552 gst_element_no_more_pads (GST_ELEMENT (wavpackdec));
562 gst_wavpack_dec_plugin_init (GstPlugin * plugin)
564 if (!gst_element_register (plugin, "wavpackdec",
565 GST_RANK_PRIMARY, GST_TYPE_WAVPACK_DEC))
567 GST_DEBUG_CATEGORY_INIT (gst_wavpack_dec_debug, "wavpackdec", 0,