Merge commit '831018b0bbe26a603802a9022472f714a59293be'
authorJames Almer <jamrial@gmail.com>
Mon, 30 Oct 2017 20:47:21 +0000 (17:47 -0300)
committerJames Almer <jamrial@gmail.com>
Mon, 30 Oct 2017 20:47:21 +0000 (17:47 -0300)
* commit '831018b0bbe26a603802a9022472f714a59293be':
  mpeg4audio: Make avpriv_copy_pce_data() inline

Merged-by: James Almer <jamrial@gmail.com>
1  2 
libavcodec/aac_adtstoasc_bsf.c
libavcodec/mpeg4audio.c
libavcodec/mpeg4audio.h
libavformat/adtsenc.c
libavformat/latmenc.c

@@@ -2,20 -2,20 +2,20 @@@
   * MPEG-2/4 AAC ADTS to MPEG-4 Audio Specific Configuration bitstream filter
   * Copyright (c) 2009 Alex Converse <alex.converse@gmail.com>
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -49,14 -49,14 +49,14 @@@ static int aac_adtstoasc_filter(AVBSFCo
      if (ret < 0)
          return ret;
  
 +    if (bsfc->par_in->extradata && in->size >= 2 && (AV_RB16(in->data) >> 4) != 0xfff)
 +        goto finish;
 +
      if (in->size < AAC_ADTS_HEADER_SIZE)
          goto packet_too_small;
  
      init_get_bits(&gb, in->data, AAC_ADTS_HEADER_SIZE * 8);
  
 -    if (bsfc->par_in->extradata && show_bits(&gb, 12) != 0xfff)
 -        goto finish;
 -
      if (avpriv_aac_parse_header(&gb, &hdr) < 0) {
          av_log(bsfc, AV_LOG_ERROR, "Error parsing ADTS frame header!\n");
          ret = AVERROR_INVALIDDATA;
@@@ -91,7 -91,7 +91,7 @@@
                  goto fail;
              }
              init_put_bits(&pb, pce_data, MAX_PCE_SIZE);
-             pce_size = avpriv_copy_pce_data(&pb, &gb)/8;
+             pce_size = ff_copy_pce_data(&pb, &gb) / 8;
              flush_put_bits(&pb);
              in->size -= get_bits_count(&gb)/8;
              in->data += get_bits_count(&gb)/8;
diff --combined libavcodec/mpeg4audio.c
@@@ -3,20 -3,20 +3,20 @@@
   * Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
   * Copyright (c) 2009 Alex Converse <alex.converse@gmail.com>
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -42,11 -42,6 +42,11 @@@ static int parse_config_ALS(GetBitConte
      // which are buggy in old ALS conformance files
      c->sample_rate = get_bits_long(gb, 32);
  
 +    if (c->sample_rate <= 0) {
 +        av_log(NULL, AV_LOG_ERROR, "Invalid sample rate %d\n", c->sample_rate);
 +        return AVERROR_INVALIDDATA;
 +    }
 +
      // skip number of samples
      skip_bits_long(gb, 32);
  
@@@ -57,8 -52,6 +57,8 @@@
      return 0;
  }
  
 +/* XXX: make sure to update the copies in the different encoders if you change
 + * this table */
  const int avpriv_mpeg4audio_sample_rates[16] = {
      96000, 88200, 64000, 48000, 44100, 32000,
      24000, 22050, 16000, 12000, 11025, 8000, 7350
@@@ -83,62 -76,63 +83,62 @@@ static inline int get_sample_rate(GetBi
          avpriv_mpeg4audio_sample_rates[*index];
  }
  
 -int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf,
 -                                 int bit_size, int sync_extension)
 +int ff_mpeg4audio_get_config_gb(MPEG4AudioConfig *c, GetBitContext *gb,
 +                                int sync_extension)
  {
 -    GetBitContext gb;
      int specific_config_bitindex, ret;
 -
 -    ret = init_get_bits(&gb, buf, bit_size);
 -    if (ret < 0)
 -        return ret;
 -    c->object_type = get_object_type(&gb);
 -    c->sample_rate = get_sample_rate(&gb, &c->sampling_index);
 -    c->chan_config = get_bits(&gb, 4);
 +    int start_bit_index = get_bits_count(gb);
 +    c->object_type = get_object_type(gb);
 +    c->sample_rate = get_sample_rate(gb, &c->sampling_index);
 +    c->chan_config = get_bits(gb, 4);
      if (c->chan_config < FF_ARRAY_ELEMS(ff_mpeg4audio_channels))
          c->channels = ff_mpeg4audio_channels[c->chan_config];
      c->sbr = -1;
      c->ps  = -1;
      if (c->object_type == AOT_SBR || (c->object_type == AOT_PS &&
          // check for W6132 Annex YYYY draft MP3onMP4
 -        !(show_bits(&gb, 3) & 0x03 && !(show_bits(&gb, 9) & 0x3F)))) {
 +        !(show_bits(gb, 3) & 0x03 && !(show_bits(gb, 9) & 0x3F)))) {
          if (c->object_type == AOT_PS)
              c->ps = 1;
          c->ext_object_type = AOT_SBR;
          c->sbr = 1;
 -        c->ext_sample_rate = get_sample_rate(&gb, &c->ext_sampling_index);
 -        c->object_type = get_object_type(&gb);
 +        c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index);
 +        c->object_type = get_object_type(gb);
          if (c->object_type == AOT_ER_BSAC)
 -            c->ext_chan_config = get_bits(&gb, 4);
 +            c->ext_chan_config = get_bits(gb, 4);
      } else {
          c->ext_object_type = AOT_NULL;
          c->ext_sample_rate = 0;
      }
 -    specific_config_bitindex = get_bits_count(&gb);
 +    specific_config_bitindex = get_bits_count(gb);
  
      if (c->object_type == AOT_ALS) {
 -        skip_bits(&gb, 5);
 -        if (show_bits_long(&gb, 24) != MKBETAG('\0','A','L','S'))
 -            skip_bits_long(&gb, 24);
 +        skip_bits(gb, 5);
 +        if (show_bits_long(gb, 24) != MKBETAG('\0','A','L','S'))
 +            skip_bits_long(gb, 24);
  
 -        specific_config_bitindex = get_bits_count(&gb);
 +        specific_config_bitindex = get_bits_count(gb);
  
 -        ret = parse_config_ALS(&gb, c);
 +        ret = parse_config_ALS(gb, c);
          if (ret < 0)
              return ret;
      }
  
      if (c->ext_object_type != AOT_SBR && sync_extension) {
 -        while (get_bits_left(&gb) > 15) {
 -            if (show_bits(&gb, 11) == 0x2b7) { // sync extension
 -                get_bits(&gb, 11);
 -                c->ext_object_type = get_object_type(&gb);
 -                if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(&gb)) == 1)
 -                    c->ext_sample_rate = get_sample_rate(&gb, &c->ext_sampling_index);
 -                if (get_bits_left(&gb) > 11 && get_bits(&gb, 11) == 0x548)
 -                    c->ps = get_bits1(&gb);
 +        while (get_bits_left(gb) > 15) {
 +            if (show_bits(gb, 11) == 0x2b7) { // sync extension
 +                get_bits(gb, 11);
 +                c->ext_object_type = get_object_type(gb);
 +                if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(gb)) == 1) {
 +                    c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index);
 +                    if (c->ext_sample_rate == c->sample_rate)
 +                        c->sbr = -1;
 +                }
 +                if (get_bits_left(gb) > 11 && get_bits(gb, 11) == 0x548)
 +                    c->ps = get_bits1(gb);
                  break;
              } else
 -                get_bits1(&gb); // skip 1 bit
 +                get_bits1(gb); // skip 1 bit
          }
      }
  
      if ((c->ps == -1 && c->object_type != AOT_AAC_LC) || c->channels & ~0x01)
          c->ps = 0;
  
 -    return specific_config_bitindex;
 +    return specific_config_bitindex - start_bit_index;
 +}
 +
 +int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf,
 +                                 int bit_size, int sync_extension)
 +{
 +    GetBitContext gb;
 +    int ret;
 +
 +    if (bit_size <= 0)
 +        return AVERROR_INVALIDDATA;
 +
 +    ret = init_get_bits(&gb, buf, bit_size);
 +    if (ret < 0)
 +        return ret;
 +
 +    return ff_mpeg4audio_get_config_gb(c, &gb, sync_extension);
  }
