gstfaad.c 24.7 KB
Newer Older
1 2
/* GStreamer FAAD (Free AAC Decoder) plugin
 * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3
 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
17 18
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
19 20
 */

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
21 22 23 24 25 26 27 28
/**
 * SECTION:element-faad
 * @seealso: faac
 *
 * faad decodes AAC (MPEG-4 part 3) stream.
 *
 * <refsect2>
 * <title>Example launch lines</title>
Stefan Kost's avatar
Stefan Kost committed
29
 * |[
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
30
 * gst-launch filesrc location=example.mp4 ! qtdemux ! faad ! audioconvert ! audioresample ! autoaudiosink
Stefan Kost's avatar
Stefan Kost committed
31 32
 * ]| Play aac from mp4 file.
 * |[
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
33
 * gst-launch filesrc location=example.adts ! faad ! audioconvert ! audioresample ! autoaudiosink
Stefan Kost's avatar
Stefan Kost committed
34
 * ]| Play standalone aac bitstream.
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
35 36 37
 * </refsect2>
 */

38 39 40 41 42
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>
43
#include <gst/audio/audio.h>
44

45 46
/* These are the correct types for these functions, as defined in the source,
 * with types changed to match glib types, since those are defined for us.
47 48
 * However, upstream FAAD is distributed with a broken header file that defined
 * these wrongly (in a way which was broken on 64 bit systems).
49
 *
50
 * Upstream CVS still has the bug, but has also renamed all the public symbols
51 52
 * for Better Corporate Branding (or whatever), so we need to take that
 * (FAAD_IS_NEAAC) into account as well.
53 54 55
 *
 * We must call them using these definitions. Most distributions now have the
 * corrected header file (they distribute a patch along with the source), 
56 57 58 59
 * but not all, hence this Truly Evil Hack.
 *
 * Note: The prototypes don't need to be defined conditionaly, as the cpp will
 * do that for us.
60
 */
61
#if FAAD2_MINOR_VERSION < 7
62 63 64 65
#ifdef FAAD_IS_NEAAC
#define NeAACDecInit NeAACDecInit_no_definition
#define NeAACDecInit2 NeAACDecInit2_no_definition
#else
66 67
#define faacDecInit faacDecInit_no_definition
#define faacDecInit2 faacDecInit2_no_definition
68
#endif
69 70
#endif /* FAAD2_MINOR_VERSION < 7 */

71
#include "gstfaad.h"
72 73

#if FAAD2_MINOR_VERSION < 7
74 75 76 77
#ifdef FAAD_IS_NEAAC
#undef NeAACDecInit
#undef NeAACDecInit2
#else
78 79
#undef faacDecInit
#undef faacDecInit2
80
#endif
81

82
extern long faacDecInit (faacDecHandle, guint8 *, guint32, guint32 *, guint8 *);
LRN's avatar
LRN committed
83
extern gint8 faacDecInit2 (faacDecHandle, guint8 *, guint32,
84
    guint32 *, guint8 *);
85

86 87
#endif /* FAAD2_MINOR_VERSION < 7 */

88 89 90
GST_DEBUG_CATEGORY_STATIC (faad_debug);
#define GST_CAT_DEFAULT faad_debug

Ronald S. Bultje's avatar
Ronald S. Bultje committed
91
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
92 93
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
94 95
    GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 2; "
        "audio/mpeg, mpegversion = (int) 4, stream-format = (string) { raw, adts }")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
96 97
    );

Wim Taymans's avatar
Wim Taymans committed
98 99 100
#define STATIC_RAW_CAPS(format) \
  "audio/x-raw, " \
    "format = (string) "GST_AUDIO_NE(format)", " \
101
    "layout = (string) interleaved, " \
Ronald S. Bultje's avatar
Ronald S. Bultje committed
102 103 104 105 106 107 108 109 110 111 112 113
    "rate = (int) [ 8000, 96000 ], " \
    "channels = (int) [ 1, 8 ]"

