gst-indent
[platform/upstream/gst-plugins-good.git] / ext / flac / gstflacdec.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
24
25 /*#define DEBUG_ENABLED */
26 #include "gstflacdec.h"
27 #include <gst/gsttaginterface.h>
28
29 #include <gst/tag/tag.h>
30
31 #include "flac_compat.h"
32
33 static GstPadTemplate *src_template, *sink_template;
34
35 /* elementfactory information */
36 GstElementDetails flacdec_details = {
37   "FLAC decoder",
38   "Codec/Decoder/Audio",
39   "Decodes FLAC lossless audio streams",
40   "Wim Taymans <wim.taymans@chello.be>",
41 };
42
43 /* FlacDec signals and args */
44 enum
45 {
46   /* FILL ME */
47   LAST_SIGNAL
48 };
49
50 enum
51 {
52   ARG_0,
53   ARG_METADATA
54 };
55
56 static void gst_flacdec_base_init (gpointer g_class);
57 static void gst_flacdec_class_init (FlacDecClass * klass);
58 static void gst_flacdec_init (FlacDec * flacdec);
59
60 static void gst_flacdec_loop (GstElement * element);
61 static GstElementStateReturn gst_flacdec_change_state (GstElement * element);
62 static const GstFormat *gst_flacdec_get_src_formats (GstPad * pad);
63 static gboolean gst_flacdec_convert_src (GstPad * pad, GstFormat src_format,
64     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
65 static const GstQueryType *gst_flacdec_get_src_query_types (GstPad * pad);
66 static gboolean gst_flacdec_src_query (GstPad * pad, GstQueryType type,
67     GstFormat * format, gint64 * value);
68 static const GstEventMask *gst_flacdec_get_src_event_masks (GstPad * pad);
69 static gboolean gst_flacdec_src_event (GstPad * pad, GstEvent * event);
70
71 static FLAC__SeekableStreamDecoderReadStatus
72 gst_flacdec_read (const FLAC__SeekableStreamDecoder * decoder,
73     FLAC__byte buffer[], unsigned *bytes, void *client_data);
74 static FLAC__SeekableStreamDecoderSeekStatus
75 gst_flacdec_seek (const FLAC__SeekableStreamDecoder * decoder,
76     FLAC__uint64 position, void *client_data);
77 static FLAC__SeekableStreamDecoderTellStatus
78 gst_flacdec_tell (const FLAC__SeekableStreamDecoder * decoder,
79     FLAC__uint64 * position, void *client_data);
80 static FLAC__SeekableStreamDecoderLengthStatus
81 gst_flacdec_length (const FLAC__SeekableStreamDecoder * decoder,
82     FLAC__uint64 * length, void *client_data);
83 static FLAC__bool gst_flacdec_eof (const FLAC__SeekableStreamDecoder * decoder,
84     void *client_data);
85 static FLAC__StreamDecoderWriteStatus
86 gst_flacdec_write (const FLAC__SeekableStreamDecoder * decoder,
87     const FLAC__Frame * frame,
88     const FLAC__int32 * const buffer[], void *client_data);
89 static void gst_flacdec_metadata_callback (const FLAC__SeekableStreamDecoder *
90     decoder, const FLAC__StreamMetadata * metadata, void *client_data);
91 static void gst_flacdec_error_callback (const FLAC__SeekableStreamDecoder *
92     decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
93
94 static GstElementClass *parent_class = NULL;
95
96 /*static guint gst_flacdec_signals[LAST_SIGNAL] = { 0 }; */
97
98 GType
99 flacdec_get_type (void)
100 {
101   static GType flacdec_type = 0;
102
103   if (!flacdec_type) {
104     static const GTypeInfo flacdec_info = {
105       sizeof (FlacDecClass),
106       gst_flacdec_base_init,
107       NULL,
108       (GClassInitFunc) gst_flacdec_class_init,
109       NULL,
110       NULL,
111       sizeof (FlacDec),
112       0,
113       (GInstanceInitFunc) gst_flacdec_init,
114     };
115     flacdec_type =
116         g_type_register_static (GST_TYPE_ELEMENT, "FlacDec", &flacdec_info, 0);
117   }
118   return flacdec_type;
119 }
120
121 static GstCaps *
122 flac_caps_factory (void)
123 {
124   return gst_caps_new_simple ("audio/x-flac", NULL);
125   /* "rate",            GST_PROPS_INT_RANGE (11025, 48000),
126    * "channels",        GST_PROPS_INT_RANGE (1, 2), */
127 }
128
129 static GstCaps *
130 raw_caps_factory (void)
131 {
132   return gst_caps_new_simple ("audio/x-raw-int",
133       "endianness", G_TYPE_INT, G_BYTE_ORDER,
134       "signed", G_TYPE_BOOLEAN, TRUE,
135       "width", G_TYPE_INT, 16,
136       "depth", G_TYPE_INT, 16,
137       "rate", GST_TYPE_INT_RANGE, 11025, 48000,
138       "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
139 }
140
141 static void
142 gst_flacdec_base_init (gpointer g_class)
143 {
144   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
145   GstCaps *raw_caps, *flac_caps;
146
147   raw_caps = raw_caps_factory ();
148   flac_caps = flac_caps_factory ();
149
150   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
151       GST_PAD_ALWAYS, flac_caps);
152   src_template = gst_pad_template_new ("src", GST_PAD_SRC,
153       GST_PAD_ALWAYS, raw_caps);
154   gst_element_class_add_pad_template (element_class, sink_template);
155   gst_element_class_add_pad_template (element_class, src_template);
156   gst_element_class_set_details (element_class, &flacdec_details);
157 }
158
159 static void
160 gst_flacdec_class_init (FlacDecClass * klass)
161 {
162   GstElementClass *gstelement_class;
163   GObjectClass *gobject_class;
164
165   gstelement_class = (GstElementClass *) klass;
166   gobject_class = (GObjectClass *) klass;
167
168   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
169
170   gstelement_class->change_state = gst_flacdec_change_state;
171 }
172
173 static void
174 gst_flacdec_init (FlacDec * flacdec)
175 {
176   flacdec->sinkpad = gst_pad_new_from_template (sink_template, "sink");
177   gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->sinkpad);
178   gst_pad_set_convert_function (flacdec->sinkpad, NULL);
179
180   gst_element_set_loop_function (GST_ELEMENT (flacdec), gst_flacdec_loop);
181   flacdec->srcpad = gst_pad_new_from_template (src_template, "src");
182   gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->srcpad);
183   gst_pad_set_formats_function (flacdec->srcpad, gst_flacdec_get_src_formats);
184   gst_pad_set_convert_function (flacdec->srcpad, gst_flacdec_convert_src);
185   gst_pad_set_query_type_function (flacdec->srcpad,
186       gst_flacdec_get_src_query_types);
187   gst_pad_set_query_function (flacdec->srcpad, gst_flacdec_src_query);
188   gst_pad_set_event_mask_function (flacdec->srcpad,
189       gst_flacdec_get_src_event_masks);
190   gst_pad_set_event_function (flacdec->srcpad, gst_flacdec_src_event);
191   gst_pad_use_explicit_caps (flacdec->srcpad);
192
193   flacdec->decoder = FLAC__seekable_stream_decoder_new ();
194   flacdec->total_samples = 0;
195   flacdec->init = TRUE;
196   flacdec->eos = FALSE;
197   flacdec->seek_pending = FALSE;
198
199   FLAC__seekable_stream_decoder_set_read_callback (flacdec->decoder,
200       gst_flacdec_read);
201   FLAC__seekable_stream_decoder_set_seek_callback (flacdec->decoder,
202       gst_flacdec_seek);
203   FLAC__seekable_stream_decoder_set_tell_callback (flacdec->decoder,
204       gst_flacdec_tell);
205   FLAC__seekable_stream_decoder_set_length_callback (flacdec->decoder,
206       gst_flacdec_length);
207   FLAC__seekable_stream_decoder_set_eof_callback (flacdec->decoder,
208       gst_flacdec_eof);
209 #if FLAC_VERSION >= 0x010003
210   FLAC__seekable_stream_decoder_set_write_callback (flacdec->decoder,
211       gst_flacdec_write);
212 #else
213   FLAC__seekable_stream_decoder_set_write_callback (flacdec->decoder,
214       (FLAC__StreamDecoderWriteStatus (*)
215           (const FLAC__SeekableStreamDecoder * decoder,
216               const FLAC__Frame * frame,
217               const FLAC__int32 * buffer[], void *client_data))
218       (gst_flacdec_write));
219 #endif
220   FLAC__seekable_stream_decoder_set_metadata_respond (flacdec->decoder,
221       FLAC__METADATA_TYPE_VORBIS_COMMENT);
222   FLAC__seekable_stream_decoder_set_metadata_callback (flacdec->decoder,
223       gst_flacdec_metadata_callback);
224   FLAC__seekable_stream_decoder_set_error_callback (flacdec->decoder,
225       gst_flacdec_error_callback);
226   FLAC__seekable_stream_decoder_set_client_data (flacdec->decoder, flacdec);
227 }
228
229 static gboolean
230 gst_flacdec_update_metadata (FlacDec * flacdec,
231     const FLAC__StreamMetadata * metadata)
232 {
233   GstTagList *list;
234   guint32 number_of_comments, cursor, str_len;
235   gchar *p_value, *value, *name, *str_ptr;
236
237   list = gst_tag_list_new ();
238   if (list == NULL) {
239     return FALSE;
240   }
241
242   number_of_comments = metadata->data.vorbis_comment.num_comments;
243   value = NULL;
244   GST_DEBUG ("%d tag(s) found", number_of_comments);
245   for (cursor = 0; cursor < number_of_comments; cursor++) {
246     str_ptr = metadata->data.vorbis_comment.comments[cursor].entry;
247     str_len = metadata->data.vorbis_comment.comments[cursor].length;
248     p_value = g_strstr_len (str_ptr, str_len, "=");
249     if (p_value) {
250       name = g_strndup (str_ptr, p_value - str_ptr);
251       value = g_strndup (p_value + 1, str_ptr + str_len - p_value - 1);
252
253       GST_DEBUG ("%s : %s", name, value);
254       gst_vorbis_tag_add (list, name, value);
255       g_free (name);
256       g_free (value);
257     }
258   }
259
260
261   gst_element_found_tags (GST_ELEMENT (flacdec), list);
262   if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
263     gst_pad_push (flacdec->srcpad, GST_DATA (gst_event_new_tag (list)));
264   }
265   return TRUE;
266 }
267
268
269 static void
270 gst_flacdec_metadata_callback (const FLAC__SeekableStreamDecoder * decoder,
271     const FLAC__StreamMetadata * metadata, void *client_data)
272 {
273   FlacDec *flacdec;
274
275   flacdec = GST_FLACDEC (client_data);
276
277   switch (metadata->type) {
278     case FLAC__METADATA_TYPE_STREAMINFO:
279       flacdec->stream_samples = metadata->data.stream_info.total_samples;
280       break;
281     case FLAC__METADATA_TYPE_VORBIS_COMMENT:
282       gst_flacdec_update_metadata (flacdec, metadata);
283       break;
284     default:
285       break;
286   }
287 }
288
289 static void
290 gst_flacdec_error_callback (const FLAC__SeekableStreamDecoder * decoder,
291     FLAC__StreamDecoderErrorStatus status, void *client_data)
292 {
293   FlacDec *flacdec;
294   gchar *error;
295
296   flacdec = GST_FLACDEC (client_data);
297
298   switch (status) {
299     case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
300       error = "lost sync";
301       break;
302     case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
303       error = "bad header";
304       break;
305     case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
306       error = "CRC mismatch";
307       break;
308     default:
309       error = "unknown error";
310       break;
311   }
312
313   GST_ELEMENT_ERROR (flacdec, STREAM, DECODE, (NULL), (error));
314 }
315
316 static FLAC__SeekableStreamDecoderSeekStatus
317 gst_flacdec_seek (const FLAC__SeekableStreamDecoder * decoder,
318     FLAC__uint64 position, void *client_data)
319 {
320   FlacDec *flacdec;
321
322   flacdec = GST_FLACDEC (client_data);
323
324   GST_DEBUG ("seek %" G_GINT64_FORMAT, position);
325   if (!gst_bytestream_seek (flacdec->bs, position, GST_SEEK_METHOD_SET)) {
326     return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
327   }
328   return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
329 }
330
331 static FLAC__SeekableStreamDecoderTellStatus
332 gst_flacdec_tell (const FLAC__SeekableStreamDecoder * decoder,
333     FLAC__uint64 * position, void *client_data)
334 {
335   FlacDec *flacdec;
336
337   flacdec = GST_FLACDEC (client_data);
338
339   *position = gst_bytestream_tell (flacdec->bs);
340   if (*position == -1)
341     return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
342
343   GST_DEBUG ("tell %" G_GINT64_FORMAT, *position);
344
345   return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
346 }
347
348 static FLAC__SeekableStreamDecoderLengthStatus
349 gst_flacdec_length (const FLAC__SeekableStreamDecoder * decoder,
350     FLAC__uint64 * length, void *client_data)
351 {
352   FlacDec *flacdec;
353
354   flacdec = GST_FLACDEC (client_data);
355
356   *length = gst_bytestream_length (flacdec->bs);
357   if (*length == -1)
358     return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
359
360   GST_DEBUG ("length %" G_GINT64_FORMAT, *length);
361
362   return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
363 }
364
365 static FLAC__bool
366 gst_flacdec_eof (const FLAC__SeekableStreamDecoder * decoder, void *client_data)
367 {
368   FlacDec *flacdec;
369
370   flacdec = GST_FLACDEC (client_data);
371   GST_DEBUG ("eof %d", flacdec->eos);
372
373   return flacdec->eos;
374 }
375
376 static FLAC__SeekableStreamDecoderReadStatus
377 gst_flacdec_read (const FLAC__SeekableStreamDecoder * decoder,
378     FLAC__byte buffer[], unsigned *bytes, void *client_data)
379 {
380   FlacDec *flacdec;
381   gint insize = 0;
382   guint8 *indata;
383
384   flacdec = GST_FLACDEC (client_data);
385
386   //g_print ("read %u\n", *bytes);
387
388   while (insize == 0) {
389     insize = gst_bytestream_peek_bytes (flacdec->bs, &indata, *bytes);
390     if (insize < *bytes) {
391       GstEvent *event;
392       guint32 avail;
393
394       gst_bytestream_get_status (flacdec->bs, &avail, &event);
395
396       switch (GST_EVENT_TYPE (event)) {
397         case GST_EVENT_EOS:
398           GST_DEBUG ("eos");
399           flacdec->eos = TRUE;
400           gst_event_unref (event);
401           if (avail == 0) {
402             return 0;
403           }
404           break;
405         case GST_EVENT_DISCONTINUOUS:
406           GST_DEBUG ("discont");
407
408           /* we are not yet sending the discont, we'll do that in the next write operation */
409           flacdec->need_discont = TRUE;
410           gst_event_unref (event);
411           break;
412         default:
413           gst_pad_event_default (flacdec->sinkpad, event);
414           break;
415       }
416       if (avail > 0)
417         insize = gst_bytestream_peek_bytes (flacdec->bs, &indata, avail);
418       else
419         insize = 0;
420     }
421   }
422
423   memcpy (buffer, indata, insize);
424   *bytes = insize;
425   gst_bytestream_flush_fast (flacdec->bs, insize);
426
427   return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
428 }
429
430 static FLAC__StreamDecoderWriteStatus
431 gst_flacdec_write (const FLAC__SeekableStreamDecoder * decoder,
432     const FLAC__Frame * frame,
433     const FLAC__int32 * const buffer[], void *client_data)
434 {
435   FlacDec *flacdec;
436   GstBuffer *outbuf;
437   guint depth = frame->header.bits_per_sample;
438   guint channels = frame->header.channels;
439   guint samples = frame->header.blocksize;
440   guint j, i;
441
442   flacdec = GST_FLACDEC (client_data);
443
444   if (flacdec->need_discont) {
445     gint64 time = 0, bytes = 0;
446     GstFormat format;
447     GstEvent *discont;
448
449     flacdec->need_discont = FALSE;
450
451     if (!GST_PAD_CAPS (flacdec->srcpad)) {
452       if (flacdec->seek_pending) {
453         flacdec->total_samples = flacdec->seek_value;
454       }
455
456       if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
457         GST_DEBUG ("send discont");
458
459         format = GST_FORMAT_TIME;
460         gst_pad_convert (flacdec->srcpad, GST_FORMAT_DEFAULT,
461             flacdec->total_samples, &format, &time);
462         format = GST_FORMAT_BYTES;
463         gst_pad_convert (flacdec->srcpad, GST_FORMAT_DEFAULT,
464             flacdec->total_samples, &format, &bytes);
465         discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time,
466             GST_FORMAT_BYTES, bytes,
467             GST_FORMAT_DEFAULT, flacdec->total_samples, NULL);
468
469         gst_pad_push (flacdec->srcpad, GST_DATA (discont));
470       }
471     }
472   }
473
474   if (!GST_PAD_CAPS (flacdec->srcpad)) {
475     gst_pad_set_explicit_caps (flacdec->srcpad,
476         gst_caps_new_simple ("audio/x-raw-int",
477             "endianness", G_TYPE_INT, G_BYTE_ORDER,
478             "signed", G_TYPE_BOOLEAN, TRUE,
479             "width", G_TYPE_INT, depth,
480             "depth", G_TYPE_INT, depth,
481             "rate", G_TYPE_INT, frame->header.sample_rate,
482             "channels", G_TYPE_INT, channels, NULL));
483
484     flacdec->depth = depth;
485     flacdec->channels = channels;
486     flacdec->frequency = frame->header.sample_rate;
487   }
488
489   if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
490     outbuf = gst_buffer_new ();
491     GST_BUFFER_SIZE (outbuf) = samples * channels * ((depth + 7) >> 3);
492     GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
493     GST_BUFFER_TIMESTAMP (outbuf) =
494         flacdec->total_samples * GST_SECOND / frame->header.sample_rate;
495
496     if (depth == 8) {
497       guint8 *outbuffer = (guint8 *) GST_BUFFER_DATA (outbuf);
498
499       for (i = 0; i < samples; i++) {
500         for (j = 0; j < channels; j++) {
501           *outbuffer++ = (guint8) buffer[j][i];
502         }
503       }
504     } else if (depth == 16) {
505       guint16 *outbuffer = (guint16 *) GST_BUFFER_DATA (outbuf);
506
507       for (i = 0; i < samples; i++) {
508         for (j = 0; j < channels; j++) {
509           *outbuffer++ = (guint16) buffer[j][i];
510         }
511       }
512     } else {
513       g_warning ("flacdec: invalid depth %d found\n", depth);
514       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
515     }
516     gst_pad_push (flacdec->srcpad, GST_DATA (outbuf));
517   }
518   flacdec->total_samples += samples;
519
520   return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
521 }
522
523 static void
524 gst_flacdec_loop (GstElement * element)
525 {
526   FlacDec *flacdec;
527   gboolean res;
528
529   flacdec = GST_FLACDEC (element);
530
531   GST_DEBUG ("flacdec: entering loop");
532   if (flacdec->init) {
533     FLAC__StreamDecoderState res;
534
535     GST_DEBUG ("flacdec: initializing decoder");
536     res = FLAC__seekable_stream_decoder_init (flacdec->decoder);
537     if (res != FLAC__SEEKABLE_STREAM_DECODER_OK) {
538       GST_ELEMENT_ERROR (flacdec, LIBRARY, INIT, (NULL),
539           (FLAC__SeekableStreamDecoderStateString[res]));
540       return;
541     }
542     /*    FLAC__seekable_stream_decoder_process_metadata (flacdec->decoder); */
543     flacdec->init = FALSE;
544   }
545
546   if (flacdec->seek_pending) {
547     GST_DEBUG ("perform seek to sample %" G_GINT64_FORMAT, flacdec->seek_value);
548
549     if (FLAC__seekable_stream_decoder_seek_absolute (flacdec->decoder,
550             flacdec->seek_value)) {
551       flacdec->total_samples = flacdec->seek_value;
552       GST_DEBUG ("seek done");
553     } else {
554       GST_DEBUG ("seek failed");
555     }
556     flacdec->seek_pending = FALSE;
557   }
558
559   GST_DEBUG ("flacdec: processing single");
560   res = FLAC__seekable_stream_decoder_process_single (flacdec->decoder);
561   GST_DEBUG ("flacdec: checking for EOS");
562   if (FLAC__seekable_stream_decoder_get_state (flacdec->decoder) ==
563       FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
564     GstEvent *event;
565
566     GST_DEBUG ("flacdec: sending EOS event");
567     FLAC__seekable_stream_decoder_reset (flacdec->decoder);
568
569     if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
570       event = gst_event_new (GST_EVENT_EOS);
571       gst_pad_push (flacdec->srcpad, GST_DATA (event));
572     }
573     gst_element_set_eos (element);
574   }
575   GST_DEBUG ("flacdec: _loop end");
576 }
577
578
579 static const GstFormat *
580 gst_flacdec_get_src_formats (GstPad * pad)
581 {
582   static const GstFormat formats[] = {
583     GST_FORMAT_DEFAULT,
584     GST_FORMAT_BYTES,
585     GST_FORMAT_TIME,
586     0,
587   };
588   return formats;
589 }
590
591 static gboolean
592 gst_flacdec_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
593     GstFormat * dest_format, gint64 * dest_value)
594 {
595   gboolean res = TRUE;
596   FlacDec *flacdec = GST_FLACDEC (gst_pad_get_parent (pad));
597   guint scale = 1;
598   gint bytes_per_sample;
599
600   bytes_per_sample = flacdec->channels * ((flacdec->depth + 7) >> 3);
601
602   switch (src_format) {
603     case GST_FORMAT_BYTES:
604       switch (*dest_format) {
605         case GST_FORMAT_DEFAULT:
606           if (bytes_per_sample == 0)
607             return FALSE;
608           *dest_value = src_value / bytes_per_sample;
609           break;
610         case GST_FORMAT_TIME:
611         {
612           gint byterate = bytes_per_sample * flacdec->frequency;
613
614           if (byterate == 0)
615             return FALSE;
616           *dest_value = src_value * GST_SECOND / byterate;
617           break;
618         }
619         default:
620           res = FALSE;
621       }
622       break;
623     case GST_FORMAT_DEFAULT:
624       switch (*dest_format) {
625         case GST_FORMAT_BYTES:
626           *dest_value = src_value * bytes_per_sample;
627           break;
628         case GST_FORMAT_TIME:
629           if (flacdec->frequency == 0)
630             return FALSE;
631           *dest_value = src_value * GST_SECOND / flacdec->frequency;
632           break;
633         default:
634           res = FALSE;
635       }
636       break;
637     case GST_FORMAT_TIME:
638       switch (*dest_format) {
639         case GST_FORMAT_BYTES:
640           scale = bytes_per_sample;
641         case GST_FORMAT_DEFAULT:
642           *dest_value = src_value * scale * flacdec->frequency / GST_SECOND;
643           break;
644         default:
645           res = FALSE;
646       }
647       break;
648     default:
649       res = FALSE;
650   }
651   return res;
652 }
653
654 static const GstQueryType *
655 gst_flacdec_get_src_query_types (GstPad * pad)
656 {
657   static const GstQueryType types[] = {
658     GST_QUERY_TOTAL,
659     GST_QUERY_POSITION,
660     0,
661   };
662   return types;
663 }
664
665 static gboolean
666 gst_flacdec_src_query (GstPad * pad, GstQueryType type,
667     GstFormat * format, gint64 * value)
668 {
669   gboolean res = TRUE;
670   FlacDec *flacdec = GST_FLACDEC (gst_pad_get_parent (pad));
671
672   switch (type) {
673     case GST_QUERY_TOTAL:
674     {
675       guint64 samples;
676
677       if (flacdec->stream_samples == 0)
678         samples = flacdec->total_samples;
679       else
680         samples = flacdec->stream_samples;
681
682       gst_pad_convert (flacdec->srcpad,
683           GST_FORMAT_DEFAULT, samples, format, value);
684       break;
685     }
686     case GST_QUERY_POSITION:
687       gst_pad_convert (flacdec->srcpad,
688           GST_FORMAT_DEFAULT, flacdec->total_samples, format, value);
689       break;
690     default:
691       res = FALSE;
692       break;
693   }
694
695   return res;
696 }
697
698 static const GstEventMask *
699 gst_flacdec_get_src_event_masks (GstPad * pad)
700 {
701   static const GstEventMask masks[] = {
702     {GST_EVENT_SEEK, GST_SEEK_FLAG_ACCURATE},
703     {0, 0},
704   };
705   return masks;
706 }
707
708 static gboolean
709 gst_flacdec_src_event (GstPad * pad, GstEvent * event)
710 {
711   gboolean res = TRUE;
712   FlacDec *flacdec = GST_FLACDEC (gst_pad_get_parent (pad));
713   GstFormat format;
714
715   switch (GST_EVENT_TYPE (event)) {
716     case GST_EVENT_SEEK:
717       format = GST_FORMAT_DEFAULT;
718
719       if (gst_pad_convert (flacdec->srcpad,
720               GST_EVENT_SEEK_FORMAT (event),
721               GST_EVENT_SEEK_OFFSET (event), &format, &flacdec->seek_value))
722         flacdec->seek_pending = TRUE;
723       else
724         res = FALSE;
725       break;
726     default:
727       res = FALSE;
728       break;
729   }
730   gst_event_unref (event);
731   return res;
732 }
733
734 static GstElementStateReturn
735 gst_flacdec_change_state (GstElement * element)
736 {
737   FlacDec *flacdec = GST_FLACDEC (element);
738
739   switch (GST_STATE_TRANSITION (element)) {
740     case GST_STATE_NULL_TO_READY:
741     case GST_STATE_READY_TO_PAUSED:
742       flacdec->bs = gst_bytestream_new (flacdec->sinkpad);
743       flacdec->seek_pending = FALSE;
744       flacdec->total_samples = 0;
745       flacdec->eos = FALSE;
746       if (flacdec->init == FALSE) {
747         FLAC__seekable_stream_decoder_reset (flacdec->decoder);
748       }
749       break;
750     case GST_STATE_PAUSED_TO_PLAYING:
751       flacdec->eos = FALSE;
752     case GST_STATE_PLAYING_TO_PAUSED:
753       break;
754     case GST_STATE_PAUSED_TO_READY:
755       gst_bytestream_destroy (flacdec->bs);
756       break;
757     case GST_STATE_READY_TO_NULL:
758     default:
759       break;
760   }
761
762   if (GST_ELEMENT_CLASS (parent_class)->change_state)
763     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
764
765   return GST_STATE_SUCCESS;
766 }