gstflacdec.c 66.1 KB
Newer Older
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
1 2
/* GStreamer
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 4
 * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
 * Copyright (C) <2006> Jan Schmidt <thaytan at mad scientist com>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
22 23 24 25 26 27 28 29 30 31 32 33 34
/**
 * SECTION:element-flacdec
 * @seealso: flacenc
 *
 * <refsect2>
 * <para>
 * flacdec decodes FLAC streams.
 * <ulink url="http://flac.sourceforge.net/">FLAC</ulink>
 * is a Free Lossless Audio Codec.
 * </para>
 * <title>Example launch line</title>
 * <para>
 * <programlisting>
35
 * gst-launch filesrc location=media/small/dark.441-16-s.flac ! flacdec ! audioconvert ! audioresample ! autoaudiosink
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
36 37
 * </programlisting>
 * </para>
38 39 40 41 42 43
 * <title>Another example launch line</title>
 * <para>
 * <programlisting>
 * gst-launch gnomevfssrc location=http://gstreamer.freedesktop.org/media/small/dark.441-16-s.flac ! flacdec ! audioconvert ! audioresample ! queue min-threshold-buffers=10 ! autoaudiosink
 * </programlisting>
 * </para>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
44 45 46
 * </refsect2>
 */

47
/* TODO: add seeking when operating chain-based with unframed input */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
48

49 50 51
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
52 53 54
#include <string.h>