/*
 * All except 16-bit integer are disabled until someone fixes FAAD.
 * FAAD allocates approximately 8*1024*2 bytes bytes, which is enough
 * for 1 frame (1024 samples) of 6 channel (5.1) 16-bit integer 16bpp
 * audio, but not for any other. You'll get random segfaults, crashes
 * and even valgrind goes crazy.
 */

#define STATIC_CAPS \
Wim Taymans's avatar
Wim Taymans committed
114
  STATIC_RAW_CAPS (S16)
Ronald S. Bultje's avatar
Ronald S. Bultje committed
115
#if 0
116
#define NOTUSED "; " \
Wim Taymans's avatar
Wim Taymans committed
117
STATIC_RAW_CAPS (S24) \
118
    "; " \
Wim Taymans's avatar
Wim Taymans committed
119
STATIC_RAW_CAPS (S32) \
120
    "; " \
Wim Taymans's avatar
Wim Taymans committed
121
STATIC_RAW_CAPS (F32) \
122
    "; " \
Wim Taymans's avatar
Wim Taymans committed
123
STATIC_RAW_CAPS (F64)
Ronald S. Bultje's avatar
Ronald S. Bultje committed
124
#endif
125

126
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
127 128
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
129
    GST_STATIC_CAPS (STATIC_CAPS)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
130 131
    );

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
132
static void gst_faad_reset (GstFaad * faad);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
133 134 135 136 137 138 139 140 141 142

static gboolean gst_faad_start (GstAudioDecoder * dec);
static gboolean gst_faad_stop (GstAudioDecoder * dec);
static gboolean gst_faad_set_format (GstAudioDecoder * dec, GstCaps * caps);
static gboolean gst_faad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
    gint * offset, gint * length);
static GstFlowReturn gst_faad_handle_frame (GstAudioDecoder * dec,
    GstBuffer * buffer);
static void gst_faad_flush (GstAudioDecoder * dec, gboolean hard);

143 144
static gboolean gst_faad_open_decoder (GstFaad * faad);
static void gst_faad_close_decoder (GstFaad * faad);
145

Wim Taymans's avatar
Wim Taymans committed
146 147
#define gst_faad_parent_class parent_class
G_DEFINE_TYPE (GstFaad, gst_faad, GST_TYPE_AUDIO_DECODER);
148 149

static void
Wim Taymans's avatar
Wim Taymans committed
150
gst_faad_class_init (GstFaadClass * klass)
151 152
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
Wim Taymans's avatar
Wim Taymans committed
153
  GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass);
154 155

  gst_element_class_add_pad_template (element_class,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
156
      gst_static_pad_template_get (&src_template));
157
  gst_element_class_add_pad_template (element_class,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
158
      gst_static_pad_template_get (&sink_template));
159

160
  gst_element_class_set_static_metadata (element_class, "AAC audio decoder",
161 162 163
      "Codec/Decoder/Audio",
      "Free MPEG-2/4 AAC decoder",
      "Ronald Bultje <rbultje@ronald.bitfreak.net>");
164

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
165 166 167 168 169 170
  base_class->start = GST_DEBUG_FUNCPTR (gst_faad_start);
  base_class->stop = GST_DEBUG_FUNCPTR (gst_faad_stop);
  base_class->set_format = GST_DEBUG_FUNCPTR (gst_faad_set_format);
  base_class->parse = GST_DEBUG_FUNCPTR (gst_faad_parse);
  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_faad_handle_frame);
  base_class->flush = GST_DEBUG_FUNCPTR (gst_faad_flush);
Wim Taymans's avatar
Wim Taymans committed
171 172

  GST_DEBUG_CATEGORY_INIT (faad_debug, "faad", 0, "AAC decoding");
173 174 175
}

static void
Wim Taymans's avatar
Wim Taymans committed
176
gst_faad_init (GstFaad * faad)
177
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
178 179 180
  gst_faad_reset (faad);
}