- static av_always_inline unsigned int copy_bits(PutBitContext *pb,
-                                                GetBitContext *gb,
-                                                int bits)
- {
-     unsigned int el = get_bits(gb, bits);
-     put_bits(pb, bits, el);
-     return el;
- }
- int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb)
- {
-     int five_bit_ch, four_bit_ch, comment_size, bits;
-     int offset = put_bits_count(pb);
-     copy_bits(pb, gb, 10);                  //Tag, Object Type, Frequency
-     five_bit_ch  = copy_bits(pb, gb, 4);    //Front
-     five_bit_ch += copy_bits(pb, gb, 4);    //Side
-     five_bit_ch += copy_bits(pb, gb, 4);    //Back
-     four_bit_ch  = copy_bits(pb, gb, 2);    //LFE
-     four_bit_ch += copy_bits(pb, gb, 3);    //Data
-     five_bit_ch += copy_bits(pb, gb, 4);    //Coupling
-     if (copy_bits(pb, gb, 1))               //Mono Mixdown
-         copy_bits(pb, gb, 4);
-     if (copy_bits(pb, gb, 1))               //Stereo Mixdown
-         copy_bits(pb, gb, 4);
-     if (copy_bits(pb, gb, 1))               //Matrix Mixdown
-         copy_bits(pb, gb, 3);
-     for (bits = five_bit_ch*5+four_bit_ch*4; bits > 16; bits -= 16)
-         copy_bits(pb, gb, 16);
-     if (bits)
-         copy_bits(pb, gb, bits);
-     avpriv_align_put_bits(pb);
-     align_get_bits(gb);
-     comment_size = copy_bits(pb, gb, 8);
-     for (; comment_size > 0; comment_size--)
-         copy_bits(pb, gb, 8);
-     return put_bits_count(pb) - offset;
- }
diff --combined libavcodec/mpeg4audio.h
@@@ -2,20 -2,20 +2,20 @@@
   * MPEG-4 Audio common header
   * Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -23,6 -23,9 +23,9 @@@
  #define AVCODEC_MPEG4AUDIO_H
  
  #include <stdint.h>