#include "gstflacdec.h"
55
#include <gst/gst-i18n-plugin.h>
56
#include <gst/gsttagsetter.h>
57
#include <gst/base/gsttypefindhelper.h>
58
#include <gst/audio/multichannel.h>
59
#include <gst/tag/tag.h>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
/* Taken from http://flac.sourceforge.net/format.html#frame_header */
static const GstAudioChannelPosition channel_positions[8][8] = {
  {GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
  {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
      GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
      GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
        GST_AUDIO_CHANNEL_POSITION_LFE,
        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
      GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
  /* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
  {
        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
        GST_AUDIO_CHANNEL_POSITION_LFE,
      GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
        GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
        GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
        GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
        GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
        GST_AUDIO_CHANNEL_POSITION_LFE,
        GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
      GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
};

103 104 105
GST_DEBUG_CATEGORY_STATIC (flacdec_debug);
#define GST_CAT_DEFAULT flacdec_debug

106 107
static void gst_flac_dec_finalize (GObject * object);
static void gst_flac_dec_loop (GstPad * pad);
108

109
static GstStateChangeReturn gst_flac_dec_change_state (GstElement * element,
110
    GstStateChange transition);
111
static const GstQueryType *gst_flac_dec_get_src_query_types (GstPad * pad);
112

113
static const GstQueryType *gst_flac_dec_get_sink_query_types (GstPad * pad);
114

115
static gboolean gst_flac_dec_sink_query (GstPad * pad, GstQuery * query);
116

117
static gboolean gst_flac_dec_src_query (GstPad * pad, GstQuery * query);
118

119
static gboolean gst_flac_dec_convert_src (GstPad * pad, GstFormat src_format,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
120
    gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
121
static gboolean gst_flac_dec_src_event (GstPad * pad, GstEvent * event);
122

123
static gboolean gst_flac_dec_sink_activate (GstPad * sinkpad);
124

125
static gboolean gst_flac_dec_sink_activate_pull (GstPad * sinkpad,
126
    gboolean active);
127 128 129
static gboolean gst_flac_dec_sink_activate_push (GstPad * sinkpad,
    gboolean active);
static gboolean gst_flac_dec_sink_event (GstPad * pad, GstEvent * event);
130

131
static GstFlowReturn gst_flac_dec_chain (GstPad * pad, GstBuffer * buf);
132

133
static void gst_flac_dec_reset_decoders (GstFlacDec * flacdec);
134

135
static void gst_flac_dec_setup_seekable_decoder (GstFlacDec * flacdec);
136

137
static void gst_flac_dec_setup_stream_decoder (GstFlacDec * flacdec);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
138

139
#ifdef LEGACY_FLAC
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
140
static FLAC__SeekableStreamDecoderReadStatus
141
gst_flac_dec_read_seekable (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
142 143
    FLAC__byte buffer[], unsigned *bytes, void *client_data);
static FLAC__SeekableStreamDecoderSeekStatus
144
gst_flac_dec_seek (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
145 146
    FLAC__uint64 position, void *client_data);
static FLAC__SeekableStreamDecoderTellStatus
147
gst_flac_dec_tell (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
148 149
    FLAC__uint64 * position, void *client_data);
static FLAC__SeekableStreamDecoderLengthStatus
150
gst_flac_dec_length (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
151
    FLAC__uint64 * length, void *client_data);
152
static FLAC__bool gst_flac_dec_eof (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
153
    void *client_data);
154 155 156
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
    FLAC__byte buffer[], unsigned *bytes, void *client_data);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
157
static FLAC__StreamDecoderWriteStatus
158
gst_flac_dec_write_seekable (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
159 160
    const FLAC__Frame * frame,
    const FLAC__int32 * const buffer[], void *client_data);
161 162 163 164 165 166 167 168
static FLAC__StreamDecoderWriteStatus
gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
    const FLAC__Frame * frame,
    const FLAC__int32 * const buffer[], void *client_data);
static void gst_flac_dec_metadata_callback_seekable (const
    FLAC__SeekableStreamDecoder * decoder,
    const FLAC__StreamMetadata * metadata, void *client_data);
static void gst_flac_dec_metadata_callback_stream (const FLAC__StreamDecoder *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
169
    decoder, const FLAC__StreamMetadata * metadata, void *client_data);
170 171 172 173 174 175
static void gst_flac_dec_metadata_callback (GstFlacDec * flacdec,
    const FLAC__StreamMetadata * metadata);
static void gst_flac_dec_error_callback_seekable (const
    FLAC__SeekableStreamDecoder * decoder,
    FLAC__StreamDecoderErrorStatus status, void *client_data);
static void gst_flac_dec_error_callback_stream (const FLAC__StreamDecoder *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
176
    decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
#else
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_seekable (const FLAC__StreamDecoder * decoder,
    FLAC__byte buffer[], size_t * bytes, void *client_data);
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
    FLAC__byte buffer[], size_t * bytes, void *client_data);
static FLAC__StreamDecoderSeekStatus
gst_flac_dec_seek (const FLAC__StreamDecoder * decoder,
    FLAC__uint64 position, void *client_data);
static FLAC__StreamDecoderTellStatus
gst_flac_dec_tell (const FLAC__StreamDecoder * decoder,
    FLAC__uint64 * position, void *client_data);
static FLAC__StreamDecoderLengthStatus
gst_flac_dec_length (const FLAC__StreamDecoder * decoder,
    FLAC__uint64 * length, void *client_data);
static FLAC__bool gst_flac_dec_eof (const FLAC__StreamDecoder * decoder,
    void *client_data);
static FLAC__StreamDecoderWriteStatus
gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
    const FLAC__Frame * frame,
    const FLAC__int32 * const buffer[], void *client_data);
static void gst_flac_dec_metadata_callback_stream (const FLAC__StreamDecoder *
    decoder, const FLAC__StreamMetadata * metadata, void *client_data);
static void gst_flac_dec_error_callback_stream (const FLAC__StreamDecoder *
    decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
204

205
GST_BOILERPLATE (GstFlacDec, gst_flac_dec, GstElement, GST_TYPE_ELEMENT);
206 207 208 209

/* FIXME 0.11: Use width=32 for all depths and let audioconvert
 * handle the conversions instead of doing it ourself.
 */
210 211 212 213 214 215
static const GstElementDetails vorbis_dec_details =
GST_ELEMENT_DETAILS ("Vorbis audio decoder",
    "Codec/Decoder/Audio",
    "decode raw vorbis streams to float audio",
    "Benjamin Otte <in7y118@public.uni-hamburg.de>");

216 217
#define GST_FLAC_DEC_SRC_CAPS                             \
    "audio/x-raw-int, "                                   \
218
    "endianness = (int) BYTE_ORDER, "                     \
219 220
    "signed = (boolean) true, "                           \
    "width = (int) { 8, 16, 32 }, "                       \
221 222
    "depth = (int) [ 4, 32 ], "                           \
    "rate = (int) [ 1, 655350 ], "                        \
223
    "channels = (int) [ 1, 8 ]"
224 225 226 227 228 229 230 231 232 233 234 235 236

static GstStaticPadTemplate flac_dec_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS (GST_FLAC_DEC_SRC_CAPS));
static GstStaticPadTemplate flac_dec_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/x-flac")
    );

237 238
static void
gst_flac_dec_base_init (gpointer g_class)
239 240
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
241

242 243 244 245
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&flac_dec_src_factory));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&flac_dec_sink_factory));
246 247 248
  gst_element_class_set_details_simple (element_class, "FLAC audio decoder",
      "Codec/Decoder/Audio",
      "Decodes FLAC lossless audio streams", "Wim Taymans <wim@fluendo.com>");
249 250

  GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
251 252
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
253
static void
254
gst_flac_dec_class_init (GstFlacDecClass * klass)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
255 256
{
  GstElementClass *gstelement_class;
257

Jeremy Simon's avatar
Jeremy Simon committed
258
  GObjectClass *gobject_class;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
259

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
260 261
  gstelement_class = (GstElementClass *) klass;
  gobject_class = (GObjectClass *) klass;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
262

263
  gobject_class->finalize = gst_flac_dec_finalize;
264

265 266
  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_flac_dec_change_state);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