181 182 183 184 185 186 187
static void
gst_faad_reset_stream_state (GstFaad * faad)
{
  if (faad->handle)
    faacDecPostSeekReset (faad->handle, 0);
}

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
188 189 190 191 192 193 194 195 196
static void
gst_faad_reset (GstFaad * faad)
{
  faad->samplerate = -1;
  faad->channels = -1;
  faad->init = FALSE;
  faad->packetised = FALSE;
  g_free (faad->channel_positions);
  faad->channel_positions = NULL;
197
  faad->last_header = 0;
198 199

  gst_faad_reset_stream_state (faad);
200 201
}

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
202 203
static gboolean
gst_faad_start (GstAudioDecoder * dec)
204
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
205
  GstFaad *faad = GST_FAAD (dec);
206

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
207 208
  GST_DEBUG_OBJECT (dec, "start");
  gst_faad_reset (faad);
209

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
210
  /* call upon legacy upstream byte support (e.g. seeking) */
211
  gst_audio_decoder_set_estimate_rate (dec, TRUE);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
212 213 214 215
  /* never mind a few errors */
  gst_audio_decoder_set_max_errors (dec, 10);

  return TRUE;
216 217
}

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
218 219
static gboolean
gst_faad_stop (GstAudioDecoder * dec)
220
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
221
  GstFaad *faad = GST_FAAD (dec);
222

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
223 224 225
  GST_DEBUG_OBJECT (dec, "stop");
  gst_faad_reset (faad);
  gst_faad_close_decoder (faad);
226

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
227
  return TRUE;
228 229
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
static gint
aac_rate_idx (gint rate)
{
  if (92017 <= rate)
    return 0;
  else if (75132 <= rate)
    return 1;
  else if (55426 <= rate)
    return 2;
  else if (46009 <= rate)
    return 3;
  else if (37566 <= rate)
    return 4;
  else if (27713 <= rate)
    return 5;
  else if (23004 <= rate)
    return 6;
  else if (18783 <= rate)
    return 7;
  else if (13856 <= rate)
    return 8;
  else if (11502 <= rate)
    return 9;
  else if (9391 <= rate)
    return 10;
  else
    return 11;
}

259
static gboolean
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
260
gst_faad_set_format (GstAudioDecoder * dec, GstCaps * caps)
261
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
262
  GstFaad *faad = GST_FAAD (dec);
263 264 265
  GstStructure *str = gst_caps_get_structure (caps, 0);
  GstBuffer *buf;
  const GValue *value;
266
  GstMapInfo map;
Wim Taymans's avatar
Wim Taymans committed
267 268
  guint8 *cdata;
  gsize csize;
269

270 271 272
  /* clean up current decoder, rather than trying to reconfigure */
  gst_faad_close_decoder (faad);

273 274
  /* Assume raw stream */
  faad->packetised = FALSE;
275

276
  if ((value = gst_structure_get_value (str, "codec_data"))) {
277 278 279
#if FAAD2_MINOR_VERSION >= 7
    unsigned long samplerate;
#else
280
    guint32 samplerate;
281
#endif
282
    guint8 channels;
283 284 285

    /* We have codec data, means packetised stream */
    faad->packetised = TRUE;
286

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
287
    buf = gst_value_get_buffer (value);
288 289
    g_return_val_if_fail (buf != NULL, FALSE);

290 291 292
    gst_buffer_map (buf, &map, GST_MAP_READ);
    cdata = map.data;
    csize = map.size;
293 294 295

    if (csize < 2)
      goto wrong_length;
296

297 298
    GST_DEBUG_OBJECT (faad,
        "codec_data: object_type=%d, sample_rate=%d, channels=%d",
299 300 301 302
        ((cdata[0] & 0xf8) >> 3),
        (((cdata[0] & 0x07) << 1) | ((cdata[1] & 0x80) >> 7)),
        ((cdata[1] & 0x78) >> 3));

303 304
    if (!gst_faad_open_decoder (faad))
      goto open_failed;
305
    /* someone forgot that char can be unsigned when writing the API */
306
    if ((gint8) faacDecInit2 (faad->handle, cdata, csize, &samplerate,
307 308
            &channels) < 0)
      goto init_failed;
309

310 311 312 313 314 315 316
    if (channels != ((cdata[1] & 0x78) >> 3)) {
      /* https://bugs.launchpad.net/ubuntu/+source/faad2/+bug/290259 */
      GST_WARNING_OBJECT (faad,
          "buggy faad version, wrong nr of channels %d instead of %d", channels,
          ((cdata[1] & 0x78) >> 3));
    }

317
    GST_DEBUG_OBJECT (faad, "codec_data init: channels=%u, rate=%u", channels,
318
        (guint32) samplerate);
319

320 321 322 323 324 325
    /* not updating these here, so they are updated in the
     * chain function, and new caps are created etc. */
    faad->samplerate = 0;
    faad->channels = 0;

    faad->init = TRUE;
326
    gst_buffer_unmap (buf, &map);
327 328 329
  } else if ((value = gst_structure_get_value (str, "framed")) &&
      g_value_get_boolean (value) == TRUE) {
    faad->packetised = TRUE;
330
    faad->init = FALSE;
331
    GST_DEBUG_OBJECT (faad, "we have packetized audio");
332 333 334
  } else {
    faad->init = FALSE;
  }
