configure.ac: Check for wavpack version and define WAVPACK_OLD_API if necessary.
[platform/upstream/gst-plugins-good.git] / ext / wavpack / gstwavpackdec.c
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>
5  *
6  * gstwavpackdec.c: raw Wavpack bitstream decoder
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #include <gst/gst.h>
25 #include <gst/audio/audio.h>
26
27 #include <math.h>
28 #include <string.h>
29
30 #include <wavpack/wavpack.h>
31 #include "gstwavpackdec.h"
32 #include "gstwavpackcommon.h"
33 #include "gstwavpackstreamreader.h"
34
35
36 #define WAVPACK_DEC_MAX_ERRORS 16
37
38 GST_DEBUG_CATEGORY_STATIC (gst_wavpack_dec_debug);
39 #define GST_CAT_DEFAULT gst_wavpack_dec_debug
40
41 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
42     GST_PAD_SINK,
43     GST_PAD_ALWAYS,
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")
48     );
49
50 #if 0
51 static GstStaticPadTemplate wvc_sink_factory =
52 GST_STATIC_PAD_TEMPLATE ("wvcsink",
53     GST_PAD_SINK,
54     GST_PAD_REQUEST,
55     GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true")
56     );
57 #endif
58
59 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
60     GST_PAD_SRC,
61     GST_PAD_ALWAYS,
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")
68     );
69
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);
76
77 #if 0
78 static GstPad *gst_wavpack_dec_request_new_pad (GstElement * element,
79     GstPadTemplate * templ, const gchar * name);
80 #endif
81
82 GST_BOILERPLATE (GstWavpackDec, gst_wavpack_dec, GstElement, GST_TYPE_ELEMENT);
83
84 #if 0
85 static GstPadLinkReturn
86 gst_wavpack_dec_wvclink (GstPad * pad, GstPad * peer)
87 {
88   if (!gst_caps_is_fixed (GST_PAD_CAPS (peer)))
89     return GST_PAD_LINK_REFUSED;
90
91   return GST_PAD_LINK_OK;
92 }
93 #endif
94
95 static void
96 gst_wavpack_dec_base_init (gpointer klass)
97 {
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);
105
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));
110 #if 0
111   gst_element_class_add_pad_template (element_class,
112       gst_static_pad_template_get (&wvc_sink_factory));
113 #endif
114   gst_element_class_set_details (element_class, &plugin_details);
115 }
116
117 static void
118 gst_wavpack_dec_class_init (GstWavpackDecClass * klass)
119 {
120   GObjectClass *gobject_class = (GObjectClass *) klass;
121   GstElementClass *gstelement_class = (GstElementClass *) klass;
122
123   gstelement_class->change_state =
124       GST_DEBUG_FUNCPTR (gst_wavpack_dec_change_state);
125 #if 0
126   gstelement_class->request_new_pad =
127       GST_DEBUG_FUNCPTR (gst_wavpack_dec_request_new_pad);
128 #endif
129   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_wavpack_dec_finalize);
130 }
131
132 static void
133 gst_wavpack_dec_init (GstWavpackDec * wavpackdec, GstWavpackDecClass * gklass)
134 {
135   GstElementClass *klass = GST_ELEMENT_GET_CLASS (wavpackdec);
136
137   wavpackdec->sinkpad =
138       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
139           "sink"), "sink");
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);
145
146   wavpackdec->srcpad =
147       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
148           "src"), "src");
149   gst_pad_use_fixed_caps (wavpackdec->srcpad);
150   gst_element_add_pad (GST_ELEMENT (wavpackdec), wavpackdec->srcpad);
151
152   wavpackdec->context = NULL;
153   wavpackdec->stream_reader = gst_wavpack_stream_reader_new ();
154
155   wavpackdec->wv_id.buffer = NULL;
156   wavpackdec->wv_id.position = wavpackdec->wv_id.length = 0;
157
158 /*
159   wavpackdec->wvc_id.buffer = NULL;
160   wavpackdec->wvc_id.position = wavpackdec->wvc_id.length = 0;
161   wavpackdec->wvcsinkpad = NULL;
162 */
163
164   wavpackdec->error_count = 0;
165
166
167   wavpackdec->channels = 0;
168   wavpackdec->sample_rate = 0;
169   wavpackdec->width = 0;
170
171   gst_segment_init (&wavpackdec->segment, GST_FORMAT_UNDEFINED);
172 }
173
174 static void
175 gst_wavpack_dec_finalize (GObject * object)
176 {
177   GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (object);
178
179   g_free (wavpackdec->stream_reader);
180   wavpackdec->stream_reader = NULL;
181
182   G_OBJECT_CLASS (parent_class)->finalize (object);
183 }
184
185 static void
186 gst_wavpack_dec_format_samples (GstWavpackDec * wavpackdec, guint8 * dst,
187     int32_t * samples, guint num_samples)
188 {
189   gint i;
190   int32_t temp;
191
192   switch (wavpackdec->width) {
193     case 8:
194       for (i = 0; i < num_samples * wavpackdec->channels; ++i)
195         *dst++ = (guint8) (*samples++);
196       break;
197     case 16:
198       for (i = 0; i < num_samples * wavpackdec->channels; ++i) {
199         *dst++ = (guint8) (temp = *samples++);
200         *dst++ = (guint8) (temp >> 8);
201       }
202       break;
203     case 24:
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);
208       }
209       break;
210     case 32:
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);
216       }
217       break;
218     default:
219       break;
220   }
221 }
222
223 static gboolean
224 gst_wavpack_dec_clip_outgoing_buffer (GstWavpackDec * wavpackdec,
225     GstBuffer * buf)
226 {
227   gint64 start, stop, cstart, cstop, diff;
228
229   if (wavpackdec->segment.format != GST_FORMAT_TIME)
230     return TRUE;
231
232   start = GST_BUFFER_TIMESTAMP (buf);
233   stop = start + GST_BUFFER_DURATION (buf);
234
235   if (gst_segment_clip (&wavpackdec->segment, GST_FORMAT_TIME,
236           start, stop, &cstart, &cstop)) {
237
238     diff = cstart - start;
239     if (diff > 0) {
240       GST_BUFFER_TIMESTAMP (buf) = cstart;
241       GST_BUFFER_DURATION (buf) -= diff;
242
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;
247     }
248
249     diff = cstop - stop;
250     if (diff > 0) {
251       GST_BUFFER_DURATION (buf) -= diff;
252
253       diff = ((wavpackdec->width + 7) >> 3) * wavpackdec->channels
254           * GST_CLOCK_TIME_TO_FRAMES (diff, wavpackdec->sample_rate);
255       GST_BUFFER_SIZE (buf) -= diff;
256     }
257   } else {
258     GST_DEBUG_OBJECT (wavpackdec, "buffer is outside configured segment");
259     return FALSE;
260   }
261
262   return TRUE;
263 }
264
265 static GstFlowReturn
266 gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
267 {
268
269   GstWavpackDec *wavpackdec;
270   GstBuffer *outbuf;
271   GstBuffer *cbuf = NULL;
272   GstFlowReturn ret = GST_FLOW_OK;
273   WavpackHeader wph;
274   int32_t *unpack_buf;
275   int32_t unpacked_sample_count;
276
277   wavpackdec = GST_WAVPACK_DEC (GST_PAD_PARENT (pad));
278
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));
284
285   wavpackdec->wv_id.buffer = GST_BUFFER_DATA (buf);
286   wavpackdec->wv_id.length = GST_BUFFER_SIZE (buf);
287   wavpackdec->wv_id.position = 0;
288
289 #if 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)) {
295       cbuf = NULL;
296     } else {
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);
303         cbuf = NULL;
304       } else {
305         wavpackdec->wvc_id.buffer = GST_BUFFER_DATA (cbuf);
306         wavpackdec->wvc_id.length = GST_BUFFER_SIZE (cbuf);
307         wavpackdec->wvc_id.position = 0;
308       }
309     }
310   }
311 #endif
312
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) {
317     gchar error_msg[80];
318
319 /*
320     wavpackdec->context =
321         WavpackOpenFileInputEx (wavpackdec->stream_reader, &wavpackdec->wv_id,
322         (cbuf) ? &wavpackdec->wvc_id : NULL, error_msg, OPEN_STREAMING, 0);
323 */
324
325     wavpackdec->context = WavpackOpenFileInputEx (wavpackdec->stream_reader,
326         &wavpackdec->wv_id, NULL, error_msg, OPEN_STREAMING, 0);
327
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) {
333         ret = GST_FLOW_OK;
334       } else {
335         ret = GST_FLOW_ERROR;
336       }
337       gst_buffer_unref (buf);
338       if (cbuf) {
339         gst_buffer_unref (cbuf);
340       }
341       return ret;
342     }
343
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);
352         if (cbuf) {
353           gst_buffer_unref (cbuf);
354         }
355
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;
360       }
361     }
362   }
363   wavpackdec->error_count = 0;
364
365   if (!GST_PAD_CAPS (wavpackdec->srcpad)) {
366     GstCaps *caps;
367
368     g_assert (wavpackdec->context);
369
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);
380
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);
386       if (cbuf) {
387         gst_buffer_unref (cbuf);
388       }
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;
393     }
394     gst_caps_unref (caps);
395     gst_pad_use_fixed_caps (wavpackdec->srcpad);
396   }
397
398   g_assert (wavpackdec->context);
399   unpack_buf =
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);
405
406   ret =
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);
412
413   if (GST_FLOW_IS_FATAL (ret)) {
414     WavpackCloseFile (wavpackdec->context);
415     wavpackdec->context = NULL;
416     g_free (unpack_buf);
417     gst_buffer_unref (buf);
418     if (cbuf) {
419       gst_buffer_unref (cbuf);
420     }
421     return ret;
422   } else if (ret != GST_FLOW_OK) {
423     g_free (unpack_buf);
424     gst_buffer_unref (buf);
425     if (cbuf) {
426       gst_buffer_unref (cbuf);
427     }
428     return ret;
429   }
430
431   gst_wavpack_dec_format_samples (wavpackdec, GST_BUFFER_DATA (outbuf),
432       unpack_buf, wph.block_samples);
433   g_free (unpack_buf);
434   gst_buffer_stamp (outbuf, buf);
435   gst_buffer_unref (buf);
436   if (cbuf) {
437     gst_buffer_unref (cbuf);
438   }
439
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));
446     }
447   } else {
448     gst_buffer_unref (outbuf);
449   }
450
451   return ret;
452 }
453
454 static gboolean
455 gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event)
456 {
457   GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
458
459   GST_LOG_OBJECT (wavpackdec, "Received %s event", GST_EVENT_TYPE_NAME (event));
460   switch (GST_EVENT_TYPE (event)) {
461     case GST_EVENT_NEWSEGMENT:{
462       GstFormat fmt;
463       gboolean is_update;
464       gint64 start, end, base;
465       gdouble rate;
466
467       gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start,
468           &end, &base);
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,
474             start, end, base);
475       } else {
476         gst_segment_init (&wavpackdec->segment, GST_FORMAT_UNDEFINED);
477       }
478       break;
479     }
480     default:
481       break;
482   }
483
484   gst_object_unref (wavpackdec);
485   return gst_pad_event_default (pad, event);
486 }
487
488 static GstStateChangeReturn
489 gst_wavpack_dec_change_state (GstElement * element, GstStateChange transition)
490 {
491   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
492   GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (element);
493
494   switch (transition) {
495     case GST_STATE_CHANGE_NULL_TO_READY:
496       break;
497     case GST_STATE_CHANGE_READY_TO_PAUSED:
498       gst_segment_init (&wavpackdec->segment, GST_FORMAT_UNDEFINED);
499       break;
500     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
501       break;
502     default:
503       break;
504   }
505
506   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
507
508   switch (transition) {
509     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
510       break;
511     case GST_STATE_CHANGE_PAUSED_TO_READY:
512       if (wavpackdec->context) {
513         WavpackCloseFile (wavpackdec->context);
514         wavpackdec->context = NULL;
515       }
516       wavpackdec->wv_id.buffer = NULL;
517       wavpackdec->wv_id.position = 0;
518       wavpackdec->wv_id.length = 0;
519       /*
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;
525        */
526       wavpackdec->channels = 0;
527       wavpackdec->sample_rate = 0;
528       wavpackdec->width = 0;
529       break;
530     case GST_STATE_CHANGE_READY_TO_NULL:
531       break;
532     default:
533       break;
534   }
535
536   return ret;
537 }
538
539 #if 0
540 static GstPad *
541 gst_wavpack_dec_request_new_pad (GstElement * element,
542     GstPadTemplate * templ, const gchar * name)
543 {
544   GstWavpackDec *wavpackdec = GST_WAVPACK_DEC (element);
545   GstPad *pad;
546
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));
553   } else {
554     pad = NULL;
555   }
556
557   return pad;
558 }
559 #endif
560
561 gboolean
562 gst_wavpack_dec_plugin_init (GstPlugin * plugin)
563 {
564   if (!gst_element_register (plugin, "wavpackdec",
565           GST_RANK_PRIMARY, GST_TYPE_WAVPACK_DEC))
566     return FALSE;
567   GST_DEBUG_CATEGORY_INIT (gst_wavpack_dec_debug, "wavpackdec", 0,
568       "wavpack decoder");
569   return TRUE;
570 }