+ #include "libavutil/attributes.h"
  #include "get_bits.h"
  #include "put_bits.h"
  
@@@ -45,17 -48,7 +48,17 @@@ extern av_export const int avpriv_mpeg4
  extern const uint8_t ff_mpeg4audio_channels[8];
  
  /**
 - * Parse MPEG-4 systems extradata to retrieve audio configuration.
 + * Parse MPEG-4 systems extradata from a potentially unaligned GetBitContext to retrieve audio configuration.
 + * @param[in] c        MPEG4AudioConfig structure to fill.
 + * @param[in] gb       Extradata from container.
 + * @param[in] sync_extension look for a sync extension after config if true.
 + * @return On error -1 is returned, on success AudioSpecificConfig bit index in extradata.
 + */
 +int ff_mpeg4audio_get_config_gb(MPEG4AudioConfig *c, GetBitContext *gb,
 +                                int sync_extension);
 +
 +/**
 + * Parse MPEG-4 systems extradata from a raw buffer to retrieve audio configuration.
   * @param[in] c        MPEG4AudioConfig structure to fill.
   * @param[in] buf      Extradata from container.
   * @param[in] bit_size Extradata size in bits.
@@@ -112,9 -105,47 +115,47 @@@ enum AudioObjectType 
      AOT_USAC,                  ///< N                       Unified Speech and Audio Coding
  };
  
 -#define MAX_PCE_SIZE 304 ///<Maximum size of a PCE including the 3-bit ID_PCE
 +#define MAX_PCE_SIZE 320 ///<Maximum size of a PCE including the 3-bit ID_PCE
                           ///<marker and the comment
  
- int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb);
+ static av_always_inline unsigned int ff_pce_copy_bits(PutBitContext *pb,
+                                                       GetBitContext *gb,
+                                                       int bits)
+ {
+     unsigned int el = get_bits(gb, bits);
+     put_bits(pb, bits, el);
+     return el;
+ }
+ static inline int ff_copy_pce_data(PutBitContext *pb, GetBitContext *gb)
+ {
+     int five_bit_ch, four_bit_ch, comment_size, bits;
+     int offset = put_bits_count(pb);
+     ff_pce_copy_bits(pb, gb, 10);               // Tag, Object Type, Frequency
+     five_bit_ch  = ff_pce_copy_bits(pb, gb, 4); // Front
+     five_bit_ch += ff_pce_copy_bits(pb, gb, 4); // Side
+     five_bit_ch += ff_pce_copy_bits(pb, gb, 4); // Back
+     four_bit_ch  = ff_pce_copy_bits(pb, gb, 2); // LFE
+     four_bit_ch += ff_pce_copy_bits(pb, gb, 3); // Data
+     five_bit_ch += ff_pce_copy_bits(pb, gb, 4); // Coupling
+     if (ff_pce_copy_bits(pb, gb, 1))            // Mono Mixdown
+         ff_pce_copy_bits(pb, gb, 4);
+     if (ff_pce_copy_bits(pb, gb, 1))            // Stereo Mixdown
+         ff_pce_copy_bits(pb, gb, 4);
+     if (ff_pce_copy_bits(pb, gb, 1))            // Matrix Mixdown
+         ff_pce_copy_bits(pb, gb, 3);
+     for (bits = five_bit_ch*5+four_bit_ch*4; bits > 16; bits -= 16)
+         ff_pce_copy_bits(pb, gb, 16);
+     if (bits)
+         ff_pce_copy_bits(pb, gb, bits);
+     avpriv_align_put_bits(pb);
+     align_get_bits(gb);
+     comment_size = ff_pce_copy_bits(pb, gb, 8);
+     for (; comment_size > 0; comment_size--)
+         ff_pce_copy_bits(pb, gb, 8);
+     return put_bits_count(pb) - offset;
+ }
  
  #endif /* AVCODEC_MPEG4AUDIO_H */