335

336 337 338
  faad->fake_codec_data[0] = 0;
  faad->fake_codec_data[1] = 0;

339
  if (faad->packetised && !faad->init) {
340 341 342 343 344 345
    gint rate, channels;

    if (gst_structure_get_int (str, "rate", &rate) &&
        gst_structure_get_int (str, "channels", &channels)) {
      gint rate_idx, profile;

346
      profile = 3;              /* 0=MAIN, 1=LC, 2=SSR, 3=LTP */
347 348 349 350
      rate_idx = aac_rate_idx (rate);

      faad->fake_codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
      faad->fake_codec_data[1] = ((rate_idx & 0x1) << 7) | (channels << 3);
351 352 353
      GST_LOG_OBJECT (faad, "created fake codec data (%u,%u): 0x%x 0x%x", rate,
          channels, (int) faad->fake_codec_data[0],
          (int) faad->fake_codec_data[1]);
354 355 356
    }
  }

357
  return TRUE;
358 359

  /* ERRORS */
360 361 362
wrong_length:
  {
    GST_DEBUG_OBJECT (faad, "codec_data less than 2 bytes long");
363
    gst_object_unref (faad);
364
    gst_buffer_unmap (buf, &map);
365 366
    return FALSE;
  }
367 368 369 370
open_failed:
  {
    GST_DEBUG_OBJECT (faad, "failed to create decoder");
    gst_object_unref (faad);
371
    gst_buffer_unmap (buf, &map);
372 373
    return FALSE;
  }
374 375 376
init_failed:
  {
    GST_DEBUG_OBJECT (faad, "faacDecInit2() failed");
377
    gst_object_unref (faad);
378
    gst_buffer_unmap (buf, &map);
379 380
    return FALSE;
  }
381 382
}

383 384 385
static gboolean
gst_faad_chanpos_to_gst (GstFaad * faad, guchar * fpos,
    GstAudioChannelPosition * pos, guint num)