267 268
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
269
static void
270
gst_flac_dec_init (GstFlacDec * flacdec, GstFlacDecClass * klass)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
271
{
272 273
  flacdec->sinkpad =
      gst_pad_new_from_static_template (&flac_dec_sink_factory, "sink");
274 275
  gst_pad_set_activate_function (flacdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate));
276
  gst_pad_set_activatepull_function (flacdec->sinkpad,
277
      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate_pull));
278 279 280 281 282 283 284 285 286 287
  gst_pad_set_activatepush_function (flacdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate_push));
  gst_pad_set_query_type_function (flacdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_get_sink_query_types));
  gst_pad_set_query_function (flacdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_query));
  gst_pad_set_event_function (flacdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_event));
  gst_pad_set_chain_function (flacdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_chain));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
288 289
  gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->sinkpad);

290 291
  flacdec->srcpad =
      gst_pad_new_from_static_template (&flac_dec_src_factory, "src");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
292
  gst_pad_set_query_type_function (flacdec->srcpad,
293 294 295 296 297
      GST_DEBUG_FUNCPTR (gst_flac_dec_get_src_query_types));
  gst_pad_set_query_function (flacdec->srcpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_src_query));
  gst_pad_set_event_function (flacdec->srcpad,
      GST_DEBUG_FUNCPTR (gst_flac_dec_src_event));
298 299
  gst_pad_use_fixed_caps (flacdec->srcpad);
  gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->srcpad);
300

301 302 303 304 305 306 307
  gst_flac_dec_reset_decoders (flacdec);
}

static void
gst_flac_dec_reset_decoders (GstFlacDec * flacdec)
{
  if (flacdec->seekable_decoder) {
308
#ifdef LEGACY_FLAC
309
    FLAC__seekable_stream_decoder_delete (flacdec->seekable_decoder);
310 311 312
#else
    FLAC__stream_decoder_delete (flacdec->seekable_decoder);
#endif
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    flacdec->seekable_decoder = NULL;
  }

  /* Clean up the stream_decoder */
  if (flacdec->stream_decoder) {
    FLAC__stream_decoder_delete (flacdec->stream_decoder);
    flacdec->stream_decoder = NULL;
  }

  if (flacdec->adapter) {
    gst_adapter_clear (flacdec->adapter);
    g_object_unref (flacdec->adapter);
    flacdec->adapter = NULL;
  }

328 329 330 331 332 333 334 335 336 337 338 339 340
  if (flacdec->close_segment) {
    gst_event_unref (flacdec->close_segment);
    flacdec->close_segment = NULL;
  }
  if (flacdec->start_segment) {
    gst_event_unref (flacdec->start_segment);
    flacdec->start_segment = NULL;
  }
  if (flacdec->tags) {
    gst_tag_list_free (flacdec->tags);
    flacdec->tags = NULL;
  }

341
  flacdec->segment.last_stop = 0;
342
  flacdec->offset = 0;
343
  flacdec->init = TRUE;
344 345 346 347 348 349
}

static void
gst_flac_dec_setup_seekable_decoder (GstFlacDec * dec)
{
  gst_flac_dec_reset_decoders (dec);
350

351 352 353 354
  dec->tags = gst_tag_list_new ();
  gst_tag_list_add (dec->tags, GST_TAG_MERGE_REPLACE,
      GST_TAG_AUDIO_CODEC, "FLAC", NULL);

355
#ifdef LEGACY_FLAC
356 357 358 359 360
  dec->seekable_decoder = FLAC__seekable_stream_decoder_new ();

  FLAC__seekable_stream_decoder_set_read_callback (dec->seekable_decoder,
      gst_flac_dec_read_seekable);
  FLAC__seekable_stream_decoder_set_seek_callback (dec->seekable_decoder,
361
      gst_flac_dec_seek);
362
  FLAC__seekable_stream_decoder_set_tell_callback (dec->seekable_decoder,
363
      gst_flac_dec_tell);
364
  FLAC__seekable_stream_decoder_set_length_callback (dec->seekable_decoder,
365
      gst_flac_dec_length);
366
  FLAC__seekable_stream_decoder_set_eof_callback (dec->seekable_decoder,
367
      gst_flac_dec_eof);
368 369 370 371 372 373 374 375 376
  FLAC__seekable_stream_decoder_set_write_callback (dec->seekable_decoder,
      gst_flac_dec_write_seekable);
  FLAC__seekable_stream_decoder_set_metadata_respond (dec->seekable_decoder,
      FLAC__METADATA_TYPE_VORBIS_COMMENT);
  FLAC__seekable_stream_decoder_set_metadata_callback (dec->seekable_decoder,
      gst_flac_dec_metadata_callback_seekable);
  FLAC__seekable_stream_decoder_set_error_callback (dec->seekable_decoder,
      gst_flac_dec_error_callback_seekable);
  FLAC__seekable_stream_decoder_set_client_data (dec->seekable_decoder, dec);
377 378 379 380
#else
  dec->seekable_decoder = FLAC__stream_decoder_new ();
  FLAC__stream_decoder_set_metadata_respond (dec->seekable_decoder,
      FLAC__METADATA_TYPE_VORBIS_COMMENT);
381 382
  FLAC__stream_decoder_set_metadata_respond (dec->seekable_decoder,
      FLAC__METADATA_TYPE_PICTURE);
383 384
  FLAC__stream_decoder_set_md5_checking (dec->seekable_decoder, false); /* no point calculating since it's never checked here */
#endif
385 386 387 388 389 390 391
}