diff --combined libavformat/adtsenc.c
@@@ -3,20 -3,20 +3,20 @@@
   * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
   *                    Mans Rullgard <mans@mansr.com>
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
  #include "libavcodec/put_bits.h"
  #include "libavcodec/avcodec.h"
  #include "libavcodec/mpeg4audio.h"
 +#include "libavutil/opt.h"
  #include "avformat.h"
 +#include "apetag.h"
 +#include "id3v2.h"
  
  #define ADTS_HEADER_SIZE 7
  
  typedef struct ADTSContext {
 +    AVClass *class;
      int write_adts;
      int objecttype;
      int sample_rate_index;
      int channel_conf;
      int pce_size;
 +    int apetag;
 +    int id3v2tag;
      uint8_t pce_data[MAX_PCE_SIZE];
  } ADTSContext;
  
  #define ADTS_MAX_FRAME_BYTES ((1 << 13) - 1)
  
 -static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, uint8_t *buf, int size)
 +static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, const uint8_t *buf, int size)
  {
      GetBitContext gb;
      PutBitContext pb;
@@@ -85,7 -79,7 +85,7 @@@
          init_put_bits(&pb, adts->pce_data, MAX_PCE_SIZE);
  
          put_bits(&pb, 3, 5); //ID_PCE
-         adts->pce_size = (avpriv_copy_pce_data(&pb, &gb) + 3) / 8;
+         adts->pce_size = (ff_copy_pce_data(&pb, &gb) + 3) / 8;
          flush_put_bits(&pb);
      }
  