Ronald S. Bultje's avatar
Ronald S. Bultje committed
386 387
{
  guint n;
388
  gboolean unknown_channel = FALSE;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
389

390 391 392
  /* special handling for the common cases for mono and stereo */
  if (num == 1 && fpos[0] == FRONT_CHANNEL_CENTER) {
    GST_DEBUG_OBJECT (faad, "mono common case; won't set channel positions");
393 394
    pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
    return TRUE;
395 396 397
  } else if (num == 2 && fpos[0] == FRONT_CHANNEL_LEFT
      && fpos[1] == FRONT_CHANNEL_RIGHT) {
    GST_DEBUG_OBJECT (faad, "stereo common case; won't set channel positions");
398 399 400
    pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
    pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
    return TRUE;
401 402
  }

Ronald S. Bultje's avatar
Ronald S. Bultje committed
403
  for (n = 0; n < num; n++) {
404
    GST_DEBUG_OBJECT (faad, "faad channel %d as %d", n, fpos[n]);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
405 406 407 408 409 410 411 412
    switch (fpos[n]) {
      case FRONT_CHANNEL_LEFT:
        pos[n] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
        break;
      case FRONT_CHANNEL_RIGHT:
        pos[n] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
        break;
      case FRONT_CHANNEL_CENTER:
413 414
        /* argh, mono = center */
        if (num == 1)
415
          pos[n] = GST_AUDIO_CHANNEL_POSITION_MONO;
416 417
        else
          pos[n] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
        break;
      case SIDE_CHANNEL_LEFT:
        pos[n] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT;
        break;
      case SIDE_CHANNEL_RIGHT:
        pos[n] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT;
        break;
      case BACK_CHANNEL_LEFT:
        pos[n] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
        break;
      case BACK_CHANNEL_RIGHT:
        pos[n] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
        break;
      case BACK_CHANNEL_CENTER:
        pos[n] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
        break;
      case LFE_CHANNEL:
435
        pos[n] = GST_AUDIO_CHANNEL_POSITION_LFE1;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
436 437
        break;
      default:
438
        GST_DEBUG_OBJECT (faad, "unknown channel %d at %d", fpos[n], n);
439 440 441 442 443
        unknown_channel = TRUE;
        break;
    }
  }
  if (unknown_channel) {
444 445
    switch (num) {
      case 1:{
446 447
        GST_DEBUG_OBJECT (faad,
            "FAAD reports unknown 1 channel mapping. Forcing to mono");
448
        pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
449 450 451
        break;
      }
      case 2:{
452 453
        GST_DEBUG_OBJECT (faad,
            "FAAD reports unknown 2 channel mapping. Forcing to stereo");
454 455
        pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
        pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
456 457 458
        break;
      }
      default:{
459 460
        GST_WARNING_OBJECT (faad,
            "Unsupported FAAD channel position 0x%x encountered", fpos[n]);
461
        return FALSE;
462 463
        break;
      }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
464 465 466
    }
  }

467
  return TRUE;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
468 469
}

470
static gboolean
471
gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info)
472
{
473
  gboolean ret;
474
  gboolean fmt_change = FALSE;
475
  GstAudioInfo ainfo;
476
  gint i;
477 478 479 480 481 482 483

  /* see if we need to renegotiate */
  if (info->samplerate != faad->samplerate ||
      info->channels != faad->channels || !faad->channel_positions) {
    fmt_change = TRUE;
  } else {
    for (i = 0; i < info->channels; i++) {
484
      if (info->channel_position[i] != faad->channel_positions[i]) {
485
        fmt_change = TRUE;
486 487
        break;
      }
488 489 490
    }
  }

491 492
  if (G_LIKELY (gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (faad))
          && !fmt_change))
493
    return TRUE;
494

495

496 497 498 499 500 501
  /* store new negotiation information */
  faad->samplerate = info->samplerate;
  faad->channels = info->channels;
  g_free (faad->channel_positions);
  faad->channel_positions = g_memdup (info->channel_position, faad->channels);

502 503 504 505
  /* FIXME: Use the GstAudioInfo of GstAudioDecoder for all of this */
  gst_audio_info_init (&ainfo);
  gst_audio_info_set_format (&ainfo, GST_AUDIO_FORMAT_S16, faad->samplerate,
      faad->channels, NULL);
506 507
  faad->bps = 16 / 8;

508 509
  if (!gst_faad_chanpos_to_gst (faad, faad->channel_positions,
          faad->aac_positions, faad->channels)) {
510 511 512
    GST_DEBUG_OBJECT (faad, "Could not map channel positions");
    return FALSE;
  }
513 514 515 516 517
  memcpy (ainfo.position, faad->aac_positions,
      faad->channels * sizeof (GstAudioChannelPosition));
  gst_audio_channel_positions_to_valid_order (ainfo.position, faad->channels);
  memcpy (faad->gst_positions, ainfo.position,
      faad->channels * sizeof (GstAudioChannelPosition));
518 519 520
  /* Unset UNPOSITIONED flag */
  if (ainfo.position[0] != GST_AUDIO_CHANNEL_POSITION_NONE)
    ainfo.flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
521

