Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * AAC encoder wrapper | |
3 | * Copyright (c) 2010 Martin Storsjo | |
4 | * | |
5 | * This file is part of FFmpeg. | |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * FFmpeg is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with FFmpeg; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | #include <vo-aacenc/voAAC.h> | |
23 | #include <vo-aacenc/cmnMemory.h> | |
24 | ||
25 | #include "avcodec.h" | |
26 | #include "audio_frame_queue.h" | |
27 | #include "internal.h" | |
28 | #include "mpeg4audio.h" | |
29 | ||
30 | #define FRAME_SIZE 1024 | |
31 | #define ENC_DELAY 1600 | |
32 | ||
33 | typedef struct AACContext { | |
34 | VO_AUDIO_CODECAPI codec_api; | |
35 | VO_HANDLE handle; | |
36 | VO_MEM_OPERATOR mem_operator; | |
37 | VO_CODEC_INIT_USERDATA user_data; | |
38 | VO_PBYTE end_buffer; | |
39 | AudioFrameQueue afq; | |
40 | int last_frame; | |
41 | int last_samples; | |
42 | } AACContext; | |
43 | ||
44 | ||
45 | static int aac_encode_close(AVCodecContext *avctx) | |
46 | { | |
47 | AACContext *s = avctx->priv_data; | |
48 | ||
49 | s->codec_api.Uninit(s->handle); | |
50 | av_freep(&avctx->extradata); | |
51 | ff_af_queue_close(&s->afq); | |
52 | av_freep(&s->end_buffer); | |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
57 | static av_cold int aac_encode_init(AVCodecContext *avctx) | |
58 | { | |
59 | AACContext *s = avctx->priv_data; | |
60 | AACENC_PARAM params = { 0 }; | |
61 | int index, ret; | |
62 | ||
63 | avctx->frame_size = FRAME_SIZE; | |
f6fa7814 | 64 | avctx->initial_padding = ENC_DELAY; |
2ba45a60 DM |
65 | s->last_frame = 2; |
66 | ff_af_queue_init(avctx, &s->afq); | |
67 | ||
68 | s->end_buffer = av_mallocz(avctx->frame_size * avctx->channels * 2); | |
69 | if (!s->end_buffer) { | |
70 | ret = AVERROR(ENOMEM); | |
71 | goto error; | |
72 | } | |
73 | ||
74 | voGetAACEncAPI(&s->codec_api); | |
75 | ||
76 | s->mem_operator.Alloc = cmnMemAlloc; | |
77 | s->mem_operator.Copy = cmnMemCopy; | |
78 | s->mem_operator.Free = cmnMemFree; | |
79 | s->mem_operator.Set = cmnMemSet; | |
80 | s->mem_operator.Check = cmnMemCheck; | |
81 | s->user_data.memflag = VO_IMF_USERMEMOPERATOR; | |
82 | s->user_data.memData = &s->mem_operator; | |
83 | s->codec_api.Init(&s->handle, VO_AUDIO_CodingAAC, &s->user_data); | |
84 | ||
85 | params.sampleRate = avctx->sample_rate; | |
86 | params.bitRate = avctx->bit_rate; | |
87 | params.nChannels = avctx->channels; | |
88 | params.adtsUsed = !(avctx->flags & CODEC_FLAG_GLOBAL_HEADER); | |
89 | if (s->codec_api.SetParam(s->handle, VO_PID_AAC_ENCPARAM, ¶ms) | |
90 | != VO_ERR_NONE) { | |
91 | av_log(avctx, AV_LOG_ERROR, "Unable to set encoding parameters\n"); | |
92 | ret = AVERROR(EINVAL); | |
93 | goto error; | |
94 | } | |
95 | ||
96 | for (index = 0; index < 16; index++) | |
97 | if (avctx->sample_rate == avpriv_mpeg4audio_sample_rates[index]) | |
98 | break; | |
99 | if (index == 16) { | |
100 | av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate %d\n", | |
101 | avctx->sample_rate); | |
102 | ret = AVERROR(ENOSYS); | |
103 | goto error; | |
104 | } | |
105 | if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) { | |
106 | avctx->extradata_size = 2; | |
107 | avctx->extradata = av_mallocz(avctx->extradata_size + | |
108 | FF_INPUT_BUFFER_PADDING_SIZE); | |
109 | if (!avctx->extradata) { | |
110 | ret = AVERROR(ENOMEM); | |
111 | goto error; | |
112 | } | |
113 | ||
114 | avctx->extradata[0] = 0x02 << 3 | index >> 1; | |
115 | avctx->extradata[1] = (index & 0x01) << 7 | avctx->channels << 3; | |
116 | } | |
117 | return 0; | |
118 | error: | |
119 | aac_encode_close(avctx); | |
120 | return ret; | |
121 | } | |
122 | ||
123 | static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |
124 | const AVFrame *frame, int *got_packet_ptr) | |
125 | { | |
126 | AACContext *s = avctx->priv_data; | |
127 | VO_CODECBUFFER input = { 0 }, output = { 0 }; | |
128 | VO_AUDIO_OUTPUTINFO output_info = { { 0 } }; | |
129 | VO_PBYTE samples; | |
130 | int ret; | |
131 | ||
132 | /* handle end-of-stream small frame and flushing */ | |
133 | if (!frame) { | |
134 | if (s->last_frame <= 0) | |
135 | return 0; | |
136 | if (s->last_samples > 0 && s->last_samples < ENC_DELAY - FRAME_SIZE) { | |
137 | s->last_samples = 0; | |
138 | s->last_frame--; | |
139 | } | |
140 | s->last_frame--; | |
141 | memset(s->end_buffer, 0, 2 * avctx->channels * avctx->frame_size); | |
142 | samples = s->end_buffer; | |
143 | } else { | |
144 | if (frame->nb_samples < avctx->frame_size) { | |
145 | s->last_samples = frame->nb_samples; | |
146 | memcpy(s->end_buffer, frame->data[0], 2 * avctx->channels * frame->nb_samples); | |
147 | samples = s->end_buffer; | |
148 | } else { | |
149 | samples = (VO_PBYTE)frame->data[0]; | |
150 | } | |
151 | /* add current frame to the queue */ | |
152 | if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) | |
153 | return ret; | |
154 | } | |
155 | ||
156 | if ((ret = ff_alloc_packet2(avctx, avpkt, FFMAX(8192, 768 * avctx->channels))) < 0) | |
157 | return ret; | |
158 | ||
159 | input.Buffer = samples; | |
160 | input.Length = 2 * avctx->channels * avctx->frame_size; | |
161 | output.Buffer = avpkt->data; | |
162 | output.Length = avpkt->size; | |
163 | ||
164 | s->codec_api.SetInputData(s->handle, &input); | |
165 | if (s->codec_api.GetOutputData(s->handle, &output, &output_info) | |
166 | != VO_ERR_NONE) { | |
167 | av_log(avctx, AV_LOG_ERROR, "Unable to encode frame\n"); | |
168 | return AVERROR(EINVAL); | |
169 | } | |
170 | ||
171 | /* Get the next frame pts/duration */ | |
172 | ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, | |
173 | &avpkt->duration); | |
174 | ||
175 | avpkt->size = output.Length; | |
176 | *got_packet_ptr = 1; | |
177 | return 0; | |
178 | } | |
179 | ||
180 | /* duplicated from avpriv_mpeg4audio_sample_rates to avoid shared build | |
181 | * failures */ | |
182 | static const int mpeg4audio_sample_rates[16] = { | |
183 | 96000, 88200, 64000, 48000, 44100, 32000, | |
184 | 24000, 22050, 16000, 12000, 11025, 8000, 7350 | |
185 | }; | |
186 | ||
187 | AVCodec ff_libvo_aacenc_encoder = { | |
188 | .name = "libvo_aacenc", | |
189 | .long_name = NULL_IF_CONFIG_SMALL("Android VisualOn AAC (Advanced Audio Coding)"), | |
190 | .type = AVMEDIA_TYPE_AUDIO, | |
191 | .id = AV_CODEC_ID_AAC, | |
192 | .priv_data_size = sizeof(AACContext), | |
193 | .init = aac_encode_init, | |
194 | .encode2 = aac_encode_frame, | |
195 | .close = aac_encode_close, | |
196 | .supported_samplerates = mpeg4audio_sample_rates, | |
197 | .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY, | |
198 | .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, | |
199 | AV_SAMPLE_FMT_NONE }, | |
200 | }; |