[FFmpeg-devel] [PATCH 1/2] lavc/audiotoolboxdec: fix a number of config and timestamp issues

pon pon pon.pon.3876098iu76.ponpon at gmail.com
Fri Apr 1 12:29:05 CEST 2016


it seems you are correct. i can't playback the ac3 files with afplay and
afconvert, though @constant  kAudioFormatAC3 is described in
CoreAudioType.h and i can playback them  with quicktime player(not 7 and
without perian). the results are attached.

i did some tests.

decoding test(gsm_ms_at and ilbc_at not done)
2ch and 51ch, aac_at ac3_at gsm_ms_at adpcm_ima_qt_at ilbc_at alac_at
mp1_at mp2_at mp3_at pcm_alaw_at pcm_mulaw_at
1ch, amr_nb_at
there are errors for pcm_alaw_at  pcm_mulaw_at.
the results are attached.

ponpon



2016-03-31 11:00 GMT+09:00 Rodger Combs <rodger.combs at gmail.com>:

> - ADTS-formatted AAC didn't work
> - Channel layouts were never exported
> - Channel mappings were incorrect beyond stereo
> - Channel counts weren't updated after packets were decoded
> - Timestamps were exported incorrectly
> ---
>  libavcodec/audiotoolboxdec.c | 286
> +++++++++++++++++++++++++++++++++----------
>  1 file changed, 221 insertions(+), 65 deletions(-)
>
> diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c
> index 1fa6f16..4ff46ea 100644
> --- a/libavcodec/audiotoolboxdec.c
> +++ b/libavcodec/audiotoolboxdec.c
> @@ -38,8 +38,9 @@ typedef struct ATDecodeContext {
>      AVPacket in_pkt;
>      AVPacket new_in_pkt;
>      AVBitStreamFilterContext *bsf;
> +    char *decoded_data;
> +    int channel_map[64];
>
> -    unsigned pkt_size;
>      int64_t last_pts;
>      int eof;
>  } ATDecodeContext;
> @@ -81,20 +82,127 @@ static UInt32 ffat_get_format_id(enum AVCodecID
> codec, int profile)
>      }
>  }
>
> -static void ffat_update_ctx(AVCodecContext *avctx)
> +static int ffat_get_channel_id(AudioChannelLabel label)
> +{
> +    if (label == 0)
> +        return -1;
> +    else if (label <= kAudioChannelLabel_LFEScreen)
> +        return label - 1;
> +    else if (label <= kAudioChannelLabel_RightSurround)
> +        return label + 4;
> +    else if (label <= kAudioChannelLabel_CenterSurround)
> +        return label + 1;
> +    else if (label <= kAudioChannelLabel_RightSurroundDirect)
> +        return label + 23;
> +    else if (label <= kAudioChannelLabel_TopBackRight)
> +        return label - 1;
> +    else if (label < kAudioChannelLabel_RearSurroundLeft)
> +        return -1;
> +    else if (label <= kAudioChannelLabel_RearSurroundRight)
> +        return label - 29;
> +    else if (label <= kAudioChannelLabel_RightWide)
> +        return label - 4;
> +    else if (label == kAudioChannelLabel_LFE2)
> +        return ff_ctzll(AV_CH_LOW_FREQUENCY_2);
> +    else if (label == kAudioChannelLabel_Mono)
> +        return ff_ctzll(AV_CH_FRONT_CENTER);
> +    else
> +        return -1;
> +}
> +
> +static int ffat_compare_channel_descriptions(const void* a, const void* b)
> +{
> +    const AudioChannelDescription* da = a;
> +    const AudioChannelDescription* db = b;
> +    return ffat_get_channel_id(da->mChannelLabel) -
> ffat_get_channel_id(db->mChannelLabel);
> +}
> +
> +static AudioChannelLayout *ffat_convert_layout(AudioChannelLayout
> *layout, UInt32* size)
> +{
> +    AudioChannelLayoutTag tag = layout->mChannelLayoutTag;
> +    AudioChannelLayout *new_layout;
> +    if (tag == kAudioChannelLayoutTag_UseChannelDescriptions)
> +        return layout;
> +    else if (tag == kAudioChannelLayoutTag_UseChannelBitmap)
> +
> AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForBitmap,
> +                                   sizeof(UInt32),
> &layout->mChannelBitmap, size);
> +    else
> +
> AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag,
> +                                   sizeof(AudioChannelLayoutTag), &tag,
> size);
> +    new_layout = av_malloc(*size);
> +    if (!new_layout) {
> +        av_free(layout);
> +        return NULL;
> +    }
> +    if (tag == kAudioChannelLayoutTag_UseChannelBitmap)
> +
> AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
> +                               sizeof(UInt32), &layout->mChannelBitmap,
> size, new_layout);
> +    else
> +        AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
> +                               sizeof(AudioChannelLayoutTag), &tag, size,
> new_layout);
> +    new_layout->mChannelLayoutTag =
> kAudioChannelLayoutTag_UseChannelDescriptions;
> +    av_free(layout);
> +    return new_layout;
> +}
> +
> +static int ffat_update_ctx(AVCodecContext *avctx)
>  {
>      ATDecodeContext *at = avctx->priv_data;
> -    AudioStreamBasicDescription in_format;
> -    UInt32 size = sizeof(in_format);
> +    AudioStreamBasicDescription format;
> +    UInt32 size = sizeof(format);
>      if (!AudioConverterGetProperty(at->converter,
>
> kAudioConverterCurrentInputStreamDescription,
> -                                   &size, &in_format)) {
> -        avctx->channels = in_format.mChannelsPerFrame;
> -        at->pkt_size = in_format.mFramesPerPacket;
> +                                   &size, &format)) {
> +        if (format.mSampleRate)
> +            avctx->sample_rate = format.mSampleRate;
> +        avctx->channels = format.mChannelsPerFrame;
> +        avctx->channel_layout =
> av_get_default_channel_layout(avctx->channels);
> +        avctx->frame_size = format.mFramesPerPacket;
> +    }
> +
> +    if (!AudioConverterGetProperty(at->converter,
> +
>  kAudioConverterCurrentOutputStreamDescription,
> +                                   &size, &format)) {
> +        format.mSampleRate = avctx->sample_rate;
> +        format.mChannelsPerFrame = avctx->channels;
> +        AudioConverterSetProperty(at->converter,
> +
> kAudioConverterCurrentOutputStreamDescription,
> +                                  size, &format);
> +    }
> +
> +    if (!AudioConverterGetPropertyInfo(at->converter,
> kAudioConverterOutputChannelLayout,
> +                                       &size, NULL) && size) {
> +        AudioChannelLayout *layout = av_malloc(size);
> +        uint64_t layout_mask = 0;
> +        int i;
> +        if (!layout)
> +            return AVERROR(ENOMEM);
> +        AudioConverterGetProperty(at->converter,
> kAudioConverterOutputChannelLayout,
> +                                  &size, layout);
> +        if (!(layout = ffat_convert_layout(layout, &size)))
> +            return AVERROR(ENOMEM);
> +        for (i = 0; i < layout->mNumberChannelDescriptions; i++) {
> +            int id =
> ffat_get_channel_id(layout->mChannelDescriptions[i].mChannelLabel);
> +            if (id < 0)
> +                goto done;
> +            if (layout_mask & (1 << id))
> +                goto done;
> +            layout_mask |= 1 << id;
> +            layout->mChannelDescriptions[i].mChannelFlags = i; // Abusing
> flags as index
> +        }
> +        avctx->channel_layout = layout_mask;
> +        qsort(layout->mChannelDescriptions,
> layout->mNumberChannelDescriptions,
> +              sizeof(AudioChannelDescription),
> &ffat_compare_channel_descriptions);
> +        for (i = 0; i < layout->mNumberChannelDescriptions; i++)
> +            at->channel_map[i] =
> layout->mChannelDescriptions[i].mChannelFlags;
> +done:
> +        av_free(layout);
>      }
>
> -    if (!at->pkt_size)
> -        at->pkt_size = 2048;
> +    if (!avctx->frame_size)
> +        avctx->frame_size = 2048;
> +
> +    return 0;
>  }
>
>  static void put_descr(PutByteContext *pb, int tag, unsigned int size)
> @@ -106,42 +214,11 @@ static void put_descr(PutByteContext *pb, int tag,
> unsigned int size)
>      bytestream2_put_byte(pb, size & 0x7F);
>  }
>
> -static av_cold int ffat_init_decoder(AVCodecContext *avctx)
> +static int ffat_set_extradata(AVCodecContext *avctx)
>  {
>      ATDecodeContext *at = avctx->priv_data;
> -    OSStatus status;
> -
> -    enum AVSampleFormat sample_fmt = (avctx->bits_per_raw_sample == 32) ?
> -                                     AV_SAMPLE_FMT_S32 :
> AV_SAMPLE_FMT_S16;
> -
> -    AudioStreamBasicDescription in_format = {
> -        .mSampleRate = avctx->sample_rate ? avctx->sample_rate : 44100,
> -        .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile),
> -        .mBytesPerPacket = avctx->block_align,
> -        .mChannelsPerFrame = avctx->channels ? avctx->channels : 1,
> -    };
> -    AudioStreamBasicDescription out_format = {
> -        .mSampleRate = in_format.mSampleRate,
> -        .mFormatID = kAudioFormatLinearPCM,
> -        .mFormatFlags = kAudioFormatFlagIsSignedInteger |
> kAudioFormatFlagIsPacked,
> -        .mFramesPerPacket = 1,
> -        .mChannelsPerFrame = in_format.mChannelsPerFrame,
> -        .mBitsPerChannel = av_get_bytes_per_sample(sample_fmt) * 8,
> -    };
> -
> -    avctx->sample_fmt = sample_fmt;
> -
> -    if (avctx->codec_id == AV_CODEC_ID_ADPCM_IMA_QT)
> -        in_format.mFramesPerPacket = 64;
> -
> -    status = AudioConverterNew(&in_format, &out_format, &at->converter);
> -
> -    if (status != 0) {
> -        av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n",
> (int)status);
> -        return AVERROR_UNKNOWN;
> -    }
> -
>      if (avctx->extradata_size) {
> +        OSStatus status;
>          char *extradata = avctx->extradata;
>          int extradata_size = avctx->extradata_size;
>          if (avctx->codec_id == AV_CODEC_ID_AAC) {
> @@ -180,15 +257,74 @@ static av_cold int ffat_init_decoder(AVCodecContext
> *avctx)
>                                             extradata_size, extradata);
>          if (status != 0)
>              av_log(avctx, AV_LOG_WARNING, "AudioToolbox cookie error:
> %i\n", (int)status);
> +
> +        if (avctx->codec_id == AV_CODEC_ID_AAC)
> +            av_free(extradata);
> +    }
> +    return 0;
> +}
> +
> +static av_cold int ffat_create_decoder(AVCodecContext *avctx)
> +{
> +    ATDecodeContext *at = avctx->priv_data;
> +    OSStatus status;
> +    int i;
> +
> +    enum AVSampleFormat sample_fmt = (avctx->bits_per_raw_sample == 32) ?
> +                                     AV_SAMPLE_FMT_S32 :
> AV_SAMPLE_FMT_S16;
> +
> +    AudioStreamBasicDescription in_format = {
> +        .mSampleRate = avctx->sample_rate ? avctx->sample_rate : 44100,
> +        .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile),
> +        .mBytesPerPacket = avctx->block_align,
> +        .mChannelsPerFrame = avctx->channels ? avctx->channels : 1,
> +    };
> +    AudioStreamBasicDescription out_format = {
> +        .mSampleRate = in_format.mSampleRate,
> +        .mFormatID = kAudioFormatLinearPCM,
> +        .mFormatFlags = kAudioFormatFlagIsSignedInteger |
> kAudioFormatFlagIsPacked,
> +        .mFramesPerPacket = 1,
> +        .mChannelsPerFrame = in_format.mChannelsPerFrame,
> +        .mBitsPerChannel = av_get_bytes_per_sample(sample_fmt) * 8,
> +    };
> +
> +    avctx->sample_fmt = sample_fmt;
> +
> +    if (avctx->codec_id == AV_CODEC_ID_ADPCM_IMA_QT)
> +        in_format.mFramesPerPacket = 64;
> +
> +    status = AudioConverterNew(&in_format, &out_format, &at->converter);
> +
> +    if (status != 0) {
> +        av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n",
> (int)status);
> +        return AVERROR_UNKNOWN;
>      }
>
> +    if ((status = ffat_set_extradata(avctx)) < 0)
> +        return status;
> +
> +    for (i = 0; i < (sizeof(at->channel_map) /
> sizeof(at->channel_map[0])); i++)
> +        at->channel_map[i] = i;
> +
>      ffat_update_ctx(avctx);
>
> +    if(!(at->decoded_data =
> av_malloc(av_get_bytes_per_sample(avctx->sample_fmt)
> +                                      * avctx->frame_size *
> avctx->channels)))
> +        return AVERROR(ENOMEM);
> +
>      at->last_pts = AV_NOPTS_VALUE;
>
>      return 0;
>  }
>
> +static av_cold int ffat_init_decoder(AVCodecContext *avctx)
> +{
> +    if (avctx->channels || avctx->extradata_size)
> +        return ffat_create_decoder(avctx);
> +    else
> +        return 0;
> +}
> +
>  static OSStatus ffat_decode_callback(AudioConverterRef converter, UInt32
> *nb_packets,
>                                       AudioBufferList *data,
>                                       AudioStreamPacketDescription
> **packets,
> @@ -229,6 +365,26 @@ static OSStatus
> ffat_decode_callback(AudioConverterRef converter, UInt32 *nb_pac
>      return 0;
>  }
>
> +#define COPY_SAMPLES(type) \
> +    type *in_ptr = (type*)at->decoded_data; \
> +    type *end_ptr = in_ptr + frame->nb_samples * avctx->channels; \
> +    type *out_ptr = (type*)frame->data[0]; \
> +    for (; in_ptr < end_ptr; in_ptr += avctx->channels, out_ptr +=
> avctx->channels) { \
> +        int c; \
> +        for (c = 0; c < avctx->channels; c++) \
> +            out_ptr[c] = in_ptr[at->channel_map[c]]; \
> +    }
> +
> +static void ffat_copy_samples(AVCodecContext *avctx, AVFrame *frame)
> +{
> +    ATDecodeContext *at = avctx->priv_data;
> +    if (avctx->sample_fmt == AV_SAMPLE_FMT_S32) {
> +        COPY_SAMPLES(int32_t);
> +    } else {
> +        COPY_SAMPLES(int16_t);
> +    }
> +}
> +
>  static int ffat_decode(AVCodecContext *avctx, void *data,
>                         int *got_frame_ptr, AVPacket *avpkt)
>  {
> @@ -237,24 +393,13 @@ static int ffat_decode(AVCodecContext *avctx, void
> *data,
>      int pkt_size = avpkt->size;
>      AVPacket filtered_packet;
>      OSStatus ret;
> -
> -    AudioBufferList out_buffers = {
> -        .mNumberBuffers = 1,
> -        .mBuffers = {
> -            {
> -                .mNumberChannels = avctx->channels,
> -                .mDataByteSize =
> av_get_bytes_per_sample(avctx->sample_fmt) * at->pkt_size * avctx->channels,
> -            }
> -        }
> -    };
> +    AudioBufferList out_buffers;
>
>      if (avctx->codec_id == AV_CODEC_ID_AAC && avpkt->size > 2 &&
>          (AV_RB16(avpkt->data) & 0xfff0) == 0xfff0) {
> -        int first = 0;
>          uint8_t *p_filtered = NULL;
>          int      n_filtered = 0;
>          if (!at->bsf) {
> -            first = 1;
>              if(!(at->bsf = av_bitstream_filter_init("aac_adtstoasc")))
>                  return AVERROR(ENOMEM);
>          }
> @@ -267,16 +412,24 @@ static int ffat_decode(AVCodecContext *avctx, void
> *data,
>              avpkt->data = p_filtered;
>              avpkt->size = n_filtered;
>          }
> +    }
>
> -        if (first) {
> -            if ((ret = ffat_set_extradata(avctx)) < 0)
> -                return ret;
> -            ffat_update_ctx(avctx);
> -            out_buffers.mBuffers[0].mNumberChannels = avctx->channels;
> -            out_buffers.mBuffers[0].mDataByteSize =
> av_get_bytes_per_sample(avctx->sample_fmt) * at->pkt_size * avctx->channels;
> -        }
> +    if (!at->converter) {
> +        if ((ret = ffat_create_decoder(avctx)) < 0)
> +            return ret;
>      }
>
> +    out_buffers = (AudioBufferList){
> +        .mNumberBuffers = 1,
> +        .mBuffers = {
> +            {
> +                .mNumberChannels = avctx->channels,
> +                .mDataByteSize =
> av_get_bytes_per_sample(avctx->sample_fmt) * avctx->frame_size
> +                                 * avctx->channels,
> +            }
> +        }
> +    };
> +
>      av_packet_unref(&at->new_in_pkt);
>
>      if (avpkt->size) {
> @@ -289,17 +442,19 @@ static int ffat_decode(AVCodecContext *avctx, void
> *data,
>
>      frame->sample_rate = avctx->sample_rate;
>
> -    frame->nb_samples = at->pkt_size;
> -    ff_get_buffer(avctx, frame, 0);
> +    frame->nb_samples = avctx->frame_size;
>
> -    out_buffers.mBuffers[0].mData = frame->data[0];
> +    out_buffers.mBuffers[0].mData = at->decoded_data;
>
>      ret = AudioConverterFillComplexBuffer(at->converter,
> ffat_decode_callback, avctx,
>                                            &frame->nb_samples,
> &out_buffers, NULL);
>      if ((!ret || ret == 1) && frame->nb_samples) {
> +        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
> +            return ret;
> +        ffat_copy_samples(avctx, frame);
>          *got_frame_ptr = 1;
>          if (at->last_pts != AV_NOPTS_VALUE) {
> -            frame->pts = at->last_pts;
> +            frame->pkt_pts = at->last_pts;
>              at->last_pts = avpkt->pts;
>          }
>      } else if (ret && ret != 1) {
> @@ -325,6 +480,7 @@ static av_cold int ffat_close_decoder(AVCodecContext
> *avctx)
>      AudioConverterDispose(at->converter);
>      av_packet_unref(&at->new_in_pkt);
>      av_packet_unref(&at->in_pkt);
> +    av_free(at->decoded_data);
>      return 0;
>  }
>
> --
> 2.7.3
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ac3_file_2ch.log
Type: application/octet-stream
Size: 3748 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ac3_file_51ch.log
Type: application/octet-stream
Size: 3672 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0001.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: afplay_ac3_file_2ch.log
Type: application/octet-stream
Size: 93 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0002.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: afplay_ac3_file_51ch.log
Type: application/octet-stream
Size: 79 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0003.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: afplay_pcm_alaw_file_2ch.log
Type: application/octet-stream
Size: 256 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0004.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: afplay_pcm_alaw_file_51ch.log
Type: application/octet-stream
Size: 249 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0005.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: afplay_pcm_mulaw_file_2ch.log
Type: application/octet-stream
Size: 258 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0006.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: afplay_pcm_mulaw_file_51ch.log
Type: application/octet-stream
Size: 250 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0007.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pcm_alaw_file_2ch.log
Type: application/octet-stream
Size: 14486 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0008.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pcm_alaw_file_51ch.log
Type: application/octet-stream
Size: 7315 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0009.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pcm_mulaw_file_2ch.log
Type: application/octet-stream
Size: 14530 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0010.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pcm_mulaw_file_51ch.log
Type: application/octet-stream
Size: 7329 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20160401/50b87f06/attachment-0011.obj>


More information about the ffmpeg-devel mailing list