522 523 524 525 526 527
  /* get the remap table */
  memset (faad->reorder_map, 0, sizeof (faad->reorder_map));
  faad->need_reorder = FALSE;
  if (gst_audio_get_channel_reorder_map (faad->channels, faad->aac_positions,
          faad->gst_positions, faad->reorder_map)) {
    for (i = 0; i < faad->channels; i++) {
Wim Taymans's avatar
Wim Taymans committed
528
      GST_DEBUG_OBJECT (faad, "remap %d -> %d", i, faad->reorder_map[i]);
529 530 531 532 533 534
      if (faad->reorder_map[i] != i) {
        faad->need_reorder = TRUE;
      }
    }
  }

535
  ret = gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (faad), &ainfo);
536

537
  return ret;
538 539
}

540 541 542 543 544 545 546 547 548
/*
 * Find syncpoint in ADTS/ADIF stream. Doesn't work for raw,
 * packetized streams. Be careful when calling.
 * Returns FALSE on no-sync, fills offset/length if one/two
 * syncpoints are found, only returns TRUE when it finds two
 * subsequent syncpoints (similar to mp3 typefinding in
 * gst/typefind/) for ADTS because 12 bits isn't very reliable.
 */
static gboolean
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
549 550
gst_faad_sync (GstFaad * faad, const guint8 * data, guint size, gboolean next,
    gint * off, gint * length)
551
{
552
  guint n = 0;
553
  gint snc;
554
  gboolean ret = FALSE;
555
  guint len = 0;
556

557
  GST_LOG_OBJECT (faad, "Finding syncpoint");
558

559 560
  /* check for too small a buffer */
  if (size < 3)
561
    goto exit;
562

563 564 565 566 567
  for (n = 0; n < size - 3; n++) {
    snc = GST_READ_UINT16_BE (&data[n]);
    if ((snc & 0xfff6) == 0xfff0) {
      /* we have an ADTS syncpoint. Parse length and find
       * next syncpoint. */
568 569
      GST_LOG_OBJECT (faad,
          "Found one ADTS syncpoint at offset 0x%x, tracing next...", n);
570 571

      if (size - n < 5) {
572
        GST_LOG_OBJECT (faad, "Not enough data to parse ADTS header");
573
        break;
574 575 576 577 578
      }

      len = ((data[n + 3] & 0x03) << 11) |
          (data[n + 4] << 3) | ((data[n + 5] & 0xe0) >> 5);
      if (n + len + 2 >= size) {
579 580 581 582 583 584 585 586 587 588
        GST_LOG_OBJECT (faad, "Frame size %d, next frame is not within reach",
            len);
        if (next) {
          break;
        } else if (n + len <= size) {
          GST_LOG_OBJECT (faad, "but have complete frame and no next frame; "
              "accept ADTS syncpoint at offset 0x%x (framelen %u)", n, len);
          ret = TRUE;
          break;
        }
589 590 591 592
      }

      snc = GST_READ_UINT16_BE (&data[n + len]);
      if ((snc & 0xfff6) == 0xfff0) {
593 594
        GST_LOG_OBJECT (faad,
            "Found ADTS syncpoint at offset 0x%x (framelen %u)", n, len);
595 596
        ret = TRUE;
        break;
597 598
      }

599 600
      GST_LOG_OBJECT (faad, "No next frame found... (should be at 0x%x)",
          n + len);
601 602
    } else if (!memcmp (&data[n], "ADIF", 4)) {
      /* we have an ADIF syncpoint. 4 bytes is enough. */
603
      GST_LOG_OBJECT (faad, "Found ADIF syncpoint at offset 0x%x", n);
604 605
      ret = TRUE;
      break;
606 607 608
    }
  }

609
exit:
610

611
  *off = n;
612

613 614 615
  if (ret) {
    *length = len;
  } else {
616
    GST_LOG_OBJECT (faad, "Found no syncpoint");
617
  }
618 619

  return ret;
620 621
}

