• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 "C2SoftAmrWbEnc"
19 #include <log/log.h>
20 
21 #include <media/stagefright/foundation/MediaDefs.h>
22 
23 #include <C2Debug.h>
24 #include <C2PlatformSupport.h>
25 #include <SimpleC2Interface.h>
26 
27 #include "C2SoftAmrWbEnc.h"
28 #include "cmnMemory.h"
29 
30 namespace android {
31 
32 constexpr char COMPONENT_NAME[] = "c2.android.amrwb.encoder";
33 
34 class C2SoftAmrWbEnc::IntfImpl : public C2InterfaceHelper {
35    public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)36     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
37         : C2InterfaceHelper(helper) {
38         setDerivedInstance(this);
39 
40         addParameter(
41             DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
42                 .withConstValue(
43                     new C2StreamFormatConfig::input(0u, C2FormatAudio))
44                 .build());
45 
46         addParameter(
47             DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
48                 .withConstValue(
49                     new C2StreamFormatConfig::output(0u, C2FormatCompressed))
50                 .build());
51 
52         addParameter(
53             DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
54                 .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
55                     MEDIA_MIMETYPE_AUDIO_RAW))
56                 .build());
57 
58         addParameter(
59             DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
60                 .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
61                     MEDIA_MIMETYPE_AUDIO_AMR_WB))
62                 .build());
63 
64         addParameter(
65                 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
66                 .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
67                 .withFields({C2F(mChannelCount, value).equalTo(1)})
68                 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
69                 .build());
70 
71         addParameter(
72             DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
73                 .withDefault(new C2StreamSampleRateInfo::input(0u, 16000))
74                 .withFields({C2F(mSampleRate, value).equalTo(16000)})
75                 .withSetter(
76                     (Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
77                 .build());
78 
79         addParameter(
80                 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
81                 .withDefault(new C2BitrateTuning::output(0u, 6600))
82                 .withFields({C2F(mBitrate, value).inRange(6600, 23850)})
83                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
84                 .build());
85 
86         addParameter(
87                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
88                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192))
89                 .build());
90     }
91 
getSampleRate() const92     uint32_t getSampleRate() const { return mSampleRate->value; }
getChannelCount() const93     uint32_t getChannelCount() const { return mChannelCount->value; }
getBitrate() const94     uint32_t getBitrate() const { return mBitrate->value; }
95 
96    private:
97     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
98     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
99     std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
100     std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
101     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
102     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
103     std::shared_ptr<C2BitrateTuning::output> mBitrate;
104     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
105 };
106 
C2SoftAmrWbEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)107 C2SoftAmrWbEnc::C2SoftAmrWbEnc(const char* name, c2_node_id_t id,
108                                const std::shared_ptr<IntfImpl>& intfImpl)
109     : SimpleC2Component(
110           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
111       mIntf(intfImpl),
112       mEncoderHandle(nullptr),
113       mApiHandle(nullptr),
114       mMemOperator(nullptr) {
115 }
116 
~C2SoftAmrWbEnc()117 C2SoftAmrWbEnc::~C2SoftAmrWbEnc() {
118     onRelease();
119 }
120 
onInit()121 c2_status_t C2SoftAmrWbEnc::onInit() {
122     // TODO: get mode directly from config
123     switch(mIntf->getBitrate()) {
124         case 6600: mMode = VOAMRWB_MD66;
125             break;
126         case 8850: mMode = VOAMRWB_MD885;
127             break;
128         case 12650: mMode = VOAMRWB_MD1265;
129             break;
130         case 14250: mMode = VOAMRWB_MD1425;
131             break;
132         case 15850: mMode = VOAMRWB_MD1585;
133             break;
134         case 18250: mMode = VOAMRWB_MD1825;
135             break;
136         case 19850: mMode = VOAMRWB_MD1985;
137             break;
138         case 23050: mMode = VOAMRWB_MD2305;
139             break;
140         case 23850: mMode = VOAMRWB_MD2385;
141             break;
142         default: mMode = VOAMRWB_MD2305;
143     }
144     status_t err = initEncoder();
145     mIsFirst = true;
146     mSignalledError = false;
147     mSignalledOutputEos = false;
148     mAnchorTimeStamp = 0;
149     mProcessedSamples = 0;
150     mFilledLen = 0;
151 
152     return err == OK ? C2_OK : C2_NO_MEMORY;
153 }
154 
onRelease()155 void C2SoftAmrWbEnc::onRelease() {
156     if (mEncoderHandle) {
157         CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
158         mEncoderHandle = nullptr;
159     }
160     if (mApiHandle) {
161         delete mApiHandle;
162         mApiHandle = nullptr;
163     }
164     if (mMemOperator) {
165         delete mMemOperator;
166         mMemOperator = nullptr;
167     }
168 }
169 
onStop()170 c2_status_t C2SoftAmrWbEnc::onStop() {
171     for (int i = 0; i < kNumSamplesPerFrame; i++) {
172         mInputFrame[i] = 0x0008; /* EHF_MASK */
173     }
174     uint8_t outBuffer[kNumBytesPerInputFrame];
175     (void) encodeInput(outBuffer, kNumBytesPerInputFrame);
176     mIsFirst = true;
177     mSignalledError = false;
178     mSignalledOutputEos = false;
179     mAnchorTimeStamp = 0;
180     mProcessedSamples = 0;
181     mFilledLen = 0;
182 
183     return C2_OK;
184 }
185 
onReset()186 void C2SoftAmrWbEnc::onReset() {
187     (void) onStop();
188 }
189 
onFlush_sm()190 c2_status_t C2SoftAmrWbEnc::onFlush_sm() {
191     return onStop();
192 }
193 
initEncoder()194 status_t C2SoftAmrWbEnc::initEncoder() {
195     mApiHandle = new VO_AUDIO_CODECAPI;
196     if (!mApiHandle) return NO_MEMORY;
197 
198     if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
199         ALOGE("Failed to get api handle");
200         return UNKNOWN_ERROR;
201     }
202 
203     mMemOperator = new VO_MEM_OPERATOR;
204     if (!mMemOperator) return NO_MEMORY;
205 
206     mMemOperator->Alloc = cmnMemAlloc;
207     mMemOperator->Copy = cmnMemCopy;
208     mMemOperator->Free = cmnMemFree;
209     mMemOperator->Set = cmnMemSet;
210     mMemOperator->Check = cmnMemCheck;
211 
212     VO_CODEC_INIT_USERDATA userData;
213     memset(&userData, 0, sizeof(userData));
214     userData.memflag = VO_IMF_USERMEMOPERATOR;
215     userData.memData = (VO_PTR) mMemOperator;
216 
217     if (VO_ERR_NONE != mApiHandle->Init(
218                 &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
219         ALOGE("Failed to init AMRWB encoder");
220         return UNKNOWN_ERROR;
221     }
222 
223     VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
224     if (VO_ERR_NONE != mApiHandle->SetParam(
225                 mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
226         ALOGE("Failed to set AMRWB encoder frame type to %d", type);
227         return UNKNOWN_ERROR;
228     }
229 
230     if (VO_ERR_NONE !=
231             mApiHandle->SetParam(
232                     mEncoderHandle, VO_PID_AMRWB_MODE,  &mMode)) {
233         ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
234         return UNKNOWN_ERROR;
235     }
236 
237     return OK;
238 }
239 
encodeInput(uint8_t * buffer,uint32_t length)240 int C2SoftAmrWbEnc::encodeInput(uint8_t *buffer, uint32_t length) {
241     VO_CODECBUFFER inputData;
242     memset(&inputData, 0, sizeof(inputData));
243     inputData.Buffer = (unsigned char *) mInputFrame;
244     inputData.Length = kNumBytesPerInputFrame;
245 
246     CHECK_EQ((VO_U32)VO_ERR_NONE,
247              mApiHandle->SetInputData(mEncoderHandle, &inputData));
248 
249     VO_AUDIO_OUTPUTINFO outputInfo;
250     memset(&outputInfo, 0, sizeof(outputInfo));
251     VO_CODECBUFFER outputData;
252     memset(&outputData, 0, sizeof(outputData));
253     outputData.Buffer = buffer;
254     outputData.Length = length;
255     VO_U32 ret = mApiHandle->GetOutputData(
256             mEncoderHandle, &outputData, &outputInfo);
257     if (ret != VO_ERR_NONE && ret != VO_ERR_INPUT_BUFFER_SMALL) {
258         ALOGD("encountered error during encode call");
259         return -1;
260     }
261     return outputData.Length;
262 }
263 
fillEmptyWork(const std::unique_ptr<C2Work> & work)264 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
265     work->worklets.front()->output.flags = work->input.flags;
266     work->worklets.front()->output.buffers.clear();
267     work->worklets.front()->output.ordinal = work->input.ordinal;
268     work->workletsProcessed = 1u;
269 }
270 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)271 void C2SoftAmrWbEnc::process(
272         const std::unique_ptr<C2Work> &work,
273         const std::shared_ptr<C2BlockPool> &pool) {
274     // Initialize output work
275     work->result = C2_OK;
276     work->workletsProcessed = 1u;
277     work->worklets.front()->output.flags = work->input.flags;
278 
279     if (mSignalledError || mSignalledOutputEos) {
280         work->result = C2_BAD_VALUE;
281         return;
282     }
283 
284     size_t inOffset = 0u;
285     size_t inSize = 0u;
286     C2ReadView rView = mDummyReadView;
287     if (!work->input.buffers.empty()) {
288         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
289         inSize = rView.capacity();
290         if (inSize && rView.error()) {
291             ALOGE("read view map failed %d", rView.error());
292             work->result = rView.error();
293             return;
294         }
295     }
296     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
297 
298     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
299           inSize, (int)work->input.ordinal.timestamp.peeku(),
300           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
301 
302     size_t outCapacity = kNumBytesPerInputFrame;
303     outCapacity += mFilledLen + inSize;
304     std::shared_ptr<C2LinearBlock> outputBlock;
305     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
306     c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &outputBlock);
307     if (err != C2_OK) {
308         ALOGE("fetchLinearBlock for Output failed with status %d", err);
309         work->result = C2_NO_MEMORY;
310         return;
311     }
312     C2WriteView wView = outputBlock->map().get();
313     if (wView.error()) {
314         ALOGE("write view map failed %d", wView.error());
315         work->result = wView.error();
316         return;
317     }
318     uint64_t outTimeStamp =
319         mProcessedSamples * 1000000ll / mIntf->getSampleRate();
320     size_t inPos = 0;
321     size_t outPos = 0;
322     while (inPos < inSize) {
323         const uint8_t *inPtr = rView.data() + inOffset;
324         int validSamples = mFilledLen / sizeof(int16_t);
325         if ((inPos + (kNumBytesPerInputFrame - mFilledLen)) <= inSize) {
326             memcpy(mInputFrame + validSamples, inPtr + inPos,
327                    (kNumBytesPerInputFrame - mFilledLen));
328             inPos += (kNumBytesPerInputFrame - mFilledLen);
329         } else {
330             memcpy(mInputFrame + validSamples, inPtr + inPos, (inSize - inPos));
331             mFilledLen += (inSize - inPos);
332             inPos += (inSize - inPos);
333             if (eos) {
334                 validSamples = mFilledLen / sizeof(int16_t);
335                 memset(mInputFrame + validSamples, 0, (kNumBytesPerInputFrame - mFilledLen));
336             } else break;
337         }
338         int numEncBytes = encodeInput((wView.data() + outPos), outCapacity - outPos);
339         if (numEncBytes < 0) {
340             ALOGE("encodeFrame call failed, state [%d %zu %zu]", numEncBytes, outPos, outCapacity);
341             mSignalledError = true;
342             work->result = C2_CORRUPTED;
343             return;
344         }
345         outPos += numEncBytes;
346         mProcessedSamples += kNumSamplesPerFrame;
347         mFilledLen = 0;
348     }
349     ALOGV("causal sample size %d", mFilledLen);
350     if (mIsFirst) {
351         mIsFirst = false;
352         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
353     }
354     fillEmptyWork(work);
355     if (outPos != 0) {
356         work->worklets.front()->output.buffers.push_back(
357                 createLinearBuffer(std::move(outputBlock), 0, outPos));
358         work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
359     }
360     if (eos) {
361         mSignalledOutputEos = true;
362         ALOGV("signalled EOS");
363         if (mFilledLen) ALOGV("Discarding trailing %d bytes", mFilledLen);
364     }
365 }
366 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)367 c2_status_t C2SoftAmrWbEnc::drain(
368         uint32_t drainMode,
369         const std::shared_ptr<C2BlockPool> &pool) {
370     (void) pool;
371     if (drainMode == NO_DRAIN) {
372         ALOGW("drain with NO_DRAIN: no-op");
373         return C2_OK;
374     }
375     if (drainMode == DRAIN_CHAIN) {
376         ALOGW("DRAIN_CHAIN not supported");
377         return C2_OMITTED;
378     }
379 
380     onFlush_sm();
381     return C2_OK;
382 }
383 
384 class C2SoftAmrWbEncFactory : public C2ComponentFactory {
385 public:
C2SoftAmrWbEncFactory()386     C2SoftAmrWbEncFactory()
387         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
388               GetCodec2PlatformComponentStore()->getParamReflector())) {}
389 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)390     virtual c2_status_t createComponent(
391             c2_node_id_t id,
392             std::shared_ptr<C2Component>* const component,
393             std::function<void(C2Component*)> deleter) override {
394         *component = std::shared_ptr<C2Component>(
395             new C2SoftAmrWbEnc(
396                 COMPONENT_NAME, id,
397                 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
398             deleter);
399         return C2_OK;
400     }
401 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)402     virtual c2_status_t createInterface(
403             c2_node_id_t id,
404             std::shared_ptr<C2ComponentInterface>* const interface,
405             std::function<void(C2ComponentInterface*)> deleter) override {
406         *interface = std::shared_ptr<C2ComponentInterface>(
407             new SimpleInterface<C2SoftAmrWbEnc::IntfImpl>(
408                 COMPONENT_NAME, id,
409                 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
410             deleter);
411         return C2_OK;
412     }
413 
414     virtual ~C2SoftAmrWbEncFactory() override = default;
415 
416 private:
417     std::shared_ptr<C2ReflectorHelper> mHelper;
418 };
419 
420 }  // namespace android
421 
CreateCodec2Factory()422 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
423     ALOGV("in %s", __func__);
424     return new ::android::C2SoftAmrWbEncFactory();
425 }
426 
DestroyCodec2Factory(::C2ComponentFactory * factory)427 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
428     ALOGV("in %s", __func__);
429     delete factory;
430 }
431