static void
gst_flac_dec_setup_stream_decoder (GstFlacDec * dec)
{
  gst_flac_dec_reset_decoders (dec);

392 393 394 395
  dec->tags = gst_tag_list_new ();
  gst_tag_list_add (dec->tags, GST_TAG_MERGE_REPLACE,
      GST_TAG_AUDIO_CODEC, "FLAC", NULL);

396 397 398 399
  dec->adapter = gst_adapter_new ();

  dec->stream_decoder = FLAC__stream_decoder_new ();

400
#ifdef LEGACY_FLAC
401 402 403 404 405
  FLAC__stream_decoder_set_read_callback (dec->stream_decoder,
      gst_flac_dec_read_stream);
  FLAC__stream_decoder_set_write_callback (dec->stream_decoder,
      gst_flac_dec_write_stream);
  FLAC__stream_decoder_set_metadata_respond (dec->stream_decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
406
      FLAC__METADATA_TYPE_VORBIS_COMMENT);
407 408 409 410 411
  FLAC__stream_decoder_set_metadata_callback (dec->stream_decoder,
      gst_flac_dec_metadata_callback_stream);
  FLAC__stream_decoder_set_error_callback (dec->stream_decoder,
      gst_flac_dec_error_callback_stream);
  FLAC__stream_decoder_set_client_data (dec->stream_decoder, dec);
412 413 414 415
#else
  FLAC__stream_decoder_set_md5_checking (dec->stream_decoder, false);   /* no point calculating since it's never checked here */
  FLAC__stream_decoder_set_metadata_respond (dec->stream_decoder,
      FLAC__METADATA_TYPE_VORBIS_COMMENT);
416 417
  FLAC__stream_decoder_set_metadata_respond (dec->stream_decoder,
      FLAC__METADATA_TYPE_PICTURE);
418
#endif
419
}
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
420

Colin Walters's avatar
Colin Walters committed
421
static void
422
gst_flac_dec_finalize (GObject * object)
Colin Walters's avatar
Colin Walters committed
423
{
424
  GstFlacDec *flacdec;
Colin Walters's avatar
Colin Walters committed
425

426
  flacdec = GST_FLAC_DEC (object);
Colin Walters's avatar
Colin Walters committed
427

428
  gst_flac_dec_reset_decoders (flacdec);
Colin Walters's avatar
Colin Walters committed
429

430
  G_OBJECT_CLASS (parent_class)->finalize (object);
Colin Walters's avatar
Colin Walters committed
431 432 433
}


434
static gboolean
435
gst_flac_dec_update_metadata (GstFlacDec * flacdec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
436
    const FLAC__StreamMetadata * metadata)
437
{
438
  GstTagList *list;
439
  guint num, i;
440

441 442 443 444
  if (flacdec->tags)
    list = flacdec->tags;
  else
    flacdec->tags = list = gst_tag_list_new ();
445

446 447 448 449 450 451 452 453
  num = metadata->data.vorbis_comment.num_comments;
  GST_DEBUG ("%u tag(s) found", num);

  for (i = 0; i < num; ++i) {
    gchar *vc, *name, *value;

    vc = g_strndup ((gchar *) metadata->data.vorbis_comment.comments[i].entry,
        metadata->data.vorbis_comment.comments[i].length);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
454

455
    if (gst_tag_parse_extended_comment (vc, &name, NULL, &value, TRUE)) {
456
      GST_DEBUG ("%s : %s", name, value);
457
      gst_vorbis_tag_add (list, name, value);
458 459 460
      g_free (name);
      g_free (value);
    }
461 462

    g_free (vc);
463
  }
464

465 466 467
  return TRUE;
}

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
static const guint8 crc8_table[256] = {
  0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
  0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
  0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
  0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
  0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
  0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
  0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
  0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
  0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
  0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
  0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
  0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
  0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
  0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
  0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
  0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
  0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
  0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
  0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
  0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
  0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
  0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
  0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
  0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
  0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
  0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
  0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
  0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
  0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
  0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
  0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
  0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
};

