blob: 680771fa51c8cc106514030dfcdc58c22b813dcc [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "C2SoftAacDec"
19#include <log/log.h>
20
21#include <inttypes.h>
22#include <math.h>
23#include <numeric>
24
25#include <cutils/properties.h>
26#include <media/stagefright/foundation/MediaDefs.h>
27#include <media/stagefright/foundation/hexdump.h>
28#include <media/stagefright/MediaErrors.h>
29#include <utils/misc.h>
30
31#include <C2PlatformSupport.h>
32#include <SimpleC2Interface.h>
33
34#include "C2SoftAacDec.h"
35
36#define FILEREAD_MAX_LAYERS 2
37
38#define DRC_DEFAULT_MOBILE_REF_LEVEL -16.0 /* 64*-0.25dB = -16 dB below full scale for mobile conf */
39#define DRC_DEFAULT_MOBILE_DRC_CUT 1.0 /* maximum compression of dynamic range for mobile conf */
40#define DRC_DEFAULT_MOBILE_DRC_BOOST 1.0 /* maximum compression of dynamic range for mobile conf */
41#define DRC_DEFAULT_MOBILE_DRC_HEAVY C2Config::DRC_COMPRESSION_HEAVY /* switch for heavy compression for mobile conf */
42#define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */
Jean-Michel Trivi4b936cc2020-02-17 16:29:47 -080043#define DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS (0.25) /* decoder output loudness; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
Pawin Vongmasa36653902018-11-15 00:10:25 -080044#define DRC_DEFAULT_MOBILE_ENC_LEVEL (0.25) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
45#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */
46// names of properties that can be used to override the default DRC settings
47#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level"
48#define PROP_DRC_OVERRIDE_CUT "aac_drc_cut"
49#define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost"
50#define PROP_DRC_OVERRIDE_HEAVY "aac_drc_heavy"
51#define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level"
52#define PROP_DRC_OVERRIDE_EFFECT "ro.aac_drc_effect_type"
53
54namespace android {
55
Wonsik Kimab34ed62019-01-31 15:28:46 -080056constexpr char COMPONENT_NAME[] = "c2.android.aac.decoder";
57
58class C2SoftAacDec::IntfImpl : public SimpleInterface<void>::BaseParams {
Pawin Vongmasa36653902018-11-15 00:10:25 -080059public:
60 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
Wonsik Kimab34ed62019-01-31 15:28:46 -080061 : SimpleInterface<void>::BaseParams(
62 helper,
63 COMPONENT_NAME,
64 C2Component::KIND_DECODER,
65 C2Component::DOMAIN_AUDIO,
66 MEDIA_MIMETYPE_AUDIO_AAC) {
67 noPrivateBuffers();
68 noInputReferences();
69 noOutputReferences();
70 noInputLatency();
71 noTimeStretch();
Pawin Vongmasa36653902018-11-15 00:10:25 -080072
73 addParameter(
Wonsik Kimab34ed62019-01-31 15:28:46 -080074 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
75 .withConstValue(new C2PortActualDelayTuning::output(2u))
Pawin Vongmasa36653902018-11-15 00:10:25 -080076 .build());
77
78 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -080079 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
Pawin Vongmasa36653902018-11-15 00:10:25 -080080 .withDefault(new C2StreamSampleRateInfo::output(0u, 44100))
81 .withFields({C2F(mSampleRate, value).oneOf({
Sungtak Leed7f88ee2019-11-14 16:04:25 -080082 7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000,
83 44100, 48000, 64000, 88200, 96000
Pawin Vongmasa36653902018-11-15 00:10:25 -080084 })})
85 .withSetter(Setter<decltype(*mSampleRate)>::NonStrictValueWithNoDeps)
86 .build());
87
88 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -080089 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
Pawin Vongmasa36653902018-11-15 00:10:25 -080090 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
91 .withFields({C2F(mChannelCount, value).inRange(1, 8)})
92 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
93 .build());
94
95 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -080096 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
97 .withDefault(new C2StreamBitrateInfo::input(0u, 64000))
Pawin Vongmasa36653902018-11-15 00:10:25 -080098 .withFields({C2F(mBitrate, value).inRange(8000, 960000)})
99 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
100 .build());
101
102 addParameter(
103 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
104 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192))
105 .build());
106
107 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800108 DefineParam(mAacFormat, C2_PARAMKEY_AAC_PACKAGING)
109 .withDefault(new C2StreamAacFormatInfo::input(0u, C2Config::AAC_PACKAGING_RAW))
Pawin Vongmasa36653902018-11-15 00:10:25 -0800110 .withFields({C2F(mAacFormat, value).oneOf({
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800111 C2Config::AAC_PACKAGING_RAW, C2Config::AAC_PACKAGING_ADTS
Pawin Vongmasa36653902018-11-15 00:10:25 -0800112 })})
113 .withSetter(Setter<decltype(*mAacFormat)>::StrictValueWithNoDeps)
114 .build());
115
116 addParameter(
117 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
118 .withDefault(new C2StreamProfileLevelInfo::input(0u,
119 C2Config::PROFILE_AAC_LC, C2Config::LEVEL_UNUSED))
120 .withFields({
121 C2F(mProfileLevel, profile).oneOf({
122 C2Config::PROFILE_AAC_LC,
123 C2Config::PROFILE_AAC_HE,
124 C2Config::PROFILE_AAC_HE_PS,
125 C2Config::PROFILE_AAC_LD,
126 C2Config::PROFILE_AAC_ELD,
127 C2Config::PROFILE_AAC_ER_SCALABLE,
128 C2Config::PROFILE_AAC_XHE}),
129 C2F(mProfileLevel, level).oneOf({
130 C2Config::LEVEL_UNUSED
131 })
132 })
133 .withSetter(ProfileLevelSetter)
134 .build());
135
136 addParameter(
137 DefineParam(mDrcCompressMode, C2_PARAMKEY_DRC_COMPRESSION_MODE)
138 .withDefault(new C2StreamDrcCompressionModeTuning::input(0u, C2Config::DRC_COMPRESSION_HEAVY))
139 .withFields({
140 C2F(mDrcCompressMode, value).oneOf({
141 C2Config::DRC_COMPRESSION_ODM_DEFAULT,
142 C2Config::DRC_COMPRESSION_NONE,
143 C2Config::DRC_COMPRESSION_LIGHT,
144 C2Config::DRC_COMPRESSION_HEAVY})
145 })
146 .withSetter(Setter<decltype(*mDrcCompressMode)>::StrictValueWithNoDeps)
147 .build());
148
149 addParameter(
150 DefineParam(mDrcTargetRefLevel, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL)
151 .withDefault(new C2StreamDrcTargetReferenceLevelTuning::input(0u, DRC_DEFAULT_MOBILE_REF_LEVEL))
152 .withFields({C2F(mDrcTargetRefLevel, value).inRange(-31.75, 0.25)})
153 .withSetter(Setter<decltype(*mDrcTargetRefLevel)>::StrictValueWithNoDeps)
154 .build());
155
156 addParameter(
157 DefineParam(mDrcEncTargetLevel, C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL)
158 .withDefault(new C2StreamDrcEncodedTargetLevelTuning::input(0u, DRC_DEFAULT_MOBILE_ENC_LEVEL))
159 .withFields({C2F(mDrcEncTargetLevel, value).inRange(-31.75, 0.25)})
160 .withSetter(Setter<decltype(*mDrcEncTargetLevel)>::StrictValueWithNoDeps)
161 .build());
162
163 addParameter(
164 DefineParam(mDrcBoostFactor, C2_PARAMKEY_DRC_BOOST_FACTOR)
165 .withDefault(new C2StreamDrcBoostFactorTuning::input(0u, DRC_DEFAULT_MOBILE_DRC_BOOST))
166 .withFields({C2F(mDrcBoostFactor, value).inRange(0, 1.)})
167 .withSetter(Setter<decltype(*mDrcBoostFactor)>::StrictValueWithNoDeps)
168 .build());
169
170 addParameter(
171 DefineParam(mDrcAttenuationFactor, C2_PARAMKEY_DRC_ATTENUATION_FACTOR)
172 .withDefault(new C2StreamDrcAttenuationFactorTuning::input(0u, DRC_DEFAULT_MOBILE_DRC_CUT))
173 .withFields({C2F(mDrcAttenuationFactor, value).inRange(0, 1.)})
174 .withSetter(Setter<decltype(*mDrcAttenuationFactor)>::StrictValueWithNoDeps)
175 .build());
176
177 addParameter(
178 DefineParam(mDrcEffectType, C2_PARAMKEY_DRC_EFFECT_TYPE)
179 .withDefault(new C2StreamDrcEffectTypeTuning::input(0u, C2Config::DRC_EFFECT_LIMITED_PLAYBACK_RANGE))
180 .withFields({
181 C2F(mDrcEffectType, value).oneOf({
182 C2Config::DRC_EFFECT_ODM_DEFAULT,
183 C2Config::DRC_EFFECT_OFF,
184 C2Config::DRC_EFFECT_NONE,
185 C2Config::DRC_EFFECT_LATE_NIGHT,
186 C2Config::DRC_EFFECT_NOISY_ENVIRONMENT,
187 C2Config::DRC_EFFECT_LIMITED_PLAYBACK_RANGE,
188 C2Config::DRC_EFFECT_LOW_PLAYBACK_LEVEL,
189 C2Config::DRC_EFFECT_DIALOG_ENHANCEMENT,
190 C2Config::DRC_EFFECT_GENERAL_COMPRESSION})
191 })
192 .withSetter(Setter<decltype(*mDrcEffectType)>::StrictValueWithNoDeps)
193 .build());
Jean-Michel Trivi4b936cc2020-02-17 16:29:47 -0800194
195 addParameter(
196 DefineParam(mDrcOutputLoudness, C2_PARAMKEY_DRC_OUTPUT_LOUDNESS)
197 .withDefault(new C2StreamDrcOutputLoudnessTuning::output(0u, DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS))
198 .withFields({C2F(mDrcOutputLoudness, value).inRange(-57.75, 0.25)})
199 .withSetter(Setter<decltype(*mDrcOutputLoudness)>::StrictValueWithNoDeps)
200 .build());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800201 }
202
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800203 bool isAdts() const { return mAacFormat->value == C2Config::AAC_PACKAGING_ADTS; }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800204 static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me) {
205 (void)mayBlock;
206 (void)me; // TODO: validate
207 return C2R::Ok();
208 }
209 int32_t getDrcCompressMode() const { return mDrcCompressMode->value == C2Config::DRC_COMPRESSION_HEAVY ? 1 : 0; }
210 int32_t getDrcTargetRefLevel() const { return (mDrcTargetRefLevel->value <= 0 ? -mDrcTargetRefLevel->value * 4. + 0.5 : -1); }
211 int32_t getDrcEncTargetLevel() const { return (mDrcEncTargetLevel->value <= 0 ? -mDrcEncTargetLevel->value * 4. + 0.5 : -1); }
212 int32_t getDrcBoostFactor() const { return mDrcBoostFactor->value * 127. + 0.5; }
213 int32_t getDrcAttenuationFactor() const { return mDrcAttenuationFactor->value * 127. + 0.5; }
214 int32_t getDrcEffectType() const { return mDrcEffectType->value; }
Jean-Michel Trivi4b936cc2020-02-17 16:29:47 -0800215 int32_t getDrcOutputLoudness() const { return (mDrcOutputLoudness->value <= 0 ? -mDrcOutputLoudness->value * 4. + 0.5 : -1); }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800216
217private:
Pawin Vongmasa36653902018-11-15 00:10:25 -0800218 std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
219 std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800220 std::shared_ptr<C2StreamBitrateInfo::input> mBitrate;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800221 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
222 std::shared_ptr<C2StreamAacFormatInfo::input> mAacFormat;
223 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
224 std::shared_ptr<C2StreamDrcCompressionModeTuning::input> mDrcCompressMode;
225 std::shared_ptr<C2StreamDrcTargetReferenceLevelTuning::input> mDrcTargetRefLevel;
226 std::shared_ptr<C2StreamDrcEncodedTargetLevelTuning::input> mDrcEncTargetLevel;
227 std::shared_ptr<C2StreamDrcBoostFactorTuning::input> mDrcBoostFactor;
228 std::shared_ptr<C2StreamDrcAttenuationFactorTuning::input> mDrcAttenuationFactor;
229 std::shared_ptr<C2StreamDrcEffectTypeTuning::input> mDrcEffectType;
Jean-Michel Trivi4b936cc2020-02-17 16:29:47 -0800230 std::shared_ptr<C2StreamDrcOutputLoudnessTuning::output> mDrcOutputLoudness;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800231 // TODO Add : C2StreamAacSbrModeTuning
232};
233
Pawin Vongmasa36653902018-11-15 00:10:25 -0800234C2SoftAacDec::C2SoftAacDec(
235 const char *name,
236 c2_node_id_t id,
237 const std::shared_ptr<IntfImpl> &intfImpl)
238 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
239 mIntf(intfImpl),
240 mAACDecoder(nullptr),
241 mStreamInfo(nullptr),
242 mSignalledError(false),
243 mOutputDelayRingBuffer(nullptr) {
244}
245
246C2SoftAacDec::~C2SoftAacDec() {
247 onRelease();
248}
249
250c2_status_t C2SoftAacDec::onInit() {
251 status_t err = initDecoder();
252 return err == OK ? C2_OK : C2_CORRUPTED;
253}
254
255c2_status_t C2SoftAacDec::onStop() {
256 drainDecoder();
257 // reset the "configured" state
258 mOutputDelayCompensated = 0;
259 mOutputDelayRingBufferWritePos = 0;
260 mOutputDelayRingBufferReadPos = 0;
261 mOutputDelayRingBufferFilled = 0;
262 mBuffersInfo.clear();
263
264 // To make the codec behave the same before and after a reset, we need to invalidate the
265 // streaminfo struct. This does that:
266 mStreamInfo->sampleRate = 0; // TODO: mStreamInfo is read only
267
268 mSignalledError = false;
269
270 return C2_OK;
271}
272
273void C2SoftAacDec::onReset() {
274 (void)onStop();
275}
276
277void C2SoftAacDec::onRelease() {
278 if (mAACDecoder) {
279 aacDecoder_Close(mAACDecoder);
280 mAACDecoder = nullptr;
281 }
282 if (mOutputDelayRingBuffer) {
283 delete[] mOutputDelayRingBuffer;
284 mOutputDelayRingBuffer = nullptr;
285 }
286}
287
288status_t C2SoftAacDec::initDecoder() {
289 ALOGV("initDecoder()");
290 status_t status = UNKNOWN_ERROR;
291 mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, /* num layers */ 1);
292 if (mAACDecoder != nullptr) {
293 mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder);
294 if (mStreamInfo != nullptr) {
295 status = OK;
296 }
297 }
298
299 mOutputDelayCompensated = 0;
300 mOutputDelayRingBufferSize = 2048 * MAX_CHANNEL_COUNT * kNumDelayBlocksMax;
301 mOutputDelayRingBuffer = new short[mOutputDelayRingBufferSize];
302 mOutputDelayRingBufferWritePos = 0;
303 mOutputDelayRingBufferReadPos = 0;
304 mOutputDelayRingBufferFilled = 0;
305
306 if (mAACDecoder == nullptr) {
307 ALOGE("AAC decoder is null. TODO: Can not call aacDecoder_SetParam in the following code");
308 }
309
310 //aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, 0);
311
312 //init DRC wrapper
313 mDrcWrap.setDecoderHandle(mAACDecoder);
314 mDrcWrap.submitStreamData(mStreamInfo);
315
316 // for streams that contain metadata, use the mobile profile DRC settings unless overridden by platform properties
317 // TODO: change the DRC settings depending on audio output device type (HDMI, loadspeaker, headphone)
318
319 // DRC_PRES_MODE_WRAP_DESIRED_TARGET
320 int32_t targetRefLevel = mIntf->getDrcTargetRefLevel();
321 ALOGV("AAC decoder using desired DRC target reference level of %d", targetRefLevel);
322 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, (unsigned)targetRefLevel);
323
324 // DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR
325
326 int32_t attenuationFactor = mIntf->getDrcAttenuationFactor();
327 ALOGV("AAC decoder using desired DRC attenuation factor of %d", attenuationFactor);
328 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, (unsigned)attenuationFactor);
329
330 // DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR
331 int32_t boostFactor = mIntf->getDrcBoostFactor();
332 ALOGV("AAC decoder using desired DRC boost factor of %d", boostFactor);
333 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, (unsigned)boostFactor);
334
335 // DRC_PRES_MODE_WRAP_DESIRED_HEAVY
336 int32_t compressMode = mIntf->getDrcCompressMode();
Jean-Michel Triviedf942b2020-01-29 09:59:44 -0800337 ALOGV("AAC decoder using desired DRC heavy compression switch of %d", compressMode);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800338 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, (unsigned)compressMode);
339
340 // DRC_PRES_MODE_WRAP_ENCODER_TARGET
341 int32_t encTargetLevel = mIntf->getDrcEncTargetLevel();
342 ALOGV("AAC decoder using encoder-side DRC reference level of %d", encTargetLevel);
343 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, (unsigned)encTargetLevel);
344
345 // AAC_UNIDRC_SET_EFFECT
346 int32_t effectType = mIntf->getDrcEffectType();
347 ALOGV("AAC decoder using MPEG-D DRC effect type %d", effectType);
348 aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, effectType);
349
350 // By default, the decoder creates a 5.1 channel downmix signal.
351 // For seven and eight channel input streams, enable 6.1 and 7.1 channel output
352 aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1);
353
354 return status;
355}
356
357bool C2SoftAacDec::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamples) {
358 if (numSamples == 0) {
359 return true;
360 }
361 if (outputDelayRingBufferSpaceLeft() < numSamples) {
362 ALOGE("RING BUFFER WOULD OVERFLOW");
363 return false;
364 }
365 if (mOutputDelayRingBufferWritePos + numSamples <= mOutputDelayRingBufferSize
366 && (mOutputDelayRingBufferReadPos <= mOutputDelayRingBufferWritePos
367 || mOutputDelayRingBufferReadPos > mOutputDelayRingBufferWritePos + numSamples)) {
368 // faster memcopy loop without checks, if the preconditions allow this
369 for (int32_t i = 0; i < numSamples; i++) {
370 mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos++] = samples[i];
371 }
372
373 if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) {
374 mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize;
375 }
376 } else {
377 ALOGV("slow C2SoftAacDec::outputDelayRingBufferPutSamples()");
378
379 for (int32_t i = 0; i < numSamples; i++) {
380 mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos] = samples[i];
381 mOutputDelayRingBufferWritePos++;
382 if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) {
383 mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize;
384 }
385 }
386 }
387 mOutputDelayRingBufferFilled += numSamples;
388 return true;
389}
390
391int32_t C2SoftAacDec::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numSamples) {
392
393 if (numSamples > mOutputDelayRingBufferFilled) {
394 ALOGE("RING BUFFER WOULD UNDERRUN");
395 return -1;
396 }
397
398 if (mOutputDelayRingBufferReadPos + numSamples <= mOutputDelayRingBufferSize
399 && (mOutputDelayRingBufferWritePos < mOutputDelayRingBufferReadPos
400 || mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferReadPos + numSamples)) {
401 // faster memcopy loop without checks, if the preconditions allow this
402 if (samples != nullptr) {
403 for (int32_t i = 0; i < numSamples; i++) {
404 samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos++];
405 }
406 } else {
407 mOutputDelayRingBufferReadPos += numSamples;
408 }
409 if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) {
410 mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize;
411 }
412 } else {
413 ALOGV("slow C2SoftAacDec::outputDelayRingBufferGetSamples()");
414
415 for (int32_t i = 0; i < numSamples; i++) {
416 if (samples != nullptr) {
417 samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos];
418 }
419 mOutputDelayRingBufferReadPos++;
420 if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) {
421 mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize;
422 }
423 }
424 }
425 mOutputDelayRingBufferFilled -= numSamples;
426 return numSamples;
427}
428
429int32_t C2SoftAacDec::outputDelayRingBufferSamplesAvailable() {
430 return mOutputDelayRingBufferFilled;
431}
432
433int32_t C2SoftAacDec::outputDelayRingBufferSpaceLeft() {
434 return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable();
435}
436
437void C2SoftAacDec::drainRingBuffer(
438 const std::unique_ptr<C2Work> &work,
439 const std::shared_ptr<C2BlockPool> &pool,
440 bool eos) {
441 while (!mBuffersInfo.empty() && outputDelayRingBufferSamplesAvailable()
442 >= mStreamInfo->frameSize * mStreamInfo->numChannels) {
443 Info &outInfo = mBuffersInfo.front();
444 ALOGV("outInfo.frameIndex = %" PRIu64, outInfo.frameIndex);
445 int samplesize __unused = mStreamInfo->numChannels * sizeof(int16_t);
446
447 int available = outputDelayRingBufferSamplesAvailable();
448 int numFrames = outInfo.decodedSizes.size();
449 int numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels);
450 if (available < numSamples) {
451 if (eos) {
452 numSamples = available;
453 } else {
454 break;
455 }
456 }
457 ALOGV("%d samples available (%d), or %d frames",
458 numSamples, available, numFrames);
459 ALOGV("getting %d from ringbuffer", numSamples);
460
461 std::shared_ptr<C2LinearBlock> block;
462 std::function<void(const std::unique_ptr<C2Work>&)> fillWork =
463 [&block, numSamples, pool, this]()
464 -> std::function<void(const std::unique_ptr<C2Work>&)> {
465 auto fillEmptyWork = [](
466 const std::unique_ptr<C2Work> &work, c2_status_t err) {
467 work->result = err;
468 C2FrameData &output = work->worklets.front()->output;
469 output.flags = work->input.flags;
470 output.buffers.clear();
471 output.ordinal = work->input.ordinal;
472
473 work->workletsProcessed = 1u;
474 };
475
476 using namespace std::placeholders;
477 if (numSamples == 0) {
478 return std::bind(fillEmptyWork, _1, C2_OK);
479 }
480
481 // TODO: error handling, proper usage, etc.
482 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
483 c2_status_t err = pool->fetchLinearBlock(
484 numSamples * sizeof(int16_t), usage, &block);
485 if (err != C2_OK) {
486 ALOGD("failed to fetch a linear block (%d)", err);
487 return std::bind(fillEmptyWork, _1, C2_NO_MEMORY);
488 }
489 C2WriteView wView = block->map().get();
490 // TODO
491 INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(wView.data());
492 int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples);
493 if (ns != numSamples) {
494 ALOGE("not a complete frame of samples available");
495 mSignalledError = true;
496 return std::bind(fillEmptyWork, _1, C2_CORRUPTED);
497 }
498 return [buffer = createLinearBuffer(block)](
499 const std::unique_ptr<C2Work> &work) {
500 work->result = C2_OK;
501 C2FrameData &output = work->worklets.front()->output;
502 output.flags = work->input.flags;
503 output.buffers.clear();
504 output.buffers.push_back(buffer);
505 output.ordinal = work->input.ordinal;
506 work->workletsProcessed = 1u;
507 };
508 }();
509
510 if (work && work->input.ordinal.frameIndex == c2_cntr64_t(outInfo.frameIndex)) {
511 fillWork(work);
512 } else {
513 finish(outInfo.frameIndex, fillWork);
514 }
515
516 ALOGV("out timestamp %" PRIu64 " / %u", outInfo.timestamp, block ? block->capacity() : 0);
517 mBuffersInfo.pop_front();
518 }
519}
520
521void C2SoftAacDec::process(
522 const std::unique_ptr<C2Work> &work,
523 const std::shared_ptr<C2BlockPool> &pool) {
524 // Initialize output work
525 work->result = C2_OK;
526 work->workletsProcessed = 1u;
527 work->worklets.front()->output.configUpdate.clear();
528 work->worklets.front()->output.flags = work->input.flags;
529
530 if (mSignalledError) {
531 return;
532 }
533
534 UCHAR* inBuffer[FILEREAD_MAX_LAYERS];
535 UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0};
536 UINT bytesValid[FILEREAD_MAX_LAYERS] = {0};
537
538 INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
539 C2ReadView view = mDummyReadView;
540 size_t offset = 0u;
541 size_t size = 0u;
542 if (!work->input.buffers.empty()) {
543 view = work->input.buffers[0]->data().linearBlocks().front().map().get();
544 size = view.capacity();
545 }
546
547 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
548 bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
549
550 //TODO
551#if 0
552 if (mInputBufferCount == 0 && !codecConfig) {
553 ALOGW("first buffer should have FLAG_CODEC_CONFIG set");
554 codecConfig = true;
555 }
556#endif
557 if (codecConfig && size > 0u) {
558 // const_cast because of libAACdec method signature.
559 inBuffer[0] = const_cast<UCHAR *>(view.data() + offset);
560 inBufferLength[0] = size;
561
562 AAC_DECODER_ERROR decoderErr =
563 aacDecoder_ConfigRaw(mAACDecoder,
564 inBuffer,
565 inBufferLength);
566
567 if (decoderErr != AAC_DEC_OK) {
568 ALOGE("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
569 mSignalledError = true;
570 work->result = C2_CORRUPTED;
571 return;
572 }
573 work->worklets.front()->output.flags = work->input.flags;
574 work->worklets.front()->output.ordinal = work->input.ordinal;
575 work->worklets.front()->output.buffers.clear();
576 return;
577 }
578
579 Info inInfo;
580 inInfo.frameIndex = work->input.ordinal.frameIndex.peeku();
581 inInfo.timestamp = work->input.ordinal.timestamp.peeku();
582 inInfo.bufferSize = size;
583 inInfo.decodedSizes.clear();
584 while (size > 0u) {
585 ALOGV("size = %zu", size);
586 if (mIntf->isAdts()) {
587 size_t adtsHeaderSize = 0;
588 // skip 30 bits, aac_frame_length follows.
589 // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
590
591 const uint8_t *adtsHeader = view.data() + offset;
592
593 bool signalError = false;
594 if (size < 7) {
595 ALOGE("Audio data too short to contain even the ADTS header. "
596 "Got %zu bytes.", size);
597 hexdump(adtsHeader, size);
598 signalError = true;
599 } else {
600 bool protectionAbsent = (adtsHeader[1] & 1);
601
602 unsigned aac_frame_length =
603 ((adtsHeader[3] & 3) << 11)
604 | (adtsHeader[4] << 3)
605 | (adtsHeader[5] >> 5);
606
607 if (size < aac_frame_length) {
608 ALOGE("Not enough audio data for the complete frame. "
609 "Got %zu bytes, frame size according to the ADTS "
610 "header is %u bytes.",
611 size, aac_frame_length);
612 hexdump(adtsHeader, size);
613 signalError = true;
614 } else {
615 adtsHeaderSize = (protectionAbsent ? 7 : 9);
616 if (aac_frame_length < adtsHeaderSize) {
617 signalError = true;
618 } else {
619 // const_cast because of libAACdec method signature.
620 inBuffer[0] = const_cast<UCHAR *>(adtsHeader + adtsHeaderSize);
621 inBufferLength[0] = aac_frame_length - adtsHeaderSize;
622
623 offset += adtsHeaderSize;
624 size -= adtsHeaderSize;
625 }
626 }
627 }
628
629 if (signalError) {
630 mSignalledError = true;
631 work->result = C2_CORRUPTED;
632 return;
633 }
634 } else {
635 // const_cast because of libAACdec method signature.
636 inBuffer[0] = const_cast<UCHAR *>(view.data() + offset);
637 inBufferLength[0] = size;
638 }
639
640 // Fill and decode
641 bytesValid[0] = inBufferLength[0];
642
643 INT prevSampleRate = mStreamInfo->sampleRate;
644 INT prevNumChannels = mStreamInfo->numChannels;
Jean-Michel Trivi4b936cc2020-02-17 16:29:47 -0800645 INT prevOutLoudness = mStreamInfo->outputLoudness;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800646
647 aacDecoder_Fill(mAACDecoder,
648 inBuffer,
649 inBufferLength,
650 bytesValid);
651
652 // run DRC check
653 mDrcWrap.submitStreamData(mStreamInfo);
Jean-Michel Triviedf942b2020-01-29 09:59:44 -0800654
655 // apply runtime updates
656 // DRC_PRES_MODE_WRAP_DESIRED_TARGET
657 int32_t targetRefLevel = mIntf->getDrcTargetRefLevel();
658 ALOGV("AAC decoder using desired DRC target reference level of %d", targetRefLevel);
659 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, (unsigned)targetRefLevel);
660
661 // DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR
662 int32_t attenuationFactor = mIntf->getDrcAttenuationFactor();
663 ALOGV("AAC decoder using desired DRC attenuation factor of %d", attenuationFactor);
664 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, (unsigned)attenuationFactor);
665
666 // DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR
667 int32_t boostFactor = mIntf->getDrcBoostFactor();
668 ALOGV("AAC decoder using desired DRC boost factor of %d", boostFactor);
669 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, (unsigned)boostFactor);
670
671 // DRC_PRES_MODE_WRAP_DESIRED_HEAVY
672 int32_t compressMode = mIntf->getDrcCompressMode();
673 ALOGV("AAC decoder using desried DRC heavy compression switch of %d", compressMode);
674 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, (unsigned)compressMode);
675
676 // DRC_PRES_MODE_WRAP_ENCODER_TARGET
677 int32_t encTargetLevel = mIntf->getDrcEncTargetLevel();
678 ALOGV("AAC decoder using encoder-side DRC reference level of %d", encTargetLevel);
679 mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, (unsigned)encTargetLevel);
680
681 // AAC_UNIDRC_SET_EFFECT
682 int32_t effectType = mIntf->getDrcEffectType();
683 ALOGV("AAC decoder using MPEG-D DRC effect type %d", effectType);
684 aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, effectType);
685
Pawin Vongmasa36653902018-11-15 00:10:25 -0800686 mDrcWrap.update();
687
688 UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
689 size -= inBufferUsedLength;
690 offset += inBufferUsedLength;
691
692 AAC_DECODER_ERROR decoderErr;
693 do {
694 if (outputDelayRingBufferSpaceLeft() <
695 (mStreamInfo->frameSize * mStreamInfo->numChannels)) {
696 ALOGV("skipping decode: not enough space left in ringbuffer");
697 // discard buffer
698 size = 0;
699 break;
700 }
701
702 int numConsumed = mStreamInfo->numTotalBytes;
703 decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
704 tmpOutBuffer,
705 2048 * MAX_CHANNEL_COUNT,
706 0 /* flags */);
707
708 numConsumed = mStreamInfo->numTotalBytes - numConsumed;
709
710 if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
711 break;
712 }
713 inInfo.decodedSizes.push_back(numConsumed);
714
715 if (decoderErr != AAC_DEC_OK) {
716 ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
717 }
718
719 if (bytesValid[0] != 0) {
720 ALOGE("bytesValid[0] != 0 should never happen");
721 mSignalledError = true;
722 work->result = C2_CORRUPTED;
723 return;
724 }
725
726 size_t numOutBytes =
727 mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
728
729 if (decoderErr == AAC_DEC_OK) {
730 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
731 mStreamInfo->frameSize * mStreamInfo->numChannels)) {
732 mSignalledError = true;
733 work->result = C2_CORRUPTED;
734 return;
735 }
736 } else {
737 ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
738
739 memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
740
741 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
742 mStreamInfo->frameSize * mStreamInfo->numChannels)) {
743 mSignalledError = true;
744 work->result = C2_CORRUPTED;
745 return;
746 }
747
748 // Discard input buffer.
749 size = 0;
750
751 aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
752
753 // After an error, replace bufferSize with the sum of the
754 // decodedSizes to resynchronize the in/out lists.
755 inInfo.decodedSizes.pop_back();
756 inInfo.bufferSize = std::accumulate(
757 inInfo.decodedSizes.begin(), inInfo.decodedSizes.end(), 0);
758
759 // fall through
760 }
761
762 /*
763 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
764 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
765 * rate system and the sampling rate in the final output is actually
766 * doubled compared with the core AAC decoder sampling rate.
767 *
768 * Explicit signalling is done by explicitly defining SBR audio object
769 * type in the bitstream. Implicit signalling is done by embedding
770 * SBR content in AAC extension payload specific to SBR, and hence
771 * requires an AAC decoder to perform pre-checks on actual audio frames.
772 *
773 * Thus, we could not say for sure whether a stream is
774 * AAC+/eAAC+ until the first data frame is decoded.
775 */
776 if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
777 // if ((mInputBufferCount > 2) && (mOutputBufferCount <= 1)) {
778 ALOGD("Invalid AAC stream");
779 // TODO: notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
780 // mSignalledError = true;
781 // }
782 } else if ((mStreamInfo->sampleRate != prevSampleRate) ||
783 (mStreamInfo->numChannels != prevNumChannels)) {
784 ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
785 prevSampleRate, mStreamInfo->sampleRate,
786 prevNumChannels, mStreamInfo->numChannels);
787
788 C2StreamSampleRateInfo::output sampleRateInfo(0u, mStreamInfo->sampleRate);
789 C2StreamChannelCountInfo::output channelCountInfo(0u, mStreamInfo->numChannels);
790 std::vector<std::unique_ptr<C2SettingResult>> failures;
791 c2_status_t err = mIntf->config(
792 { &sampleRateInfo, &channelCountInfo },
793 C2_MAY_BLOCK,
794 &failures);
795 if (err == OK) {
796 // TODO: this does not handle the case where the values are
797 // altered during config.
798 C2FrameData &output = work->worklets.front()->output;
799 output.configUpdate.push_back(C2Param::Copy(sampleRateInfo));
800 output.configUpdate.push_back(C2Param::Copy(channelCountInfo));
801 } else {
802 ALOGE("Config Update failed");
803 mSignalledError = true;
804 work->result = C2_CORRUPTED;
805 return;
806 }
807 }
808 ALOGV("size = %zu", size);
Jean-Michel Trivi4b936cc2020-02-17 16:29:47 -0800809
810 if (mStreamInfo->outputLoudness != prevOutLoudness) {
811 C2StreamDrcOutputLoudnessTuning::output
812 drcOutLoudness(0u, (float) (mStreamInfo->outputLoudness*-0.25));
813
814 std::vector<std::unique_ptr<C2SettingResult>> failures;
815 c2_status_t err = mIntf->config(
816 { &drcOutLoudness },
817 C2_MAY_BLOCK,
818 &failures);
819 if (err == OK) {
820 work->worklets.front()->output.configUpdate.push_back(
821 C2Param::Copy(drcOutLoudness));
822 } else {
823 ALOGE("Getting output loudness failed");
824 }
825 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800826 } while (decoderErr == AAC_DEC_OK);
827 }
828
829 int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
830
831 mBuffersInfo.push_back(std::move(inInfo));
832 work->workletsProcessed = 0u;
833 if (!eos && mOutputDelayCompensated < outputDelay) {
834 // discard outputDelay at the beginning
835 int32_t toCompensate = outputDelay - mOutputDelayCompensated;
836 int32_t discard = outputDelayRingBufferSamplesAvailable();
837 if (discard > toCompensate) {
838 discard = toCompensate;
839 }
840 int32_t discarded = outputDelayRingBufferGetSamples(nullptr, discard);
841 mOutputDelayCompensated += discarded;
842 return;
843 }
844
845 if (eos) {
846 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
847 } else {
848 drainRingBuffer(work, pool, false /* not EOS */);
849 }
850}
851
852c2_status_t C2SoftAacDec::drainInternal(
853 uint32_t drainMode,
854 const std::shared_ptr<C2BlockPool> &pool,
855 const std::unique_ptr<C2Work> &work) {
856 if (drainMode == NO_DRAIN) {
857 ALOGW("drain with NO_DRAIN: no-op");
858 return C2_OK;
859 }
860 if (drainMode == DRAIN_CHAIN) {
861 ALOGW("DRAIN_CHAIN not supported");
862 return C2_OMITTED;
863 }
864
865 bool eos = (drainMode == DRAIN_COMPONENT_WITH_EOS);
866
867 drainDecoder();
868 drainRingBuffer(work, pool, eos);
869
870 if (eos) {
871 auto fillEmptyWork = [](const std::unique_ptr<C2Work> &work) {
872 work->worklets.front()->output.flags = work->input.flags;
873 work->worklets.front()->output.buffers.clear();
874 work->worklets.front()->output.ordinal = work->input.ordinal;
875 work->workletsProcessed = 1u;
876 };
877 while (mBuffersInfo.size() > 1u) {
878 finish(mBuffersInfo.front().frameIndex, fillEmptyWork);
879 mBuffersInfo.pop_front();
880 }
881 if (work && work->workletsProcessed == 0u) {
882 fillEmptyWork(work);
883 }
884 mBuffersInfo.clear();
885 }
886
887 return C2_OK;
888}
889
890c2_status_t C2SoftAacDec::drain(
891 uint32_t drainMode,
892 const std::shared_ptr<C2BlockPool> &pool) {
893 return drainInternal(drainMode, pool, nullptr);
894}
895
896c2_status_t C2SoftAacDec::onFlush_sm() {
897 drainDecoder();
898 mBuffersInfo.clear();
899
900 int avail;
901 while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) {
902 if (avail > mStreamInfo->frameSize * mStreamInfo->numChannels) {
903 avail = mStreamInfo->frameSize * mStreamInfo->numChannels;
904 }
905 int32_t ns = outputDelayRingBufferGetSamples(nullptr, avail);
906 if (ns != avail) {
907 ALOGW("not a complete frame of samples available");
908 break;
909 }
910 }
911 mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos;
912
913 return C2_OK;
914}
915
916void C2SoftAacDec::drainDecoder() {
917 // flush decoder until outputDelay is compensated
918 while (mOutputDelayCompensated > 0) {
919 // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC
920 INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
921
922 // run DRC check
923 mDrcWrap.submitStreamData(mStreamInfo);
924 mDrcWrap.update();
925
926 AAC_DECODER_ERROR decoderErr =
927 aacDecoder_DecodeFrame(mAACDecoder,
928 tmpOutBuffer,
929 2048 * MAX_CHANNEL_COUNT,
930 AACDEC_FLUSH);
931 if (decoderErr != AAC_DEC_OK) {
932 ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
933 }
934
935 int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels;
936 if (tmpOutBufferSamples > mOutputDelayCompensated) {
937 tmpOutBufferSamples = mOutputDelayCompensated;
938 }
939 outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples);
940
941 mOutputDelayCompensated -= tmpOutBufferSamples;
942 }
943}
944
945class C2SoftAacDecFactory : public C2ComponentFactory {
946public:
947 C2SoftAacDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
948 GetCodec2PlatformComponentStore()->getParamReflector())) {
949 }
950
951 virtual c2_status_t createComponent(
952 c2_node_id_t id,
953 std::shared_ptr<C2Component>* const component,
954 std::function<void(C2Component*)> deleter) override {
955 *component = std::shared_ptr<C2Component>(
956 new C2SoftAacDec(COMPONENT_NAME,
957 id,
958 std::make_shared<C2SoftAacDec::IntfImpl>(mHelper)),
959 deleter);
960 return C2_OK;
961 }
962
963 virtual c2_status_t createInterface(
964 c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
965 std::function<void(C2ComponentInterface*)> deleter) override {
966 *interface = std::shared_ptr<C2ComponentInterface>(
967 new SimpleInterface<C2SoftAacDec::IntfImpl>(
968 COMPONENT_NAME, id, std::make_shared<C2SoftAacDec::IntfImpl>(mHelper)),
969 deleter);
970 return C2_OK;
971 }
972
973 virtual ~C2SoftAacDecFactory() override = default;
974
975private:
976 std::shared_ptr<C2ReflectorHelper> mHelper;
977};
978
979} // namespace android
980
981extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
982 ALOGV("in %s", __func__);
983 return new ::android::C2SoftAacDecFactory();
984}
985
986extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
987 ALOGV("in %s", __func__);
988 delete factory;
989}