4fd00b9b1c267979ddb24d34b5e5632fa7734893
[platform/upstream/gst-plugins-good.git] / ext / wavpack / gstwavpackparse.c
1 /* GStreamer wavpack plugin
2  * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
3  * Copyright (c) 2006 Tim-Philipp Müller <tim centricular net>
4  * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
5  *
6  * gstwavpackparse.c: wavpack file parser
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 /**
25  * SECTION:element-wavpackparse
26  *
27  * <refsect2>
28  * WavpackParse takes raw, unframed Wavpack streams and splits them into
29  * single Wavpack chunks with information like bit depth and the position
30  * in the stream.
31  * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
32  * audio codec that features both lossless and lossy encoding.
33  * <title>Example launch line</title>
34  * <para>
35  * <programlisting>
36  * gst-launch filesrc location=test.wv ! wavpackparse ! wavpackdec ! fakesink
37  * </programlisting>
38  * This pipeline decodes the Wavpack file test.wv into raw audio buffers.
39  * </para>
40  * </refsect2>
41  */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 #include <gst/gst.h>
47 #include <gst/gst-i18n-plugin.h>
48
49 #include <math.h>
50 #include <string.h>
51
52 #include <wavpack/wavpack.h>
53 #include "gstwavpackparse.h"
54 #include "gstwavpackstreamreader.h"
55 #include "gstwavpackcommon.h"
56
57 GST_DEBUG_CATEGORY_STATIC (gst_wavpack_parse_debug);
58 #define GST_CAT_DEFAULT gst_wavpack_parse_debug
59
60 /* FIXME: unconditionally use GSlice after we depend on GLib >= 2.10 */
61 #if GLIB_CHECK_VERSION (2, 10, 0)
62 static inline GstWavpackParseIndexEntry *
63 gst_wavpack_parse_index_entry_new ()
64 {
65   return g_slice_new (GstWavpackParseIndexEntry);
66 }
67
68 static inline void
69 gst_wavpack_parse_index_entry_free (GstWavpackParseIndexEntry * entry)
70 {
71   g_slice_free (GstWavpackParseIndexEntry, entry);
72 }
73 #else
74 static inline GstWavpackParseIndexEntry *
75 gst_wavpack_parse_index_entry_new ()
76 {
77   return g_new (GstWavpackParseIndexEntry, 1);
78 }
79
80 static inline void
81 gst_wavpack_parse_index_entry_free (GstWavpackParseIndexEntry * entry)
82 {
83   g_free (entry);
84 }
85 #endif
86
87 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
88     GST_PAD_SINK,
89     GST_PAD_ALWAYS,
90     GST_STATIC_CAPS ("audio/x-wavpack, "
91         "framed = (boolean) false; "
92         "audio/x-wavpack-correction, " "framed = (boolean) false")
93     );
94
95 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
96     GST_PAD_SRC,
97     GST_PAD_SOMETIMES,
98     GST_STATIC_CAPS ("audio/x-wavpack, "
99         "width = (int) [ 1, 32 ], "
100         "channels = (int) [ 1, 8 ], "
101         "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
102     );
103
104 static GstStaticPadTemplate wvc_src_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc",
105     GST_PAD_SRC,
106     GST_PAD_SOMETIMES,
107     GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true")
108     );
109
110 static gboolean gst_wavpack_parse_sink_activate (GstPad * sinkpad);
111 static gboolean
112 gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active);
113
114 static void gst_wavpack_parse_loop (GstElement * element);
115 static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement *
116     element, GstStateChange transition);
117 static void gst_wavpack_parse_reset (GstWavpackParse * parse);
118 static gint64 gst_wavpack_parse_get_upstream_length (GstWavpackParse * wvparse);
119 static GstBuffer *gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse,
120     gint64 offset, guint size, GstFlowReturn * flow);
121 static GstFlowReturn gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf);
122
123 GST_BOILERPLATE (GstWavpackParse, gst_wavpack_parse, GstElement,
124     GST_TYPE_ELEMENT);
125
126 static void
127 gst_wavpack_parse_base_init (gpointer klass)
128 {
129   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
130
131   gst_element_class_add_pad_template (element_class,
132       gst_static_pad_template_get (&src_factory));
133   gst_element_class_add_pad_template (element_class,
134       gst_static_pad_template_get (&wvc_src_factory));
135   gst_element_class_add_pad_template (element_class,
136       gst_static_pad_template_get (&sink_factory));
137
138   gst_element_class_set_details_simple (element_class, "Wavpack parser",
139       "Codec/Demuxer/Audio",
140       "Parses Wavpack files",
141       "Arwed v. Merkatz <v.merkatz@gmx.net>, "
142       "Sebastian Dröge <slomo@circular-chaos.org>");
143 }
144
145 static void
146 gst_wavpack_parse_finalize (GObject * object)
147 {
148   gst_wavpack_parse_reset (GST_WAVPACK_PARSE (object));
149
150   G_OBJECT_CLASS (parent_class)->finalize (object);
151 }
152
153 static void
154 gst_wavpack_parse_class_init (GstWavpackParseClass * klass)
155 {
156   GObjectClass *gobject_class;
157   GstElementClass *gstelement_class;
158
159   gobject_class = (GObjectClass *) klass;
160   gstelement_class = (GstElementClass *) klass;
161
162   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_wavpack_parse_finalize);
163   gstelement_class->change_state =
164       GST_DEBUG_FUNCPTR (gst_wavpack_parse_change_state);
165 }
166
167 static GstWavpackParseIndexEntry *
168 gst_wavpack_parse_index_get_last_entry (GstWavpackParse * wvparse)
169 {
170   g_assert (wvparse->entries != NULL);
171
172   return wvparse->entries->data;
173 }
174
175 static GstWavpackParseIndexEntry *
176 gst_wavpack_parse_index_get_entry_from_sample (GstWavpackParse * wvparse,
177     gint64 sample_offset)
178 {
179   gint i;
180   GSList *node;
181
182   if (wvparse->entries == NULL)
183     return NULL;
184
185   for (node = wvparse->entries, i = 0; node; node = node->next, i++) {
186     GstWavpackParseIndexEntry *entry;
187
188     entry = node->data;
189
190     GST_LOG_OBJECT (wvparse, "Index entry %03u: sample %" G_GINT64_FORMAT " @"
191         " byte %" G_GINT64_FORMAT, i, entry->sample_offset, entry->byte_offset);
192
193     if (entry->sample_offset <= sample_offset &&
194         sample_offset < entry->sample_offset_end) {
195       GST_LOG_OBJECT (wvparse, "found match");
196       return entry;
197     }
198
199     /* as the list is sorted and we first look at the latest entry
200      * we can abort searching for an entry if the sample we want is
201      * after the latest one */
202     if (sample_offset >= entry->sample_offset_end)
203       break;
204   }
205   GST_LOG_OBJECT (wvparse, "no match in index");
206   return NULL;
207 }
208
209 static void
210 gst_wavpack_parse_index_append_entry (GstWavpackParse * wvparse,
211     gint64 byte_offset, gint64 sample_offset, gint64 num_samples)
212 {
213   GstWavpackParseIndexEntry *entry;
214
215   /* do we have this one already? */
216   if (wvparse->entries) {
217     entry = gst_wavpack_parse_index_get_last_entry (wvparse);
218     if (entry->byte_offset >= byte_offset
219         || entry->sample_offset >= sample_offset)
220       return;
221   }
222
223   GST_LOG_OBJECT (wvparse, "Adding index entry %8" G_GINT64_FORMAT " - %"
224       GST_TIME_FORMAT " @ offset 0x%08" G_GINT64_MODIFIER "x", sample_offset,
225       GST_TIME_ARGS (gst_util_uint64_scale_int (sample_offset,
226               GST_SECOND, wvparse->samplerate)), byte_offset);
227
228   entry = gst_wavpack_parse_index_entry_new ();
229   entry->byte_offset = byte_offset;
230   entry->sample_offset = sample_offset;
231   entry->sample_offset_end = sample_offset + num_samples;
232   wvparse->entries = g_slist_prepend (wvparse->entries, entry);
233 }
234
235 static void
236 gst_wavpack_parse_reset (GstWavpackParse * parse)
237 {
238   parse->total_samples = -1;
239   parse->samplerate = 0;
240   parse->channels = 0;
241
242   gst_segment_init (&parse->segment, GST_FORMAT_UNDEFINED);
243   parse->next_block_index = 0;
244
245   parse->current_offset = 0;
246   parse->need_newsegment = TRUE;
247   parse->discont = TRUE;
248   parse->upstream_length = -1;
249
250   if (parse->entries) {
251     g_slist_foreach (parse->entries, (GFunc) gst_wavpack_parse_index_entry_free,
252         NULL);
253     g_slist_free (parse->entries);
254     parse->entries = NULL;
255   }
256
257   if (parse->adapter) {
258     gst_adapter_clear (parse->adapter);
259     g_object_unref (parse->adapter);
260     parse->adapter = NULL;
261   }
262
263   if (parse->srcpad != NULL) {
264     gboolean res;
265
266     GST_DEBUG_OBJECT (parse, "Removing src pad");
267     res = gst_element_remove_pad (GST_ELEMENT (parse), parse->srcpad);
268     g_return_if_fail (res != FALSE);
269     gst_object_unref (parse->srcpad);
270     parse->srcpad = NULL;
271   }
272
273   g_list_foreach (parse->queued_events, (GFunc) gst_mini_object_unref, NULL);
274   g_list_free (parse->queued_events);
275   parse->queued_events = NULL;
276
277   if (parse->pending_buffer)
278     gst_buffer_unref (parse->pending_buffer);
279
280   parse->pending_buffer = NULL;
281 }
282
283 static const GstQueryType *
284 gst_wavpack_parse_get_src_query_types (GstPad * pad)
285 {
286   static const GstQueryType types[] = {
287     GST_QUERY_POSITION,
288     GST_QUERY_DURATION,
289     GST_QUERY_SEEKING,
290     0
291   };
292
293   return types;
294 }
295
296 static gboolean
297 gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query)
298 {
299   GstWavpackParse *parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
300   GstFormat format;
301   gboolean ret = FALSE;
302
303   switch (GST_QUERY_TYPE (query)) {
304     case GST_QUERY_POSITION:{
305       gint64 cur;
306       guint rate;
307
308       GST_OBJECT_LOCK (parse);
309       cur = parse->segment.last_stop;
310       rate = parse->samplerate;
311       GST_OBJECT_UNLOCK (parse);
312
313       if (rate == 0) {
314         GST_DEBUG_OBJECT (parse, "haven't read header yet");
315         break;
316       }
317
318       gst_query_parse_position (query, &format, NULL);
319
320       switch (format) {
321         case GST_FORMAT_TIME:
322           cur = gst_util_uint64_scale_int (cur, GST_SECOND, rate);
323           gst_query_set_position (query, GST_FORMAT_TIME, cur);
324           ret = TRUE;
325           break;
326         case GST_FORMAT_DEFAULT:
327           gst_query_set_position (query, GST_FORMAT_DEFAULT, cur);
328           ret = TRUE;
329           break;
330         default:
331           GST_DEBUG_OBJECT (parse, "cannot handle position query in "
332               "%s format. Forwarding upstream.", gst_format_get_name (format));
333           ret = gst_pad_query_default (pad, query);
334           break;
335       }
336       break;
337     }
338     case GST_QUERY_DURATION:{
339       gint64 len;
340       guint rate;
341
342       GST_OBJECT_LOCK (parse);
343       rate = parse->samplerate;
344       len = parse->total_samples;
345       GST_OBJECT_UNLOCK (parse);
346
347       if (rate == 0) {
348         GST_DEBUG_OBJECT (parse, "haven't read header yet");
349         break;
350       }
351
352       gst_query_parse_duration (query, &format, NULL);
353
354       switch (format) {
355         case GST_FORMAT_TIME:
356           if (len != -1)
357             len = gst_util_uint64_scale_int (len, GST_SECOND, rate);
358           gst_query_set_duration (query, GST_FORMAT_TIME, len);
359           ret = TRUE;
360           break;
361         case GST_FORMAT_DEFAULT:
362           gst_query_set_duration (query, GST_FORMAT_DEFAULT, len);
363           ret = TRUE;
364           break;
365         default:
366           GST_DEBUG_OBJECT (parse, "cannot handle duration query in "
367               "%s format. Forwarding upstream.", gst_format_get_name (format));
368           ret = gst_pad_query_default (pad, query);
369           break;
370       }
371       break;
372     }
373     case GST_QUERY_SEEKING:{
374       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
375       if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) {
376         gboolean seekable;
377         gint64 duration = -1;
378
379         /* only fails if we didn't read the headers yet and can't say
380          * anything about our seeking capabilities */
381         if (!gst_pad_query_duration (pad, &format, &duration))
382           break;
383
384         /* can't seek in streaming mode yet */
385         GST_OBJECT_LOCK (parse);
386         seekable = (parse->adapter == NULL);
387         GST_OBJECT_UNLOCK (parse);
388
389         gst_query_set_seeking (query, format, seekable, 0, duration);
390         ret = TRUE;
391       }
392       break;
393     }
394     default:{
395       ret = gst_pad_query_default (pad, query);
396       break;
397     }
398   }
399
400   gst_object_unref (parse);
401   return ret;
402
403 }
404
405 /* returns TRUE on success, with byte_offset set to the offset of the
406  * wavpack chunk containing the sample requested. start_sample will be
407  * set to the first sample in the chunk starting at byte_offset.
408  * Scanning from the last known header offset to the wanted position
409  * when seeking forward isn't very clever, but seems fast enough in
410  * practice and has the nice side effect of populating our index
411  * table */
412 static gboolean
413 gst_wavpack_parse_scan_to_find_sample (GstWavpackParse * parse,
414     gint64 sample, gint64 * byte_offset, gint64 * start_sample)
415 {
416   GstWavpackParseIndexEntry *entry;
417   GstFlowReturn ret;
418   gint64 off = 0;
419
420   /* first, check if we have to scan at all */
421   entry = gst_wavpack_parse_index_get_entry_from_sample (parse, sample);
422   if (entry) {
423     *byte_offset = entry->byte_offset;
424     *start_sample = entry->sample_offset;
425     GST_LOG_OBJECT (parse, "Found index entry: sample %" G_GINT64_FORMAT
426         " @ offset %" G_GINT64_FORMAT, entry->sample_offset,
427         entry->byte_offset);
428     return TRUE;
429   }
430
431   GST_LOG_OBJECT (parse, "No matching entry in index, scanning file ...");
432
433   /* if we have an index, we can start scanning from the last known offset
434    * in there, after all we know our wanted sample is not in the index */
435   if (parse->entries) {
436     GstWavpackParseIndexEntry *entry;
437
438     entry = gst_wavpack_parse_index_get_last_entry (parse);
439     off = entry->byte_offset;
440   }
441
442   /* now scan forward until we find the chunk we're looking for or hit EOS */
443   do {
444     WavpackHeader header;
445     GstBuffer *buf;
446
447     buf = gst_wavpack_parse_pull_buffer (parse, off, sizeof (WavpackHeader),
448         &ret);
449
450     if (buf == NULL)
451       break;
452
453     gst_wavpack_read_header (&header, GST_BUFFER_DATA (buf));
454     gst_buffer_unref (buf);
455
456     if (header.flags & INITIAL_BLOCK)
457       gst_wavpack_parse_index_append_entry (parse, off, header.block_index,
458           header.block_samples);
459     else
460       continue;
461
462     if (header.block_index <= sample &&
463         sample < (header.block_index + header.block_samples)) {
464       *byte_offset = off;
465       *start_sample = header.block_index;
466       return TRUE;
467     }
468
469     off += header.ckSize + 8;
470   } while (1);
471
472   GST_DEBUG_OBJECT (parse, "scan failed: %s (off=0x%08" G_GINT64_MODIFIER "x)",
473       gst_flow_get_name (ret), off);
474
475   return FALSE;
476 }
477
478 static gboolean
479 gst_wavpack_parse_send_newsegment (GstWavpackParse * wvparse, gboolean update)
480 {
481   GstSegment *s = &wvparse->segment;
482   gboolean ret;
483   gint64 stop_time = -1;
484   gint64 start_time = 0;
485   gint64 cur_pos_time;
486   gint64 diff;
487
488   /* segment is in DEFAULT format, but we want to send a TIME newsegment */
489   start_time = gst_util_uint64_scale_int (s->start, GST_SECOND,
490       wvparse->samplerate);
491
492   if (s->stop != -1) {
493     stop_time = gst_util_uint64_scale_int (s->stop, GST_SECOND,
494         wvparse->samplerate);
495   }
496
497   GST_DEBUG_OBJECT (wvparse, "sending newsegment from %" GST_TIME_FORMAT
498       " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start_time),
499       GST_TIME_ARGS (stop_time));
500
501   /* after a seek, s->last_stop will point to a chunk boundary, ie. from
502    * which sample we will start sending data again, while s->start will
503    * point to the sample we actually want to seek to and want to start
504    * playing right after the seek. Adjust clock-time for the difference
505    * so we start playing from start_time */
506   cur_pos_time = gst_util_uint64_scale_int (s->last_stop, GST_SECOND,
507       wvparse->samplerate);
508   diff = start_time - cur_pos_time;
509
510   ret = gst_pad_push_event (wvparse->srcpad,
511       gst_event_new_new_segment (update, s->rate, GST_FORMAT_TIME,
512           start_time, stop_time, start_time - diff));
513
514   return ret;
515 }
516
517 static gboolean
518 gst_wavpack_parse_handle_seek_event (GstWavpackParse * wvparse,
519     GstEvent * event)
520 {
521   GstSeekFlags seek_flags;
522   GstSeekType start_type;
523   GstSeekType stop_type;
524   GstSegment segment;
525   GstFormat format;
526   gboolean only_update;
527   gboolean flush, ret;
528   gdouble speed;
529   gint64 stop;
530   gint64 start;                 /* sample we want to seek to                  */
531   gint64 byte_offset;           /* byte offset the chunk we seek to starts at */
532   gint64 chunk_start;           /* first sample in chunk we seek to           */
533   guint rate;
534   gint64 last_stop;
535
536   if (wvparse->adapter) {
537     GST_DEBUG_OBJECT (wvparse, "seeking in streaming mode not implemented yet");
538     return FALSE;
539   }
540
541   gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type,
542       &start, &stop_type, &stop);
543
544   if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME) {
545     GST_DEBUG ("seeking is only supported in TIME or DEFAULT format");
546     return FALSE;
547   }
548
549   if (speed < 0.0) {
550     GST_DEBUG ("only forward playback supported, rate %f not allowed", speed);
551     return FALSE;
552   }
553
554   GST_OBJECT_LOCK (wvparse);
555
556   rate = wvparse->samplerate;
557   if (rate == 0) {
558     GST_OBJECT_UNLOCK (wvparse);
559     GST_DEBUG ("haven't read header yet");
560     return FALSE;
561   }
562
563   /* figure out the last position we need to play. If it's configured (stop !=
564    * -1), use that, else we play until the total duration of the file */
565   if (stop == -1)
566     stop = wvparse->segment.duration;
567
568   /* convert from time to samples if necessary */
569   if (format == GST_FORMAT_TIME) {
570     if (start_type != GST_SEEK_TYPE_NONE)
571       start = gst_util_uint64_scale_int (start, rate, GST_SECOND);
572     if (stop_type != GST_SEEK_TYPE_NONE)
573       stop = gst_util_uint64_scale_int (stop, rate, GST_SECOND);
574   }
575
576   if (start < 0) {
577     GST_OBJECT_UNLOCK (wvparse);
578     GST_DEBUG_OBJECT (wvparse, "Invalid start sample %" G_GINT64_FORMAT, start);
579     return FALSE;
580   }
581
582   flush = ((seek_flags & GST_SEEK_FLAG_FLUSH) != 0);
583
584   /* operate on segment copy until we know the seek worked */
585   segment = wvparse->segment;
586
587   gst_segment_set_seek (&segment, speed, GST_FORMAT_DEFAULT,
588       seek_flags, start_type, start, stop_type, stop, &only_update);
589
590 #if 0
591   if (only_update) {
592     wvparse->segment = segment;
593     gst_wavpack_parse_send_newsegment (wvparse, TRUE);
594     goto done;
595   }
596 #endif
597
598   gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_start ());
599
600   if (flush) {
601     gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_start ());
602   } else {
603     gst_pad_pause_task (wvparse->sinkpad);
604   }
605
606   GST_PAD_STREAM_LOCK (wvparse->sinkpad);
607
608   /* Save current position */
609   last_stop = wvparse->segment.last_stop;
610
611   gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_stop ());
612
613   if (flush) {
614     gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_stop ());
615   }
616
617   GST_DEBUG_OBJECT (wvparse, "Performing seek to %" GST_TIME_FORMAT " sample %"
618       G_GINT64_FORMAT, GST_TIME_ARGS (segment.start * GST_SECOND / rate),
619       start);
620
621   ret = gst_wavpack_parse_scan_to_find_sample (wvparse, segment.start,
622       &byte_offset, &chunk_start);
623
624   if (ret) {
625     GST_DEBUG_OBJECT (wvparse, "new offset: %" G_GINT64_FORMAT, byte_offset);
626     wvparse->current_offset = byte_offset;
627     /* we want to send a newsegment event with the actual seek position
628      * as start, even though our first buffer might start before the
629      * configured segment. We leave it up to the decoder or sink to crop
630      * the output buffers accordingly */
631     wvparse->segment = segment;
632     wvparse->segment.last_stop = chunk_start;
633     wvparse->need_newsegment = TRUE;
634     wvparse->discont = (last_stop != chunk_start) ? TRUE : FALSE;
635
636     /* if we're doing a segment seek, post a SEGMENT_START message */
637     if (wvparse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
638       gst_element_post_message (GST_ELEMENT_CAST (wvparse),
639           gst_message_new_segment_start (GST_OBJECT_CAST (wvparse),
640               wvparse->segment.format, wvparse->segment.last_stop));
641     }
642   } else {
643     GST_DEBUG_OBJECT (wvparse, "seek failed: don't know where to seek to");
644   }
645
646   GST_PAD_STREAM_UNLOCK (wvparse->sinkpad);
647   GST_OBJECT_UNLOCK (wvparse);
648
649   gst_pad_start_task (wvparse->sinkpad,
650       (GstTaskFunction) gst_wavpack_parse_loop, wvparse);
651
652   return ret;
653 }
654
655 static gboolean
656 gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
657 {
658   GstWavpackParse *parse;
659   gboolean ret = TRUE;
660
661   parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
662
663   switch (GST_EVENT_TYPE (event)) {
664     case GST_EVENT_FLUSH_STOP:{
665       if (parse->adapter) {
666         gst_adapter_clear (parse->adapter);
667       }
668       if (parse->pending_buffer) {
669         gst_buffer_unref (parse->pending_buffer);
670         parse->pending_buffer = NULL;
671         parse->pending_offset = 0;
672       }
673       ret = gst_pad_push_event (parse->srcpad, event);
674       break;
675     }
676     case GST_EVENT_NEWSEGMENT:{
677       parse->need_newsegment = TRUE;
678       gst_event_unref (event);
679       ret = TRUE;
680       break;
681     }
682     case GST_EVENT_EOS:{
683       if (parse->adapter) {
684         /* remove all bytes that are left in the adapter after EOS. They can't
685          * be a complete Wavpack block and we can't do anything with them */
686         gst_adapter_clear (parse->adapter);
687       }
688       if (parse->pending_buffer) {
689         gst_buffer_unref (parse->pending_buffer);
690         parse->pending_buffer = NULL;
691         parse->pending_offset = 0;
692       }
693       ret = gst_pad_push_event (parse->srcpad, event);
694       break;
695     }
696     default:{
697       /* stream lock is recursive, should be fine for all events */
698       GST_PAD_STREAM_LOCK (pad);
699       if (parse->srcpad == NULL) {
700         parse->queued_events = g_list_append (parse->queued_events, event);
701       } else {
702         ret = gst_pad_push_event (parse->srcpad, event);
703       }
704       GST_PAD_STREAM_UNLOCK (pad);
705     }
706   }
707
708
709   gst_object_unref (parse);
710   return ret;
711 }
712
713 static gboolean
714 gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event)
715 {
716   GstWavpackParse *parse;
717   gboolean ret;
718
719   parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
720
721   switch (GST_EVENT_TYPE (event)) {
722     case GST_EVENT_SEEK:
723       ret = gst_wavpack_parse_handle_seek_event (parse, event);
724       break;
725     default:
726       ret = gst_pad_event_default (pad, event);
727       break;
728   }
729
730   gst_object_unref (parse);
731   return ret;
732 }
733
734 static void
735 gst_wavpack_parse_init (GstWavpackParse * parse, GstWavpackParseClass * gclass)
736 {
737   GstElementClass *klass = GST_ELEMENT_GET_CLASS (parse);
738   GstPadTemplate *tmpl;
739
740   tmpl = gst_element_class_get_pad_template (klass, "sink");
741   parse->sinkpad = gst_pad_new_from_template (tmpl, "sink");
742
743   gst_pad_set_activate_function (parse->sinkpad,
744       GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate));
745   gst_pad_set_activatepull_function (parse->sinkpad,
746       GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate_pull));
747   gst_pad_set_event_function (parse->sinkpad,
748       GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_event));
749   gst_pad_set_chain_function (parse->sinkpad,
750       GST_DEBUG_FUNCPTR (gst_wavpack_parse_chain));
751
752   gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
753
754   parse->srcpad = NULL;
755   gst_wavpack_parse_reset (parse);
756 }
757
758 static gint64
759 gst_wavpack_parse_get_upstream_length (GstWavpackParse * parse)
760 {
761   gint64 length = -1;
762
763   GstFormat format = GST_FORMAT_BYTES;
764
765   if (!gst_pad_query_peer_duration (parse->sinkpad, &format, &length)) {
766     length = -1;
767   } else {
768     GST_DEBUG ("upstream length: %" G_GINT64_FORMAT, length);
769   }
770   return length;
771 }
772
773 static GstBuffer *
774 gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse, gint64 offset,
775     guint size, GstFlowReturn * flow)
776 {
777   GstFlowReturn flow_ret;
778   GstBuffer *buf = NULL;
779
780   if (offset + size >= wvparse->upstream_length) {
781     wvparse->upstream_length = gst_wavpack_parse_get_upstream_length (wvparse);
782     if (offset + size >= wvparse->upstream_length) {
783       GST_DEBUG_OBJECT (wvparse, "EOS: %" G_GINT64_FORMAT " + %u > %"
784           G_GINT64_FORMAT, offset, size, wvparse->upstream_length);
785       flow_ret = GST_FLOW_UNEXPECTED;
786       goto done;
787     }
788   }
789
790   flow_ret = gst_pad_pull_range (wvparse->sinkpad, offset, size, &buf);
791
792   if (flow_ret != GST_FLOW_OK) {
793     GST_DEBUG_OBJECT (wvparse, "pull_range (%" G_GINT64_FORMAT ", %u) "
794         "failed, flow: %s", offset, size, gst_flow_get_name (flow_ret));
795     buf = NULL;
796     goto done;
797   }
798
799   if (GST_BUFFER_SIZE (buf) < size) {
800     GST_DEBUG_OBJECT (wvparse, "Short read at offset %" G_GINT64_FORMAT
801         ", got only %u of %u bytes", offset, GST_BUFFER_SIZE (buf), size);
802     gst_buffer_unref (buf);
803     buf = NULL;
804     flow_ret = GST_FLOW_UNEXPECTED;
805   }
806
807 done:
808   if (flow)
809     *flow = flow_ret;
810   return buf;
811 }
812
813 static gboolean
814 gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
815     WavpackHeader * header)
816 {
817   GstWavpackMetadata meta;
818   GstCaps *caps = NULL;
819   guchar *bufptr;
820
821   g_assert (wvparse->srcpad == NULL);
822
823   bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader);
824
825   while (gst_wavpack_read_metadata (&meta, GST_BUFFER_DATA (buf), &bufptr)) {
826     switch (meta.id) {
827       case ID_WVC_BITSTREAM:{
828         caps = gst_caps_new_simple ("audio/x-wavpack-correction",
829             "framed", G_TYPE_BOOLEAN, TRUE, NULL);
830         wvparse->srcpad =
831             gst_pad_new_from_template (gst_element_class_get_pad_template
832             (GST_ELEMENT_GET_CLASS (wvparse), "wvcsrc"), "wvcsrc");
833         break;
834       }
835       case ID_WV_BITSTREAM:
836       case ID_WVX_BITSTREAM:{
837         WavpackStreamReader *stream_reader = gst_wavpack_stream_reader_new ();
838         WavpackContext *wpc;
839         gchar error_msg[80];
840         read_id rid;
841         gint channel_mask;
842
843         rid.buffer = GST_BUFFER_DATA (buf);
844         rid.length = GST_BUFFER_SIZE (buf);
845         rid.position = 0;
846
847         wpc =
848             WavpackOpenFileInputEx (stream_reader, &rid, NULL, error_msg, 0, 0);
849
850         if (!wpc)
851           return FALSE;
852
853         wvparse->samplerate = WavpackGetSampleRate (wpc);
854         wvparse->channels = WavpackGetNumChannels (wpc);
855         wvparse->total_samples = (header->total_samples == (int32_t) - 1) ?
856             -1 : header->total_samples;
857
858         caps = gst_caps_new_simple ("audio/x-wavpack",
859             "width", G_TYPE_INT, WavpackGetBitsPerSample (wpc),
860             "channels", G_TYPE_INT, wvparse->channels,
861             "rate", G_TYPE_INT, wvparse->samplerate,
862             "framed", G_TYPE_BOOLEAN, TRUE, NULL);
863 #ifdef WAVPACK_OLD_API
864         channel_mask = wpc->config.channel_mask;
865 #else
866         channel_mask = WavpackGetChannelMask (wpc);
867 #endif
868         if (channel_mask == 0)
869           channel_mask =
870               gst_wavpack_get_default_channel_mask (wvparse->channels);
871
872         if (channel_mask != 0) {
873           if (!gst_wavpack_set_channel_layout (caps, channel_mask)) {
874             GST_WARNING_OBJECT (wvparse, "Failed to set channel layout");
875             gst_caps_unref (caps);
876             caps = NULL;
877             WavpackCloseFile (wpc);
878             g_free (stream_reader);
879             break;
880           }
881         }
882
883         wvparse->srcpad =
884             gst_pad_new_from_template (gst_element_class_get_pad_template
885             (GST_ELEMENT_GET_CLASS (wvparse), "src"), "src");
886         WavpackCloseFile (wpc);
887         g_free (stream_reader);
888         break;
889       }
890       default:{
891         GST_LOG_OBJECT (wvparse, "unhandled ID: 0x%02x", meta.id);
892         break;
893       }
894     }
895     if (caps != NULL)
896       break;
897   }
898
899   if (caps == NULL || wvparse->srcpad == NULL)
900     return FALSE;
901
902   GST_DEBUG_OBJECT (wvparse, "Added src pad with caps %" GST_PTR_FORMAT, caps);
903
904   gst_pad_set_query_function (wvparse->srcpad,
905       GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query));
906   gst_pad_set_query_type_function (wvparse->srcpad,
907       GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types));
908   gst_pad_set_event_function (wvparse->srcpad,
909       GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event));
910
911   gst_pad_set_caps (wvparse->srcpad, caps);
912   gst_caps_unref (caps);
913   gst_pad_use_fixed_caps (wvparse->srcpad);
914
915   gst_object_ref (wvparse->srcpad);
916   gst_pad_set_active (wvparse->srcpad, TRUE);
917   gst_element_add_pad (GST_ELEMENT (wvparse), wvparse->srcpad);
918   gst_element_no_more_pads (GST_ELEMENT (wvparse));
919
920   return TRUE;
921 }
922
923 static GstFlowReturn
924 gst_wavpack_parse_push_buffer (GstWavpackParse * wvparse, GstBuffer * buf,
925     WavpackHeader * header)
926 {
927   wvparse->current_offset += header->ckSize + 8;
928
929   wvparse->segment.last_stop = header->block_index;
930
931   if (wvparse->need_newsegment) {
932     if (gst_wavpack_parse_send_newsegment (wvparse, FALSE))
933       wvparse->need_newsegment = FALSE;
934   }
935
936   /* send any queued events */
937   if (wvparse->queued_events) {
938     GList *l;
939
940     for (l = wvparse->queued_events; l != NULL; l = l->next) {
941       gst_pad_push_event (wvparse->srcpad, GST_EVENT (l->data));
942     }
943     g_list_free (wvparse->queued_events);
944     wvparse->queued_events = NULL;
945   }
946
947   if (wvparse->pending_buffer == NULL) {
948     wvparse->pending_buffer = buf;
949     wvparse->pending_offset = header->block_index;
950   } else if (wvparse->pending_offset == header->block_index) {
951     wvparse->pending_buffer = gst_buffer_join (wvparse->pending_buffer, buf);
952   } else {
953     GST_ERROR ("Got incomplete block, dropping");
954     gst_buffer_unref (wvparse->pending_buffer);
955     wvparse->pending_buffer = buf;
956     wvparse->pending_offset = header->block_index;
957   }
958
959   if (!(header->flags & FINAL_BLOCK))
960     return GST_FLOW_OK;
961
962   buf = wvparse->pending_buffer;
963   wvparse->pending_buffer = NULL;
964
965   GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (header->block_index,
966       GST_SECOND, wvparse->samplerate);
967   GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (header->block_samples,
968       GST_SECOND, wvparse->samplerate);
969   GST_BUFFER_OFFSET (buf) = header->block_index;
970   GST_BUFFER_OFFSET_END (buf) = header->block_index + header->block_samples;
971
972   if (wvparse->discont || wvparse->next_block_index != header->block_index) {
973     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
974     wvparse->discont = FALSE;
975   }
976
977   wvparse->next_block_index = header->block_index + header->block_samples;
978
979   gst_buffer_set_caps (buf, GST_PAD_CAPS (wvparse->srcpad));
980
981   GST_LOG_OBJECT (wvparse, "Pushing buffer with time %" GST_TIME_FORMAT,
982       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
983
984   return gst_pad_push (wvparse->srcpad, buf);
985 }
986
987 static guint8 *
988 gst_wavpack_parse_find_marker (guint8 * buf, guint size)
989 {
990   int i;
991   guint8 *ret = NULL;
992
993   if (G_UNLIKELY (size < 4))
994     return NULL;
995
996   for (i = 0; i < size - 4; i++) {
997     if (memcmp (buf + i, "wvpk", 4) == 0) {
998       ret = buf + i;
999       break;
1000     }
1001   }
1002   return ret;
1003 }
1004
1005 static GstFlowReturn
1006 gst_wavpack_parse_resync_loop (GstWavpackParse * parse, WavpackHeader * header)
1007 {
1008   GstFlowReturn flow_ret = GST_FLOW_UNEXPECTED;
1009   GstBuffer *buf = NULL;
1010
1011   /* loop until we have a frame header or reach the end of the stream */
1012   while (1) {
1013     guint8 *data, *marker;
1014     guint len, size;
1015
1016     if (buf) {
1017       gst_buffer_unref (buf);
1018       buf = NULL;
1019     }
1020
1021     if (parse->upstream_length == 0 ||
1022         parse->upstream_length <= parse->current_offset) {
1023       parse->upstream_length = gst_wavpack_parse_get_upstream_length (parse);
1024       if (parse->upstream_length == 0 ||
1025           parse->upstream_length <= parse->current_offset) {
1026         break;
1027       }
1028     }
1029
1030     len = MIN (parse->upstream_length - parse->current_offset, 2048);
1031
1032     GST_LOG_OBJECT (parse, "offset: %" G_GINT64_FORMAT, parse->current_offset);
1033
1034     buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
1035         len, &flow_ret);
1036
1037     /* whatever the problem is, there's nothing more for us to do for now */
1038     if (flow_ret != GST_FLOW_OK)
1039       break;
1040
1041     data = GST_BUFFER_DATA (buf);
1042     size = GST_BUFFER_SIZE (buf);
1043
1044     /* not enough data for a header? */
1045     if (size < sizeof (WavpackHeader))
1046       break;
1047
1048     /* got a header right where we are at now? */
1049     if (gst_wavpack_read_header (header, data))
1050       break;
1051
1052     /* nope, let's see if we can find one */
1053     marker = gst_wavpack_parse_find_marker (data + 1, size - 1);
1054
1055     if (marker) {
1056       parse->current_offset += marker - data;
1057       /* do one more loop iteration to make sure we pull enough
1058        * data for a full header, we'll bail out then */
1059     } else {
1060       parse->current_offset += len - 4;
1061     }
1062   }
1063
1064   if (buf)
1065     gst_buffer_unref (buf);
1066
1067   return flow_ret;
1068 }
1069
1070 static void
1071 gst_wavpack_parse_loop (GstElement * element)
1072 {
1073   GstWavpackParse *parse = GST_WAVPACK_PARSE (element);
1074   GstFlowReturn flow_ret;
1075   WavpackHeader header = { {0,}, 0, };
1076   GstBuffer *buf = NULL;
1077
1078   flow_ret = gst_wavpack_parse_resync_loop (parse, &header);
1079
1080   if (flow_ret != GST_FLOW_OK)
1081     goto pause;
1082
1083   GST_LOG_OBJECT (parse, "Read header at offset %" G_GINT64_FORMAT
1084       ": chunk size = %u+8", parse->current_offset, header.ckSize);
1085
1086   buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
1087       header.ckSize + 8, &flow_ret);
1088
1089   if (flow_ret != GST_FLOW_OK)
1090     goto pause;
1091
1092   if (parse->srcpad == NULL) {
1093     if (!gst_wavpack_parse_create_src_pad (parse, buf, &header)) {
1094       GST_ERROR_OBJECT (parse, "Failed to create src pad");
1095       flow_ret = GST_FLOW_ERROR;
1096       goto pause;
1097     }
1098   }
1099   if (header.flags & INITIAL_BLOCK)
1100     gst_wavpack_parse_index_append_entry (parse, parse->current_offset,
1101         header.block_index, header.block_samples);
1102
1103   flow_ret = gst_wavpack_parse_push_buffer (parse, buf, &header);
1104   if (flow_ret != GST_FLOW_OK)
1105     goto pause;
1106
1107   return;
1108
1109 pause:
1110   {
1111     const gchar *reason = gst_flow_get_name (flow_ret);
1112
1113     GST_LOG_OBJECT (parse, "pausing task, reason %s", reason);
1114     gst_pad_pause_task (parse->sinkpad);
1115
1116     if (GST_FLOW_IS_FATAL (flow_ret) || flow_ret == GST_FLOW_NOT_LINKED) {
1117       if (flow_ret == GST_FLOW_UNEXPECTED && parse->srcpad) {
1118         if (parse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1119           GstClockTime stop;
1120
1121           GST_LOG_OBJECT (parse, "Sending segment done");
1122
1123           if ((stop = parse->segment.stop) == -1)
1124             stop = parse->segment.duration;
1125
1126           gst_element_post_message (GST_ELEMENT_CAST (parse),
1127               gst_message_new_segment_done (GST_OBJECT_CAST (parse),
1128                   parse->segment.format, stop));
1129         } else {
1130           GST_LOG_OBJECT (parse, "Sending EOS, at end of stream");
1131           gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
1132         }
1133       } else {
1134         GST_ELEMENT_ERROR (parse, STREAM, FAILED,
1135             (_("Internal data stream error.")),
1136             ("stream stopped, reason %s", reason));
1137         if (parse->srcpad)
1138           gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
1139       }
1140     }
1141     return;
1142   }
1143 }
1144
1145 static gboolean
1146 gst_wavpack_parse_resync_adapter (GstAdapter * adapter)
1147 {
1148   const guint8 *buf, *marker;
1149   guint avail = gst_adapter_available (adapter);
1150
1151   if (avail < 4)
1152     return FALSE;
1153
1154   /* if the marker is at the beginning don't do the expensive search */
1155   buf = gst_adapter_peek (adapter, 4);
1156   if (memcmp (buf, "wvpk", 4) == 0)
1157     return TRUE;
1158
1159   if (avail == 4)
1160     return FALSE;
1161
1162   /* search for the marker in the complete content of the adapter */
1163   buf = gst_adapter_peek (adapter, avail);
1164   if (buf && (marker = gst_wavpack_parse_find_marker ((guint8 *) buf, avail))) {
1165     gst_adapter_flush (adapter, marker - buf);
1166     return TRUE;
1167   }
1168
1169   /* flush everything except the last 4 bytes. they could contain
1170    * the start of a new marker */
1171   gst_adapter_flush (adapter, avail - 4);
1172
1173   return FALSE;
1174 }
1175
1176 static GstFlowReturn
1177 gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf)
1178 {
1179   GstWavpackParse *wvparse = GST_WAVPACK_PARSE (GST_PAD_PARENT (pad));
1180   GstFlowReturn ret = GST_FLOW_OK;
1181   WavpackHeader wph;
1182   const guint8 *tmp_buf;
1183
1184   if (!wvparse->adapter) {
1185     wvparse->adapter = gst_adapter_new ();
1186   }
1187
1188   if (GST_BUFFER_IS_DISCONT (buf)) {
1189     gst_adapter_clear (wvparse->adapter);
1190     wvparse->discont = TRUE;
1191   }
1192
1193   gst_adapter_push (wvparse->adapter, buf);
1194
1195   if (gst_adapter_available (wvparse->adapter) < sizeof (WavpackHeader))
1196     return ret;
1197
1198   if (!gst_wavpack_parse_resync_adapter (wvparse->adapter))
1199     return ret;
1200
1201   tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
1202   gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
1203
1204   while (gst_adapter_available (wvparse->adapter) >= wph.ckSize + 4 * 1 + 4) {
1205     GstBuffer *outbuf =
1206         gst_adapter_take_buffer (wvparse->adapter, wph.ckSize + 4 * 1 + 4);
1207
1208     if (!outbuf)
1209       return GST_FLOW_ERROR;
1210
1211     if (wvparse->srcpad == NULL) {
1212       if (!gst_wavpack_parse_create_src_pad (wvparse, outbuf, &wph)) {
1213         GST_ERROR_OBJECT (wvparse, "Failed to create src pad");
1214         ret = GST_FLOW_ERROR;
1215         break;
1216       }
1217     }
1218
1219     ret = gst_wavpack_parse_push_buffer (wvparse, outbuf, &wph);
1220
1221     if (ret != GST_FLOW_OK)
1222       break;
1223
1224     if (gst_adapter_available (wvparse->adapter) >= sizeof (WavpackHeader)) {
1225       tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
1226
1227       if (!gst_wavpack_parse_resync_adapter (wvparse->adapter))
1228         break;
1229
1230       gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
1231     }
1232   }
1233
1234   return ret;
1235 }
1236
1237 static GstStateChangeReturn
1238 gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition)
1239 {
1240   GstWavpackParse *wvparse = GST_WAVPACK_PARSE (element);
1241   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1242
1243   switch (transition) {
1244     case GST_STATE_CHANGE_READY_TO_PAUSED:
1245       gst_segment_init (&wvparse->segment, GST_FORMAT_DEFAULT);
1246       wvparse->segment.last_stop = 0;
1247     default:
1248       break;
1249   }
1250
1251   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1252     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1253
1254   switch (transition) {
1255     case GST_STATE_CHANGE_PAUSED_TO_READY:
1256       gst_wavpack_parse_reset (wvparse);
1257       break;
1258     default:
1259       break;
1260   }
1261
1262   return ret;
1263 }
1264
1265 static gboolean
1266 gst_wavpack_parse_sink_activate (GstPad * sinkpad)
1267 {
1268   if (gst_pad_check_pull_range (sinkpad)) {
1269     return gst_pad_activate_pull (sinkpad, TRUE);
1270   } else {
1271     return gst_pad_activate_push (sinkpad, TRUE);
1272   }
1273 }
1274
1275 static gboolean
1276 gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
1277 {
1278   gboolean result;
1279
1280   if (active) {
1281     result = gst_pad_start_task (sinkpad,
1282         (GstTaskFunction) gst_wavpack_parse_loop, GST_PAD_PARENT (sinkpad));
1283   } else {
1284     result = gst_pad_stop_task (sinkpad);
1285   }
1286
1287   return result;
1288 }
1289
1290 gboolean
1291 gst_wavpack_parse_plugin_init (GstPlugin * plugin)
1292 {
1293   if (!gst_element_register (plugin, "wavpackparse",
1294           GST_RANK_PRIMARY, GST_TYPE_WAVPACK_PARSE)) {
1295     return FALSE;
1296   }
1297
1298   GST_DEBUG_CATEGORY_INIT (gst_wavpack_parse_debug, "wavpack_parse", 0,
1299       "Wavpack file parser");
1300
1301   return TRUE;
1302 }