static guint8
gst_flac_calculate_crc8 (guint8 * data, guint length)
{
  guint8 crc = 0;

  while (length--) {
    crc = crc8_table[crc ^ *data];
    ++data;
  }

  return crc;
}

static gboolean
gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size,
    gint64 * last_sample_num)
{
  guint headerlen;
  guint sr_from_end = 0;        /* can be 0, 8 or 16 */
  guint bs_from_end = 0;        /* can be 0, 8 or 16 */
  guint32 val = 0;
  guint8 bs, sr, ca, ss, pb;

  if (size < 10)
    return FALSE;

  /* sync */
  if (data[0] != 0xFF || data[1] != 0xF8)
    return FALSE;

  bs = (data[2] & 0xF0) >> 8;   /* blocksize marker   */
  sr = (data[2] & 0x0F);        /* samplerate marker  */
  ca = (data[3] & 0xF0) >> 8;   /* channel assignment */
  ss = (data[3] & 0x0F) >> 1;   /* sample size marker */
  pb = (data[3] & 0x01);        /* padding bit        */

  GST_LOG ("got sync, bs=%x,sr=%x,ca=%x,ss=%x,pb=%x", bs, sr, ca, ss, pb);

  if (sr == 0x0F || sr == 0x01 || sr == 0x02 || sr == 0x03 ||
      ca >= 0x0B || ss == 0x03 || ss == 0x07) {
    return FALSE;
  }

  /* read block size from end of header? */
  if (bs == 6)
    bs_from_end = 8;
  else if (bs == 7)
    bs_from_end = 16;

  /* read sample rate from end of header? */
  if (sr == 0x0C)
    sr_from_end = 8;
  else if (sr == 0x0D || sr == 0x0E)
    sr_from_end = 16;

  val = (guint32) g_utf8_get_char_validated ((gchar *) data + 4, -1);

  if (val == (guint32) - 1 || val == (guint32) - 2) {
    GST_LOG_OBJECT (flacdec, "failed to read sample/frame");
    return FALSE;
  }

  headerlen = 4 + g_unichar_to_utf8 ((gunichar) val, NULL) +
      (bs_from_end / 8) + (sr_from_end / 8);

  if (gst_flac_calculate_crc8 (data, headerlen) != data[headerlen])
    return FALSE;

  if (flacdec->min_blocksize == flacdec->max_blocksize) {
    *last_sample_num = (val + 1) * flacdec->min_blocksize;
  } else {
    *last_sample_num = val;     /* FIXME: + length of last block in samples */
  }

578 579 580 581 582
  if (flacdec->sample_rate > 0) {
    GST_DEBUG_OBJECT (flacdec, "last sample %" G_GINT64_FORMAT " = %"
        GST_TIME_FORMAT, *last_sample_num,
        GST_TIME_ARGS (*last_sample_num * GST_SECOND / flacdec->sample_rate));
  }
583 584 585 586 587 588 589 590 591 592

  return TRUE;
}

#define SCANBLOCK_SIZE  (64*1024)

static void
gst_flac_dec_scan_for_last_block (GstFlacDec * flacdec, gint64 * samples)
{
  GstFormat format = GST_FORMAT_BYTES;
593

594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
  gint64 file_size, offset;

  GST_INFO_OBJECT (flacdec, "total number of samples unknown, scanning file");

  if (!gst_pad_query_peer_duration (flacdec->sinkpad, &format, &file_size)) {
    GST_WARNING_OBJECT (flacdec, "failed to query upstream size!");
    return;
  }

  GST_DEBUG_OBJECT (flacdec, "upstream size: %" G_GINT64_FORMAT, file_size);

  offset = file_size - 1;
  while (offset >= MAX (SCANBLOCK_SIZE / 2, file_size / 2)) {
    GstFlowReturn flow;
    GstBuffer *buf = NULL;
    guint8 *data;
    guint size;

    /* divide by 2 = not very sophisticated way to deal with overlapping */
    offset -= SCANBLOCK_SIZE / 2;
    GST_LOG_OBJECT (flacdec, "looking for frame at %" G_GINT64_FORMAT
        "-%" G_GINT64_FORMAT, offset, offset + SCANBLOCK_SIZE);

    flow = gst_pad_pull_range (flacdec->sinkpad, offset, SCANBLOCK_SIZE, &buf);
    if (flow != GST_FLOW_OK) {
      GST_DEBUG_OBJECT (flacdec, "flow = %s", gst_flow_get_name (flow));
      return;
    }

    size = GST_BUFFER_SIZE (buf);
    data = GST_BUFFER_DATA (buf);

    while (size > 16) {
      if (gst_flac_dec_scan_got_frame (flacdec, data, size, samples)) {
        GST_DEBUG_OBJECT (flacdec, "frame sync at offset %" G_GINT64_FORMAT,
            offset + GST_BUFFER_SIZE (buf) - size);
        gst_buffer_unref (buf);
        return;
      }
      ++data;
      --size;
    }

    gst_buffer_unref (buf);
  }
}
640

