yading@10: /* yading@10: * Interface to libfaac for aac encoding yading@10: * Copyright (c) 2002 Gildas Bazin yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * Interface to libfaac for aac encoding. yading@10: */ yading@10: yading@10: #include yading@10: yading@10: #include "libavutil/channel_layout.h" yading@10: #include "libavutil/common.h" yading@10: #include "avcodec.h" yading@10: #include "audio_frame_queue.h" yading@10: #include "internal.h" yading@10: yading@10: yading@10: /* libfaac has an encoder delay of 1024 samples */ yading@10: #define FAAC_DELAY_SAMPLES 1024 yading@10: yading@10: typedef struct FaacAudioContext { yading@10: faacEncHandle faac_handle; yading@10: AudioFrameQueue afq; yading@10: } FaacAudioContext; yading@10: yading@10: static av_cold int Faac_encode_close(AVCodecContext *avctx) yading@10: { yading@10: FaacAudioContext *s = avctx->priv_data; yading@10: yading@10: av_freep(&avctx->extradata); yading@10: ff_af_queue_close(&s->afq); yading@10: yading@10: if (s->faac_handle) yading@10: faacEncClose(s->faac_handle); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static const int channel_maps[][6] = { yading@10: { 2, 0, 1 }, //< C L R yading@10: { 2, 0, 1, 3 }, //< C L R Cs yading@10: { 2, 0, 1, 3, 4 }, //< C L R Ls Rs yading@10: { 2, 0, 1, 4, 5, 3 }, //< C L R Ls Rs LFE yading@10: }; yading@10: yading@10: static av_cold int Faac_encode_init(AVCodecContext *avctx) yading@10: { yading@10: FaacAudioContext *s = avctx->priv_data; yading@10: faacEncConfigurationPtr faac_cfg; yading@10: unsigned long samples_input, max_bytes_output; yading@10: int ret; yading@10: yading@10: /* number of channels */ yading@10: if (avctx->channels < 1 || avctx->channels > 6) { yading@10: av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed\n", avctx->channels); yading@10: ret = AVERROR(EINVAL); yading@10: goto error; yading@10: } yading@10: yading@10: s->faac_handle = faacEncOpen(avctx->sample_rate, yading@10: avctx->channels, yading@10: &samples_input, &max_bytes_output); yading@10: if (!s->faac_handle) { yading@10: av_log(avctx, AV_LOG_ERROR, "error in faacEncOpen()\n"); yading@10: ret = AVERROR_UNKNOWN; yading@10: goto error; yading@10: } yading@10: yading@10: /* check faac version */ yading@10: faac_cfg = faacEncGetCurrentConfiguration(s->faac_handle); yading@10: if (faac_cfg->version != FAAC_CFG_VERSION) { yading@10: av_log(avctx, AV_LOG_ERROR, "wrong libfaac version (compiled for: %d, using %d)\n", FAAC_CFG_VERSION, faac_cfg->version); yading@10: ret = AVERROR(EINVAL); yading@10: goto error; yading@10: } yading@10: yading@10: /* put the options in the configuration struct */ yading@10: switch(avctx->profile) { yading@10: case FF_PROFILE_AAC_MAIN: yading@10: faac_cfg->aacObjectType = MAIN; yading@10: break; yading@10: case FF_PROFILE_UNKNOWN: yading@10: case FF_PROFILE_AAC_LOW: yading@10: faac_cfg->aacObjectType = LOW; yading@10: break; yading@10: case FF_PROFILE_AAC_SSR: yading@10: faac_cfg->aacObjectType = SSR; yading@10: break; yading@10: case FF_PROFILE_AAC_LTP: yading@10: faac_cfg->aacObjectType = LTP; yading@10: break; yading@10: default: yading@10: av_log(avctx, AV_LOG_ERROR, "invalid AAC profile\n"); yading@10: ret = AVERROR(EINVAL); yading@10: goto error; yading@10: } yading@10: faac_cfg->mpegVersion = MPEG4; yading@10: faac_cfg->useTns = 0; yading@10: faac_cfg->allowMidside = 1; yading@10: faac_cfg->bitRate = avctx->bit_rate / avctx->channels; yading@10: faac_cfg->bandWidth = avctx->cutoff; yading@10: if(avctx->flags & CODEC_FLAG_QSCALE) { yading@10: faac_cfg->bitRate = 0; yading@10: faac_cfg->quantqual = avctx->global_quality / FF_QP2LAMBDA; yading@10: } yading@10: faac_cfg->outputFormat = 1; yading@10: faac_cfg->inputFormat = FAAC_INPUT_16BIT; yading@10: if (avctx->channels > 2) yading@10: memcpy(faac_cfg->channel_map, channel_maps[avctx->channels-3], yading@10: avctx->channels * sizeof(int)); yading@10: yading@10: avctx->frame_size = samples_input / avctx->channels; yading@10: yading@10: /* Set decoder specific info */ yading@10: avctx->extradata_size = 0; yading@10: if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) { yading@10: yading@10: unsigned char *buffer = NULL; yading@10: unsigned long decoder_specific_info_size; yading@10: yading@10: if (!faacEncGetDecoderSpecificInfo(s->faac_handle, &buffer, yading@10: &decoder_specific_info_size)) { yading@10: avctx->extradata = av_malloc(decoder_specific_info_size + FF_INPUT_BUFFER_PADDING_SIZE); yading@10: if (!avctx->extradata) { yading@10: ret = AVERROR(ENOMEM); yading@10: goto error; yading@10: } yading@10: avctx->extradata_size = decoder_specific_info_size; yading@10: memcpy(avctx->extradata, buffer, avctx->extradata_size); yading@10: faac_cfg->outputFormat = 0; yading@10: } yading@10: free(buffer); yading@10: } yading@10: yading@10: if (!faacEncSetConfiguration(s->faac_handle, faac_cfg)) { yading@10: av_log(avctx, AV_LOG_ERROR, "libfaac doesn't support this output format!\n"); yading@10: ret = AVERROR(EINVAL); yading@10: goto error; yading@10: } yading@10: yading@10: avctx->delay = FAAC_DELAY_SAMPLES; yading@10: ff_af_queue_init(avctx, &s->afq); yading@10: yading@10: return 0; yading@10: error: yading@10: Faac_encode_close(avctx); yading@10: return ret; yading@10: } yading@10: yading@10: static int Faac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, yading@10: const AVFrame *frame, int *got_packet_ptr) yading@10: { yading@10: FaacAudioContext *s = avctx->priv_data; yading@10: int bytes_written, ret; yading@10: int num_samples = frame ? frame->nb_samples : 0; yading@10: void *samples = frame ? frame->data[0] : NULL; yading@10: yading@10: if ((ret = ff_alloc_packet2(avctx, avpkt, (7 + 768) * avctx->channels)) < 0) yading@10: return ret; yading@10: yading@10: bytes_written = faacEncEncode(s->faac_handle, samples, yading@10: num_samples * avctx->channels, yading@10: avpkt->data, avpkt->size); yading@10: if (bytes_written < 0) { yading@10: av_log(avctx, AV_LOG_ERROR, "faacEncEncode() error\n"); yading@10: return bytes_written; yading@10: } yading@10: yading@10: /* add current frame to the queue */ yading@10: if (frame) { yading@10: if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) yading@10: return ret; yading@10: } yading@10: yading@10: if (!bytes_written) yading@10: return 0; yading@10: yading@10: /* Get the next frame pts/duration */ yading@10: ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, yading@10: &avpkt->duration); yading@10: yading@10: avpkt->size = bytes_written; yading@10: *got_packet_ptr = 1; yading@10: return 0; yading@10: } yading@10: yading@10: static const AVProfile profiles[] = { yading@10: { FF_PROFILE_AAC_MAIN, "Main" }, yading@10: { FF_PROFILE_AAC_LOW, "LC" }, yading@10: { FF_PROFILE_AAC_SSR, "SSR" }, yading@10: { FF_PROFILE_AAC_LTP, "LTP" }, yading@10: { FF_PROFILE_UNKNOWN }, yading@10: }; yading@10: yading@10: static const uint64_t faac_channel_layouts[] = { yading@10: AV_CH_LAYOUT_MONO, yading@10: AV_CH_LAYOUT_STEREO, yading@10: AV_CH_LAYOUT_SURROUND, yading@10: AV_CH_LAYOUT_4POINT0, yading@10: AV_CH_LAYOUT_5POINT0_BACK, yading@10: AV_CH_LAYOUT_5POINT1_BACK, yading@10: 0 yading@10: }; yading@10: yading@10: AVCodec ff_libfaac_encoder = { yading@10: .name = "libfaac", yading@10: .type = AVMEDIA_TYPE_AUDIO, yading@10: .id = AV_CODEC_ID_AAC, yading@10: .priv_data_size = sizeof(FaacAudioContext), yading@10: .init = Faac_encode_init, yading@10: .encode2 = Faac_encode_frame, yading@10: .close = Faac_encode_close, yading@10: .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY, yading@10: .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, yading@10: AV_SAMPLE_FMT_NONE }, yading@10: .long_name = NULL_IF_CONFIG_SMALL("libfaac AAC (Advanced Audio Coding)"), yading@10: .profiles = NULL_IF_CONFIG_SMALL(profiles), yading@10: .channel_layouts = faac_channel_layouts, yading@10: };