622 623 624
static gboolean
looks_like_valid_header (guint8 * input_data, guint input_size)
{
625
  if (input_size < 4)
626 627
    return FALSE;

628 629 630 631
  if (input_data[0] == 'A'
      && input_data[1] == 'D' && input_data[2] == 'I' && input_data[3] == 'F')
    /* ADIF type header */
    return TRUE;
632

633 634 635
  if (input_data[0] == 0xff && (input_data[1] >> 4) == 0xf)
    /* ADTS type header */
    return TRUE;
636

637
  return FALSE;
638 639
}

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
640 641 642 643 644 645 646 647 648 649 650 651
static GstFlowReturn
gst_faad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
    gint * offset, gint * length)
{
  GstFaad *faad;
  const guint8 *data;
  guint size;
  gboolean sync, eos;

  faad = GST_FAAD (dec);

  size = gst_adapter_available (adapter);
652
  g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
653 654 655 656 657 658 659 660

  gst_audio_decoder_get_parse_state (dec, &sync, &eos);

  if (faad->packetised) {
    *offset = 0;
    *length = size;
    return GST_FLOW_OK;
  } else {
Wim Taymans's avatar
Wim Taymans committed
661 662 663 664
    gboolean ret;

    data = gst_adapter_map (adapter, size);
    ret = gst_faad_sync (faad, data, size, !eos, offset, length);
Wim Taymans's avatar
Wim Taymans committed
665
    gst_adapter_unmap (adapter);
Wim Taymans's avatar
Wim Taymans committed
666

667
    return (ret ? GST_FLOW_OK : GST_FLOW_EOS);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
668 669
  }
}
670

671
static GstFlowReturn
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
672
gst_faad_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
673
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
674
  GstFaad *faad;
675
  GstFlowReturn ret = GST_FLOW_OK;
676
  GstMapInfo map;
Wim Taymans's avatar
Wim Taymans committed
677
  gsize input_size;
678
  guchar *input_data;
679
  GstBuffer *outbuf;
680
  faacDecFrameInfo info;
681
  void *out;
682

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
683
  faad = GST_FAAD (dec);
684

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
685 686 687
  /* no fancy draining */
  if (G_UNLIKELY (!buffer))
    return GST_FLOW_OK;
688

689 690 691
  gst_buffer_map (buffer, &map, GST_MAP_READ);
  input_data = map.data;
  input_size = map.size;
692

693
init:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
694 695
  /* init if not already done during capsnego */
  if (!faad->init) {
696 697 698
#if FAAD2_MINOR_VERSION >= 7
    unsigned long rate;
#else
699
    guint32 rate;
700
#endif
701 702 703
    guint8 ch;

    GST_DEBUG_OBJECT (faad, "initialising ...");
704 705
    if (!gst_faad_open_decoder (faad))
      goto open_failed;
706 707 708 709 710 711 712
    /* We check if the first data looks like it might plausibly contain
     * appropriate initialisation info... if not, we use our fake_codec_data
     */
    if (looks_like_valid_header (input_data, input_size) || !faad->packetised) {
      if (faacDecInit (faad->handle, input_data, input_size, &rate, &ch) < 0)
        goto init_failed;

713 714
      GST_DEBUG_OBJECT (faad, "faacDecInit() ok: rate=%u,channels=%u",
          (guint32) rate, ch);
715 716 717 718 719
    } else {
      if ((gint8) faacDecInit2 (faad->handle, faad->fake_codec_data, 2,
              &rate, &ch) < 0) {
        goto init2_failed;
      }
720 721
      GST_DEBUG_OBJECT (faad, "faacDecInit2() ok: rate=%u,channels=%u",
          (guint32) rate, ch);
722
    }
723

Ronald S. Bultje's avatar
Ronald S. Bultje committed
724
    faad->init = TRUE;
725

726 727 728
    /* make sure we create new caps below */
    faad->samplerate = 0;
    faad->channels = 0;
729
  }
730

Ronald S. Bultje's avatar
Ronald S. Bultje committed
731
  /* decode cycle */
732
  info.error = 0;