641 642
/* FIXME: remove ifndef once we depend on flac >= 1.2.x */
#ifndef LEGACY_FLAC
643
static void
644
gst_flac_extract_picture_buffer (GstFlacDec * dec,
645 646 647
    const FLAC__StreamMetadata * metadata)
{
  FLAC__StreamMetadata_Picture picture;
648
  GstTagList *tags;
649 650 651 652 653 654

  g_return_if_fail (metadata->type == FLAC__METADATA_TYPE_PICTURE);

  GST_LOG ("Got PICTURE block");
  picture = metadata->data.picture;

655
  GST_DEBUG ("declared MIME type is: '%s'", GST_STR_NULL (picture.mime_type));
656 657
  GST_DEBUG ("image data is %u bytes", picture.data_length);

658
  tags = gst_tag_list_new ();
659

660 661
  gst_tag_list_add_id3_image (tags, (guint8 *) picture.data,
      picture.data_length, picture.type);
662

663 664
  if (!gst_tag_list_is_empty (tags)) {
    gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, tags);
665 666
  } else {
    GST_DEBUG ("problem parsing PICTURE block, skipping");
667
    gst_tag_list_free (tags);
668 669
  }
}
670
#endif /* LEGACY_FLAC */
671

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
672
static void
673 674
gst_flac_dec_metadata_callback (GstFlacDec * flacdec,
    const FLAC__StreamMetadata * metadata)
675
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
676
  switch (metadata->type) {
677 678 679 680 681 682 683 684
    case FLAC__METADATA_TYPE_STREAMINFO:{
      gint64 samples;

      samples = metadata->data.stream_info.total_samples;

      flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
      flacdec->max_blocksize = metadata->data.stream_info.max_blocksize;
      flacdec->sample_rate = metadata->data.stream_info.sample_rate;
685
      flacdec->depth = metadata->data.stream_info.bits_per_sample;
686 687 688 689

      GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
          flacdec->min_blocksize, flacdec->max_blocksize);

690 691
      /* Only scan for last block in pull-mode, since it uses pull_range() */
      if (samples == 0 && flacdec->seekable_decoder) {
692 693 694 695 696 697
        gst_flac_dec_scan_for_last_block (flacdec, &samples);
      }

      GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples);

      if (samples > 0) {
698 699
        gint64 duration;

700 701
        gst_segment_set_duration (&flacdec->segment, GST_FORMAT_DEFAULT,
            samples);
702 703 704 705 706 707 708 709 710 711 712 713 714

        /* convert duration to time */
        duration = gst_util_uint64_scale_int (samples, GST_SECOND,
            flacdec->sample_rate);

        /* fixme, at this time we could seek to the queued seek event if we have
         * any */
        if (flacdec->start_segment)
          gst_event_unref (flacdec->start_segment);
        flacdec->start_segment =
            gst_event_new_new_segment_full (FALSE,
            flacdec->segment.rate, flacdec->segment.applied_rate,
            GST_FORMAT_TIME, 0, duration, 0);
715
      }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
716
      break;
717
    }
718

719 720
/* FIXME: remove ifndef once we depend on flac >= 1.2.x */
#ifndef LEGACY_FLAC
721 722 723 724
    case FLAC__METADATA_TYPE_PICTURE:{
      gst_flac_extract_picture_buffer (flacdec, metadata);
      break;
    }
725
#endif
726
    case FLAC__METADATA_TYPE_VORBIS_COMMENT:
727
      gst_flac_dec_update_metadata (flacdec, metadata);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
728
      break;
729
    default:
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
730
      break;
731
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
732 733
}

734
#ifdef LEGACY_FLAC
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
735
static void
736 737
gst_flac_dec_metadata_callback_seekable (const FLAC__SeekableStreamDecoder * d,
    const FLAC__StreamMetadata * metadata, void *client_data)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
738
{
739
  GstFlacDec *dec = GST_FLAC_DEC (client_data);
740

741 742
  gst_flac_dec_metadata_callback (dec, metadata);
}
743
#endif
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758