@@@ -99,8 -93,6 +99,8 @@@ static int adts_write_header(AVFormatCo
      ADTSContext *adts = s->priv_data;
      AVCodecParameters *par = s->streams[0]->codecpar;
  
 +    if (adts->id3v2tag)
 +        ff_id3v2_write_simple(s, 4, ID3v2_DEFAULT_MAGIC);
      if (par->extradata_size > 0)
          return adts_decode_extradata(s, adts, par->extradata,
                                       par->extradata_size);
@@@ -149,28 -141,11 +149,28 @@@ static int adts_write_frame_header(ADTS
  static int adts_write_packet(AVFormatContext *s, AVPacket *pkt)
  {
      ADTSContext *adts = s->priv_data;
 +    AVCodecParameters *par = s->streams[0]->codecpar;
      AVIOContext *pb = s->pb;
      uint8_t buf[ADTS_HEADER_SIZE];
  
      if (!pkt->size)
          return 0;
 +    if (!par->extradata_size) {
 +        uint8_t *side_data;
 +        int side_data_size = 0, ret;
 +
 +        side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
 +                                            &side_data_size);
 +        if (side_data_size) {
 +            ret = adts_decode_extradata(s, adts, side_data, side_data_size);
 +            if (ret < 0)
 +                return ret;
 +            ret = ff_alloc_extradata(par, side_data_size);
 +            if (ret < 0)
 +                return ret;
 +            memcpy(par->extradata, side_data, side_data_size);
 +        }
 +    }
      if (adts->write_adts) {
          int err = adts_write_frame_header(adts, buf, pkt->size,
                                               adts->pce_size);
      return 0;
  }
  
 +static int adts_write_trailer(AVFormatContext *s)
 +{
 +    ADTSContext *adts = s->priv_data;
 +
 +    if (adts->apetag)
 +        ff_ape_write_tag(s);
 +
 +    return 0;
 +}
 +
 +#define ENC AV_OPT_FLAG_ENCODING_PARAM
 +#define OFFSET(obj) offsetof(ADTSContext, obj)
 +static const AVOption options[] = {
 +    { "write_id3v2",  "Enable ID3v2 tag writing", OFFSET(id3v2tag), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, ENC},
 +    { "write_apetag", "Enable APE tag writing",   OFFSET(apetag),   AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, ENC},
 +    { NULL },
 +};
 +
 +static const AVClass adts_muxer_class = {
 +    .class_name     = "ADTS muxer",
 +    .item_name      = av_default_item_name,
 +    .option         = options,
 +    .version        = LIBAVUTIL_VERSION_INT,
 +};
 +
  AVOutputFormat ff_adts_muxer = {
      .name              = "adts",
      .long_name         = NULL_IF_CONFIG_SMALL("ADTS AAC (Advanced Audio Coding)"),
      .video_codec       = AV_CODEC_ID_NONE,
      .write_header      = adts_write_header,
      .write_packet      = adts_write_packet,
 +    .write_trailer     = adts_write_trailer,
 +    .priv_class        = &adts_muxer_class,
      .flags             = AVFMT_NOTIMESTAMPS,
  };
diff --combined libavformat/latmenc.c
@@@ -2,20 -2,20 +2,20 @@@
   * LATM/LOAS muxer
   * Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.com>
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
  #include "libavcodec/mpeg4audio.h"
  #include "libavutil/opt.h"
  #include "avformat.h"
 +#include "internal.h"
 +#include "rawenc.h"
 +
 +#define MAX_EXTRADATA_SIZE 1024
  
  typedef struct LATMContext {
      AVClass *av_class;
@@@ -37,7 -33,6 +37,7 @@@
      int object_type;
      int counter;
      int mod;
 +    uint8_t buffer[0x1fff + MAX_EXTRADATA_SIZE + 1024];
  } LATMContext;
  
  static const AVOption options[] = {
@@@ -55,21 -50,15 +55,21 @@@ static const AVClass latm_muxer_class 
  
  static int latm_decode_extradata(LATMContext *ctx, uint8_t *buf, int size)
  {
 -    GetBitContext gb;
      MPEG4AudioConfig m4ac;
  
 -    init_get_bits(&gb, buf, size * 8);
 +    if (size > MAX_EXTRADATA_SIZE) {
 +        av_log(ctx, AV_LOG_ERROR, "Extradata is larger than currently supported.\n");
 +        return AVERROR_INVALIDDATA;
 +    }
      ctx->off = avpriv_mpeg4audio_get_config(&m4ac, buf, size * 8, 1);
      if (ctx->off < 0)
          return ctx->off;
 -    skip_bits_long(&gb, ctx->off);
  
 +    if (ctx->object_type == AOT_ALS && (ctx->off & 7)) {
 +        // as long as avpriv_mpeg4audio_get_config works correctly this is impossible
 +        av_log(ctx, AV_LOG_ERROR, "BUG: ALS offset is not byte-aligned\n");
 +        return AVERROR_INVALIDDATA;
 +    }
      /* FIXME: are any formats not allowed in LATM? */
  
      if (m4ac.object_type > AOT_SBR && m4ac.object_type != AOT_ALS) {
@@@ -87,9 -76,6 +87,9 @@@ static int latm_write_header(AVFormatCo
      LATMContext *ctx = s->priv_data;
      AVCodecParameters *par = s->streams[0]->codecpar;
  
 +    if (par->codec_id == AV_CODEC_ID_AAC_LATM)
 +        return 0;
 +
      if (par->extradata_size > 0 &&
          latm_decode_extradata(ctx, par->extradata, par->extradata_size) < 0)
          return AVERROR_INVALIDDATA;
      return 0;
  }
  
 -static int latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
 +static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
  {
      LATMContext *ctx = s->priv_data;
      AVCodecParameters *par = s->streams[0]->codecpar;
 -    GetBitContext gb;
      int header_size;
  
      /* AudioMuxElement */
      put_bits(bs, 1, !!ctx->counter);
  
      if (!ctx->counter) {
 -        init_get_bits(&gb, par->extradata, par->extradata_size * 8);
 -
          /* StreamMuxConfig */
          put_bits(bs, 1, 0); /* audioMuxVersion */
          put_bits(bs, 1, 1); /* allStreamsSameTimeFraming */
  
          /* AudioSpecificConfig */
          if (ctx->object_type == AOT_ALS) {
 -            header_size = par->extradata_size-(ctx->off + 7) >> 3;
 -            avpriv_copy_bits(bs, &par->extradata[ctx->off], header_size);
 +            header_size = par->extradata_size-(ctx->off >> 3);
 +            avpriv_copy_bits(bs, &par->extradata[ctx->off >> 3], header_size);
          } else {
 +            // + 3 assumes not scalable and dependsOnCoreCoder == 0,
 +            // see decode_ga_specific_config in libavcodec/aacdec.c
              avpriv_copy_bits(bs, par->extradata, ctx->off + 3);
  
              if (!ctx->channel_conf) {
-                 avpriv_copy_pce_data(bs, &gb);
 +                GetBitContext gb;
 +                int ret = init_get_bits8(&gb, par->extradata, par->extradata_size);
 +                av_assert0(ret >= 0); // extradata size has been checked already, so this should not fail
 +                skip_bits_long(&gb, ctx->off + 3);
+                 ff_copy_pce_data(bs, &gb);
              }
          }
  
  
      ctx->counter++;
      ctx->counter %= ctx->mod;
 -
 -    return 0;
  }
  
  static int latm_write_packet(AVFormatContext *s, AVPacket *pkt)
  {
 +    LATMContext *ctx = s->priv_data;
 +    AVCodecParameters *par = s->streams[0]->codecpar;
      AVIOContext *pb = s->pb;
      PutBitContext bs;
      int i, len;
      uint8_t loas_header[] = "\x56\xe0\x00";
 -    uint8_t *buf;
  
 -    if (pkt->size > 2 && pkt->data[0] == 0xff && (pkt->data[1] >> 4) == 0xf) {
 -        av_log(s, AV_LOG_ERROR, "ADTS header detected - ADTS will not be incorrectly muxed into LATM\n");
 -        return AVERROR_INVALIDDATA;
 +    if (par->codec_id == AV_CODEC_ID_AAC_LATM)
 +        return ff_raw_write_packet(s, pkt);
 +
 +    if (!par->extradata) {
 +        if(pkt->size > 2 && pkt->data[0] == 0x56 && (pkt->data[1] >> 4) == 0xe &&
 +            (AV_RB16(pkt->data + 1) & 0x1FFF) + 3 == pkt->size)
 +            return ff_raw_write_packet(s, pkt);
 +        else {
 +            uint8_t *side_data;
 +            int side_data_size = 0, ret;
 +
 +            side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
 +                                                &side_data_size);
 +            if (side_data_size) {
 +                if (latm_decode_extradata(ctx, side_data, side_data_size) < 0)
 +                    return AVERROR_INVALIDDATA;
 +                ret = ff_alloc_extradata(par, side_data_size);
 +                if (ret < 0)
 +                    return ret;
 +                memcpy(par->extradata, side_data, side_data_size);
 +            }
 +        }
      }
  
 -    buf = av_malloc(pkt->size+1024);
 -    if (!buf)
 -        return AVERROR(ENOMEM);
 +    if (pkt->size > 0x1fff)
 +        goto too_large;
  
 -    init_put_bits(&bs, buf, pkt->size+1024);
 +    init_put_bits(&bs, ctx->buffer, pkt->size+1024+MAX_EXTRADATA_SIZE);
  
      latm_write_frame_header(s, &bs);
  
      /* The LATM payload is written unaligned */
  
      /* PayloadMux() */
 -    for (i = 0; i < pkt->size; i++)
 -        put_bits(&bs, 8, pkt->data[i]);
 +    if (pkt->size && (pkt->data[0] & 0xe1) == 0x81) {
 +        // Convert byte-aligned DSE to non-aligned.
 +        // Due to the input format encoding we know that
 +        // it is naturally byte-aligned in the input stream,
 +        // so there are no padding bits to account for.
 +        // To avoid having to add padding bits and rearrange
 +        // the whole stream we just remove the byte-align flag.
 +        // This allows us to remux our FATE AAC samples into latm
 +        // files that are still playable with minimal effort.
 +        put_bits(&bs, 8, pkt->data[0] & 0xfe);
 +        avpriv_copy_bits(&bs, pkt->data + 1, 8*pkt->size - 8);
 +    } else
 +        avpriv_copy_bits(&bs, pkt->data, 8*pkt->size);
  
      avpriv_align_put_bits(&bs);
      flush_put_bits(&bs);
  
      len = put_bits_count(&bs) >> 3;
  
 +    if (len > 0x1fff)
 +        goto too_large;
 +
      loas_header[1] |= (len >> 8) & 0x1f;
      loas_header[2] |= len & 0xff;
  
      avio_write(pb, loas_header, 3);
 -    avio_write(pb, buf, len);
 -
 -    av_free(buf);
 +    avio_write(pb, ctx->buffer, len);
  
      return 0;
 +
 +too_large:
 +    av_log(s, AV_LOG_ERROR, "LATM packet size larger than maximum size 0x1fff\n");
 +    return AVERROR_INVALIDDATA;
 +}
 +
 +static int latm_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt)
 +{
 +    int ret = 1;
 +    AVStream *st = s->streams[pkt->stream_index];
 +
 +    if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
 +        if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
 +            ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
 +    }
 +
 +    return ret;
  }
  
  AVOutputFormat ff_latm_muxer = {
      .name           = "latm",
      .long_name      = NULL_IF_CONFIG_SMALL("LOAS/LATM"),
      .mime_type      = "audio/MP4A-LATM",
 -    .extensions     = "latm",
 +    .extensions     = "latm,loas",
      .priv_data_size = sizeof(LATMContext),
      .audio_codec    = AV_CODEC_ID_AAC,
      .video_codec    = AV_CODEC_ID_NONE,
      .write_header   = latm_write_header,
      .write_packet   = latm_write_packet,
      .priv_class     = &latm_muxer_class,
 +    .check_bitstream= latm_check_bitstream,
      .flags          = AVFMT_NOTIMESTAMPS,
  };