yading@10: /* yading@10: * AAC encoder wrapper yading@10: * Copyright (c) 2010 Martin Storsjo 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: #include yading@10: #include yading@10: yading@10: #include "avcodec.h" yading@10: #include "audio_frame_queue.h" yading@10: #include "internal.h" yading@10: #include "mpeg4audio.h" yading@10: yading@10: #define FRAME_SIZE 1024 yading@10: #define ENC_DELAY 1600 yading@10: yading@10: typedef struct AACContext { yading@10: VO_AUDIO_CODECAPI codec_api; yading@10: VO_HANDLE handle; yading@10: VO_MEM_OPERATOR mem_operator; yading@10: VO_CODEC_INIT_USERDATA user_data; yading@10: VO_PBYTE end_buffer; yading@10: AudioFrameQueue afq; yading@10: int last_frame; yading@10: int last_samples; yading@10: } AACContext; yading@10: yading@10: yading@10: static int aac_encode_close(AVCodecContext *avctx) yading@10: { yading@10: AACContext *s = avctx->priv_data; yading@10: yading@10: s->codec_api.Uninit(s->handle); yading@10: av_freep(&avctx->extradata); yading@10: ff_af_queue_close(&s->afq); yading@10: av_freep(&s->end_buffer); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static av_cold int aac_encode_init(AVCodecContext *avctx) yading@10: { yading@10: AACContext *s = avctx->priv_data; yading@10: AACENC_PARAM params = { 0 }; yading@10: int index, ret; yading@10: yading@10: avctx->frame_size = FRAME_SIZE; yading@10: avctx->delay = ENC_DELAY; yading@10: s->last_frame = 2; yading@10: ff_af_queue_init(avctx, &s->afq); yading@10: yading@10: s->end_buffer = av_mallocz(avctx->frame_size * avctx->channels * 2); yading@10: if (!s->end_buffer) { yading@10: ret = AVERROR(ENOMEM); yading@10: goto error; yading@10: } yading@10: yading@10: voGetAACEncAPI(&s->codec_api); yading@10: yading@10: s->mem_operator.Alloc = cmnMemAlloc; yading@10: s->mem_operator.Copy = cmnMemCopy; yading@10: s->mem_operator.Free = cmnMemFree; yading@10: s->mem_operator.Set = cmnMemSet; yading@10: s->mem_operator.Check = cmnMemCheck; yading@10: s->user_data.memflag = VO_IMF_USERMEMOPERATOR; yading@10: s->user_data.memData = &s->mem_operator; yading@10: s->codec_api.Init(&s->handle, VO_AUDIO_CodingAAC, &s->user_data); yading@10: yading@10: params.sampleRate = avctx->sample_rate; yading@10: params.bitRate = avctx->bit_rate; yading@10: params.nChannels = avctx->channels; yading@10: params.adtsUsed = !(avctx->flags & CODEC_FLAG_GLOBAL_HEADER); yading@10: if (s->codec_api.SetParam(s->handle, VO_PID_AAC_ENCPARAM, ¶ms) yading@10: != VO_ERR_NONE) { yading@10: av_log(avctx, AV_LOG_ERROR, "Unable to set encoding parameters\n"); yading@10: ret = AVERROR(EINVAL); yading@10: goto error; yading@10: } yading@10: yading@10: for (index = 0; index < 16; index++) yading@10: if (avctx->sample_rate == avpriv_mpeg4audio_sample_rates[index]) yading@10: break; yading@10: if (index == 16) { yading@10: av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate %d\n", yading@10: avctx->sample_rate); yading@10: ret = AVERROR(ENOSYS); yading@10: goto error; yading@10: } yading@10: if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) { yading@10: avctx->extradata_size = 2; yading@10: avctx->extradata = av_mallocz(avctx->extradata_size + yading@10: FF_INPUT_BUFFER_PADDING_SIZE); yading@10: if (!avctx->extradata) { yading@10: ret = AVERROR(ENOMEM); yading@10: goto error; yading@10: } yading@10: yading@10: avctx->extradata[0] = 0x02 << 3 | index >> 1; yading@10: avctx->extradata[1] = (index & 0x01) << 7 | avctx->channels << 3; yading@10: } yading@10: return 0; yading@10: error: yading@10: aac_encode_close(avctx); yading@10: return ret; yading@10: } yading@10: yading@10: static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, yading@10: const AVFrame *frame, int *got_packet_ptr) yading@10: { yading@10: AACContext *s = avctx->priv_data; yading@10: VO_CODECBUFFER input = { 0 }, output = { 0 }; yading@10: VO_AUDIO_OUTPUTINFO output_info = { { 0 } }; yading@10: VO_PBYTE samples; yading@10: int ret; yading@10: yading@10: /* handle end-of-stream small frame and flushing */ yading@10: if (!frame) { yading@10: if (s->last_frame <= 0) yading@10: return 0; yading@10: if (s->last_samples > 0 && s->last_samples < ENC_DELAY - FRAME_SIZE) { yading@10: s->last_samples = 0; yading@10: s->last_frame--; yading@10: } yading@10: s->last_frame--; yading@10: memset(s->end_buffer, 0, 2 * avctx->channels * avctx->frame_size); yading@10: samples = s->end_buffer; yading@10: } else { yading@10: if (frame->nb_samples < avctx->frame_size) { yading@10: s->last_samples = frame->nb_samples; yading@10: memcpy(s->end_buffer, frame->data[0], 2 * avctx->channels * frame->nb_samples); yading@10: samples = s->end_buffer; yading@10: } else { yading@10: samples = (VO_PBYTE)frame->data[0]; yading@10: } yading@10: /* add current frame to the queue */ yading@10: if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) yading@10: return ret; yading@10: } yading@10: yading@10: if ((ret = ff_alloc_packet2(avctx, avpkt, FFMAX(8192, 768 * avctx->channels))) < 0) yading@10: return ret; yading@10: yading@10: input.Buffer = samples; yading@10: input.Length = 2 * avctx->channels * avctx->frame_size; yading@10: output.Buffer = avpkt->data; yading@10: output.Length = avpkt->size; yading@10: yading@10: s->codec_api.SetInputData(s->handle, &input); yading@10: if (s->codec_api.GetOutputData(s->handle, &output, &output_info) yading@10: != VO_ERR_NONE) { yading@10: av_log(avctx, AV_LOG_ERROR, "Unable to encode frame\n"); yading@10: return AVERROR(EINVAL); yading@10: } 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 = output.Length; yading@10: *got_packet_ptr = 1; yading@10: return 0; yading@10: } yading@10: yading@10: /* duplicated from avpriv_mpeg4audio_sample_rates to avoid shared build yading@10: * failures */ yading@10: static const int mpeg4audio_sample_rates[16] = { yading@10: 96000, 88200, 64000, 48000, 44100, 32000, yading@10: 24000, 22050, 16000, 12000, 11025, 8000, 7350 yading@10: }; yading@10: yading@10: AVCodec ff_libvo_aacenc_encoder = { yading@10: .name = "libvo_aacenc", yading@10: .type = AVMEDIA_TYPE_AUDIO, yading@10: .id = AV_CODEC_ID_AAC, yading@10: .priv_data_size = sizeof(AACContext), yading@10: .init = aac_encode_init, yading@10: .encode2 = aac_encode_frame, yading@10: .close = aac_encode_close, yading@10: .supported_samplerates = mpeg4audio_sample_rates, 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("Android VisualOn AAC (Advanced Audio Coding)"), yading@10: };