static void
gst_flac_dec_metadata_callback_stream (const FLAC__StreamDecoder * decoder,
    const FLAC__StreamMetadata * metadata, void *client_data)
{
  GstFlacDec *dec = GST_FLAC_DEC (client_data);

  gst_flac_dec_metadata_callback (dec, metadata);
}

static void
gst_flac_dec_error_callback (GstFlacDec * dec,
    FLAC__StreamDecoderErrorStatus status)
{
  const gchar *error;
759 760

  switch (status) {
761
    case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
762 763
      /* Ignore this error and keep processing */
      return;
764
    case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
765 766
      error = "bad header";
      break;
767
    case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
768 769 770
      error = "CRC mismatch";
      break;
    default:
Johan Dahlin's avatar
Johan Dahlin committed
771
      error = "unknown error";
772 773 774
      break;
  }

775 776 777 778
  GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status));
  dec->last_flow = GST_FLOW_ERROR;
}

779
#ifdef LEGACY_FLAC
780 781 782 783 784 785
static void
gst_flac_dec_error_callback_seekable (const FLAC__SeekableStreamDecoder * d,
    FLAC__StreamDecoderErrorStatus status, void *client_data)
{
  gst_flac_dec_error_callback (GST_FLAC_DEC (client_data), status);
}
786
#endif
787 788 789 790 791 792

static void
gst_flac_dec_error_callback_stream (const FLAC__StreamDecoder * d,
    FLAC__StreamDecoderErrorStatus status, void *client_data)
{
  gst_flac_dec_error_callback (GST_FLAC_DEC (client_data), status);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
793 794
}

795
#ifdef LEGACY_FLAC
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
796
static FLAC__SeekableStreamDecoderSeekStatus
797
gst_flac_dec_seek (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
798
    FLAC__uint64 position, void *client_data)
799 800 801 802 803
#else
static FLAC__StreamDecoderSeekStatus
gst_flac_dec_seek (const FLAC__StreamDecoder * decoder,
    FLAC__uint64 position, void *client_data)
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
804
{
805
  GstFlacDec *flacdec;
806

807
  flacdec = GST_FLAC_DEC (client_data);
808

809
  GST_DEBUG ("seek %" G_GINT64_FORMAT, position);
810 811
  flacdec->offset = position;

812
#ifdef LEGACY_FLAC
813
  return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
814 815 816
#else
  return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
817 818
}

819
#ifdef LEGACY_FLAC
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
820
static FLAC__SeekableStreamDecoderTellStatus
821
gst_flac_dec_tell (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
822
    FLAC__uint64 * position, void *client_data)
823 824 825 826 827
#else
static FLAC__StreamDecoderTellStatus
gst_flac_dec_tell (const FLAC__StreamDecoder * decoder,
    FLAC__uint64 * position, void *client_data)
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
828
{
829
  GstFlacDec *flacdec;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
830

831
  flacdec = GST_FLAC_DEC (client_data);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
832

833
  *position = flacdec->offset;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
834

835
  GST_DEBUG ("tell %" G_GINT64_FORMAT, *position);
836

837
#ifdef LEGACY_FLAC
838
  return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
839 840 841
#else
  return FLAC__STREAM_DECODER_TELL_STATUS_OK;
#endif
842 843
}

844
#ifdef LEGACY_FLAC
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
845
static FLAC__SeekableStreamDecoderLengthStatus
846
gst_flac_dec_length (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
847
    FLAC__uint64 * length, void *client_data)
848 849 850 851 852
#else
static FLAC__StreamDecoderLengthStatus
gst_flac_dec_length (const FLAC__StreamDecoder * decoder,
    FLAC__uint64 * length, void *client_data)
#endif
853
{
854
  GstFlacDec *flacdec;
855 856 857
  GstFormat fmt = GST_FORMAT_BYTES;
  gint64 len;
  GstPad *peer;
858

859
  flacdec = GST_FLAC_DEC (client_data);
860

861
  if (!(peer = gst_pad_get_peer (flacdec->sinkpad)))
862
#ifdef LEGACY_FLAC
863
    return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
864 865 866
#else
    return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
#endif
Wim Taymans's avatar
Wim Taymans committed
867
  gst_pad_query_duration (peer, &fmt, &len);
868 869
  gst_object_unref (peer);
  if (fmt != GST_FORMAT_BYTES || len == -1)
870
#ifdef LEGACY_FLAC
871
    return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
872 873 874
#else
    return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
#endif
875 876

  *length = len;
877

878
  GST_DEBUG ("length %" G_GINT64_FORMAT, *length);
879

880
#ifdef LEGACY_FLAC
881
  return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
882 883 884
#else
  return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
#endif
885 886
}

887
#ifdef LEGACY_FLAC
888
static FLAC__bool
889 890
gst_flac_dec_eof (const FLAC__SeekableStreamDecoder * decoder,
    void *client_data)