733

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
734
  do {
735
    GstMapInfo omap;
736

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
737
    if (!faad->packetised) {
738 739 740 741 742
      /* faad only really parses ADTS header at Init time, not when decoding,
       * so monitor for changes and kick faad when needed */
      if (GST_READ_UINT32_BE (input_data) >> 4 != faad->last_header >> 4) {
        GST_DEBUG_OBJECT (faad, "ADTS header changed, forcing Init");
        faad->last_header = GST_READ_UINT32_BE (input_data);
743 744 745
        /* kick hard */
        gst_faad_close_decoder (faad);
        faad->init = FALSE;
746 747
        goto init;
      }
748 749
    }

750
    out = faacDecDecode (faad->handle, &info, input_data, input_size);
751

752 753 754
    gst_buffer_unmap (buffer, &map);
    buffer = NULL;

755
    if (info.error > 0) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
756 757 758
      /* give up on frame and bail out */
      gst_audio_decoder_finish_frame (dec, NULL, 1);
      goto decode_failed;
759
    }
760

761 762 763
    GST_LOG_OBJECT (faad, "%d bytes consumed, %d samples decoded",
        (guint) info.bytesconsumed, (guint) info.samples);

764
    if (out && info.samples > 0) {
765 766
      guint channels, samples;

767 768
      if (!gst_faad_update_caps (faad, &info))
        goto negotiation_failed;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
769

770 771 772
      /* C's lovely propensity for int overflow.. */
      if (info.samples > G_MAXUINT / faad->bps)
        goto sample_overflow;
773

774
      channels = faad->channels;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
775
      /* note: info.samples is total samples, not per channel */
776 777
      samples = info.samples / channels;

Wim Taymans's avatar
Wim Taymans committed
778
      /* FIXME, add bufferpool and allocator support to the base class */
Wim Taymans's avatar
Wim Taymans committed
779
      outbuf = gst_buffer_new_allocate (NULL, info.samples * faad->bps, NULL);
780

781
      gst_buffer_map (outbuf, &omap, GST_MAP_READWRITE);
782 783 784
      if (faad->need_reorder) {
        gint16 *dest, *src, i, j;

785
        dest = (gint16 *) omap.data;
786 787 788 789 790 791 792 793 794
        src = (gint16 *) out;

        for (i = 0; i < samples; i++) {
          for (j = 0; j < channels; j++) {
            dest[faad->reorder_map[j]] = *src++;
          }
          dest += channels;
        }
      } else {
795
        memcpy (omap.data, out, omap.size);
796
      }
797
      gst_buffer_unmap (outbuf, &omap);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
798 799

      ret = gst_audio_decoder_finish_frame (dec, outbuf, 1);
800
    }
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
801
  } while (FALSE);
802

803
out:
804 805
  if (buffer)
    gst_buffer_unmap (buffer, &map);
Wim Taymans's avatar
Wim Taymans committed
806

807
  return ret;
808 809

/* ERRORS */
810 811 812 813 814 815 816
open_failed:
  {
    GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
        ("Failed to open decoder"));
    ret = GST_FLOW_ERROR;
    goto out;
  }
817 818 819 820 821 822 823 824 825 826 827 828 829 830
init_failed:
  {
    GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
        ("Failed to init decoder from stream"));
    ret = GST_FLOW_ERROR;
    goto out;
  }
init2_failed:
  {
    GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
        ("%s() failed", (faad->handle) ? "faacDecInit2" : "faacDecOpen"));
    ret = GST_FLOW_ERROR;
    goto out;
  }
831 832
decode_failed:
  {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
833 834
    GST_AUDIO_DECODER_ERROR (faad, 1, STREAM, DECODE, (NULL),
        ("decoding error: %s", faacDecGetErrorMessage (info.error)), ret);
835 836
    goto out;
  }
837 838 839 840 841 842 843 844 845 846 847 848 849 850
negotiation_failed:
  {
    GST_ELEMENT_ERROR (faad, CORE, NEGOTIATION, (NULL),
        ("Setting caps on source pad failed"));
    ret = GST_FLOW_ERROR;
    goto out;
  }
sample_overflow:
  {
    GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
        ("Output buffer too large"));
    ret = GST_FLOW_ERROR;
    goto out;
  }
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
851 852 853 854 855 856
}

static void
gst_faad_flush (GstAudioDecoder * dec, gboolean hard)
{
  gst_faad_reset_stream_state (GST_FAAD (dec));
857 858 859 860 861 862 863 864 865 866 867 868