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