891 892 893 894
#else
static FLAC__bool
gst_flac_dec_eof (const FLAC__StreamDecoder * decoder, void *client_data)
#endif
895
{
896
  GstFlacDec *flacdec;
897 898 899 900
  GstFormat fmt;
  GstPad *peer;
  gboolean ret = FALSE;
  gint64 len;
901

902
  flacdec = GST_FLAC_DEC (client_data);
903

904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
  if (!(peer = gst_pad_get_peer (flacdec->sinkpad))) {
    GST_WARNING_OBJECT (flacdec, "no peer pad, returning EOF");
    return TRUE;
  }

  fmt = GST_FORMAT_BYTES;
  if (gst_pad_query_duration (peer, &fmt, &len) && fmt == GST_FORMAT_BYTES &&
      len != -1 && flacdec->offset >= len) {
    GST_DEBUG ("offset=%" G_GINT64_FORMAT ", len=%" G_GINT64_FORMAT
        ", returning EOF", flacdec->offset, len);
    ret = TRUE;
  }

  gst_object_unref (peer);

  return ret;
920 921
}

922
#ifdef LEGACY_FLAC
923
static FLAC__SeekableStreamDecoderReadStatus
924
gst_flac_dec_read_seekable (const FLAC__SeekableStreamDecoder * decoder,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
925
    FLAC__byte buffer[], unsigned *bytes, void *client_data)
926 927 928 929 930
#else
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_seekable (const FLAC__StreamDecoder * decoder,
    FLAC__byte buffer[], size_t * bytes, void *client_data)
#endif
931
{
932
  GstFlacDec *flacdec;
933

934
  GstBuffer *buf;
935

936
  flacdec = GST_FLAC_DEC (client_data);
937

938 939
  if (gst_pad_pull_range (flacdec->sinkpad, flacdec->offset, *bytes,
          &buf) != GST_FLOW_OK)
940
#ifdef LEGACY_FLAC
941
    return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
942 943 944
#else
    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
945

946 947 948 949 950 951
  GST_DEBUG ("Read %d bytes at %" G_GUINT64_FORMAT,
      GST_BUFFER_SIZE (buf), flacdec->offset);
  memcpy (buffer, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
  *bytes = GST_BUFFER_SIZE (buf);
  gst_buffer_unref (buf);
  flacdec->offset += *bytes;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
952

953
#ifdef LEGACY_FLAC
954
  return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
955 956 957
#else
  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
958 959
}

960
#ifdef LEGACY_FLAC
961 962 963
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
    FLAC__byte buffer[], unsigned *bytes, void *client_data)
964 965 966 967 968
#else
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
    FLAC__byte buffer[], size_t * bytes, void *client_data)
#endif
969 970 971 972 973 974 975 976 977 978 979 980
{
  GstFlacDec *dec = GST_FLAC_DEC (client_data);
  guint len;

  len = MIN (gst_adapter_available (dec->adapter), *bytes);

  if (len == 0) {
    GST_LOG_OBJECT (dec, "0 bytes available at the moment");
    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
  }

  GST_LOG_OBJECT (dec, "feeding %u bytes to decoder (available=%u, bytes=%u)",
981
      len, gst_adapter_available (dec->adapter), (guint) * bytes);
982 983 984 985 986 987 988 989
  memcpy (buffer, gst_adapter_peek (dec->adapter, len), len);
  *bytes = len;

  gst_adapter_flush (dec->adapter, len);

  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
990
static FLAC__StreamDecoderWriteStatus
991 992
gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
    const FLAC__int32 * const buffer[])
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
993
{
994
  GstFlowReturn ret = GST_FLOW_OK;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
995 996
  GstBuffer *outbuf;
  guint depth = frame->header.bits_per_sample;
997
  guint width;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
998 999 1000
  guint channels = frame->header.channels;
  guint samples = frame->header.blocksize;
  guint j, i;
1001
  GstClockTime next;
1002

1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
  switch (depth) {
    case 8:
      width = 8;
      break;
    case 12:
    case 16:
      width = 16;
      break;
    case 20:
    case 24:
    case 32:
      width = 32;
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
      break;
    case 0:
      if (flacdec->depth < 4 || flacdec->depth > 32) {
        GST_ERROR_OBJECT (flacdec, "unsupported depth %d from STREAMINFO",
            flacdec->depth);
        ret = GST_FLOW_ERROR;
        goto done;
      }

      depth = flacdec->depth;
      if (depth < 9)
        width = 8;
      else if (depth < 17)
        width = 16;
      else
        width = 32;

1032 1033
      break;
    default:
1034 1035 1036
      GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth);
      ret = GST_FLOW_ERROR;
      goto done;
1037
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
1038