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 "C2SoftAmrNbEnc"
19 #include <log/log.h>
20 
21 #include <media/stagefright/foundation/MediaDefs.h>
22 
23 #include <C2PlatformSupport.h>
24 #include <SimpleC2Interface.h>
25 
26 #include "C2SoftAmrNbEnc.h"
27 
28 namespace android {
29 
30 namespace {
31 
32 constexpr char COMPONENT_NAME[] = "c2.android.amrnb.encoder";
33 
34 }  // namespace
35 
36 
37 class C2SoftAmrNbEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
38 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)39     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
40         : SimpleInterface<void>::BaseParams(
41                 helper,
42                 COMPONENT_NAME,
43                 C2Component::KIND_ENCODER,
44                 C2Component::DOMAIN_AUDIO,
45                 MEDIA_MIMETYPE_AUDIO_AMR_NB) {
46         noPrivateBuffers();
47         noInputReferences();
48         noOutputReferences();
49         noInputLatency();
50         noTimeStretch();
51         setDerivedInstance(this);
52 
53         addParameter(
54                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
55                 .withConstValue(new C2ComponentAttributesSetting(
56                     C2Component::ATTRIB_IS_TEMPORAL))
57                 .build());
58 
59         addParameter(
60                 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
61                 .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
62                 .withFields({C2F(mChannelCount, value).equalTo(1)})
63                 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
64                 .build());
65 
66         addParameter(
67             DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
68                 .withDefault(new C2StreamSampleRateInfo::input(0u, 8000))
69                 .withFields({C2F(mSampleRate, value).equalTo(8000)})
70                 .withSetter(
71                     (Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
72                 .build());
73 
74         addParameter(
75                 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
76                 .withDefault(new C2StreamBitrateInfo::output(0u, 4750))
77                 .withFields({C2F(mBitrate, value).inRange(4750, 12200)})
78                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
79                 .build());
80 
81         addParameter(
82                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
83                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192))
84                 .build());
85     }
86 
getSampleRate() const87     uint32_t getSampleRate() const { return mSampleRate->value; }
getChannelCount() const88     uint32_t getChannelCount() const { return mChannelCount->value; }
getBitrate() const89     uint32_t getBitrate() const { return mBitrate->value; }
90 
91 private:
92     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
93     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
94     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
95     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
96 };
97 
C2SoftAmrNbEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)98 C2SoftAmrNbEnc::C2SoftAmrNbEnc(const char* name, c2_node_id_t id,
99                                const std::shared_ptr<IntfImpl>& intfImpl)
100     : SimpleC2Component(
101           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
102       mIntf(intfImpl),
103       mEncState(nullptr),
104       mSidState(nullptr) {
105 }
106 
~C2SoftAmrNbEnc()107 C2SoftAmrNbEnc::~C2SoftAmrNbEnc() {
108     onRelease();
109 }
110 
onInit()111 c2_status_t C2SoftAmrNbEnc::onInit() {
112     bool dtx_enable = false;
113 
114     if (AMREncodeInit(&mEncState, &mSidState, dtx_enable) != 0)
115         return C2_CORRUPTED;
116     // TODO: get mode directly from config
117     switch(mIntf->getBitrate()) {
118         case 4750: mMode = MR475;
119             break;
120         case 5150: mMode = MR515;
121             break;
122         case 5900: mMode = MR59;
123             break;
124         case 6700: mMode = MR67;
125             break;
126         case 7400: mMode = MR74;
127             break;
128         case 7950: mMode = MR795;
129             break;
130         case 10200: mMode = MR102;
131             break;
132         case 12200: mMode = MR122;
133             break;
134         default: mMode = MR795;
135     }
136     mIsFirst = true;
137     mSignalledError = false;
138     mSignalledOutputEos = false;
139     mAnchorTimeStamp = 0;
140     mProcessedSamples = 0;
141     mFilledLen = 0;
142 
143     return C2_OK;
144 }
145 
onRelease()146 void C2SoftAmrNbEnc::onRelease() {
147     if (mEncState) {
148         AMREncodeExit(&mEncState, &mSidState);
149         mEncState = mSidState = nullptr;
150     }
151 }
152 
onStop()153 c2_status_t C2SoftAmrNbEnc::onStop() {
154     if (AMREncodeReset(mEncState, mSidState) != 0)
155         return C2_CORRUPTED;
156     mIsFirst = true;
157     mSignalledError = false;
158     mSignalledOutputEos = false;
159     mAnchorTimeStamp = 0;
160     mProcessedSamples = 0;
161     mFilledLen = 0;
162 
163     return C2_OK;
164 }
165 
onReset()166 void C2SoftAmrNbEnc::onReset() {
167     (void) onStop();
168 }
169 
onFlush_sm()170 c2_status_t C2SoftAmrNbEnc::onFlush_sm() {
171     return onStop();
172 }
173 
fillEmptyWork(const std::unique_ptr<C2Work> & work)174 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
175     work->worklets.front()->output.flags = work->input.flags;
176     work->worklets.front()->output.buffers.clear();
177     work->worklets.front()->output.ordinal = work->input.ordinal;
178     work->workletsProcessed = 1u;
179 }
180 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)181 void C2SoftAmrNbEnc::process(
182         const std::unique_ptr<C2Work> &work,
183         const std::shared_ptr<C2BlockPool> &pool) {
184     // Initialize output work
185     work->result = C2_OK;
186     work->workletsProcessed = 1u;
187     work->worklets.front()->output.flags = work->input.flags;
188 
189     if (mSignalledError || mSignalledOutputEos) {
190         work->result = C2_BAD_VALUE;
191         return;
192     }
193 
194     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
195     size_t inOffset = 0u;
196     size_t inSize = 0u;
197     C2ReadView rView = mDummyReadView;
198     if (!work->input.buffers.empty()) {
199         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
200         inSize = rView.capacity();
201         if (inSize && rView.error()) {
202             ALOGE("read view map failed %d", rView.error());
203             work->result = C2_CORRUPTED;
204             return;
205         }
206     }
207 
208     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
209           inSize, (int)work->input.ordinal.timestamp.peeku(),
210           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
211 
212     size_t outCapacity = kNumBytesPerInputFrame;
213     outCapacity += mFilledLen + inSize;
214     std::shared_ptr<C2LinearBlock> outputBlock;
215     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
216     c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &outputBlock);
217     if (err != C2_OK) {
218         ALOGE("fetchLinearBlock for Output failed with status %d", err);
219         work->result = C2_NO_MEMORY;
220         return;
221     }
222     C2WriteView wView = outputBlock->map().get();
223     if (wView.error()) {
224         ALOGE("write view map failed %d", wView.error());
225         work->result = C2_CORRUPTED;
226         return;
227     }
228     uint64_t outTimeStamp =
229         mProcessedSamples * 1000000ll / mIntf->getSampleRate();
230     size_t inPos = 0;
231     size_t outPos = 0;
232     while (inPos < inSize) {
233         const uint8_t *inPtr = rView.data() + inOffset;
234         int validSamples = mFilledLen / sizeof(int16_t);
235         if ((inPos + (kNumBytesPerInputFrame - mFilledLen)) <= inSize) {
236             memcpy(mInputFrame + validSamples, inPtr + inPos,
237                    (kNumBytesPerInputFrame - mFilledLen));
238             inPos += (kNumBytesPerInputFrame - mFilledLen);
239         } else {
240             memcpy(mInputFrame + validSamples, inPtr + inPos, (inSize - inPos));
241             mFilledLen += (inSize - inPos);
242             inPos += (inSize - inPos);
243             if (eos) {
244                 validSamples = mFilledLen / sizeof(int16_t);
245                 memset(mInputFrame + validSamples, 0, (kNumBytesPerInputFrame - mFilledLen));
246             } else break;
247 
248         }
249         Frame_Type_3GPP frameType;
250         int numEncBytes = AMREncode(mEncState, mSidState, mMode, mInputFrame,
251                                     wView.data() + outPos, &frameType,
252                                     AMR_TX_WMF);
253         if (numEncBytes < 0 || numEncBytes > ((int)outCapacity - (int)outPos)) {
254             ALOGE("encodeFrame call failed, state [%d %zu %zu]", numEncBytes, outPos, outCapacity);
255             mSignalledError = true;
256             work->result = C2_CORRUPTED;
257             return;
258         }
259         // Convert header byte from WMF to IETF format.
260         if (numEncBytes > 0)
261             wView.data()[outPos] = ((wView.data()[outPos] << 3) | 4) & 0x7c;
262         outPos += numEncBytes;
263         mProcessedSamples += kNumSamplesPerFrame;
264         mFilledLen = 0;
265     }
266     ALOGV("causal sample size %d", mFilledLen);
267     if (mIsFirst && outPos != 0) {
268         mIsFirst = false;
269         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
270     }
271     fillEmptyWork(work);
272     if (outPos != 0) {
273         work->worklets.front()->output.buffers.push_back(
274                 createLinearBuffer(std::move(outputBlock), 0, outPos));
275         work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
276 
277     }
278     if (eos) {
279         mSignalledOutputEos = true;
280         ALOGV("signalled EOS");
281         if (mFilledLen) ALOGV("Discarding trailing %d bytes", mFilledLen);
282     }
283 }
284 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)285 c2_status_t C2SoftAmrNbEnc::drain(
286         uint32_t drainMode,
287         const std::shared_ptr<C2BlockPool> &pool) {
288     (void) pool;
289     if (drainMode == NO_DRAIN) {
290         ALOGW("drain with NO_DRAIN: no-op");
291         return C2_OK;
292     }
293     if (drainMode == DRAIN_CHAIN) {
294         ALOGW("DRAIN_CHAIN not supported");
295         return C2_OMITTED;
296     }
297 
298     onFlush_sm();
299     return C2_OK;
300 }
301 
302 class C2SoftAmrNbEncFactory : public C2ComponentFactory {
303 public:
C2SoftAmrNbEncFactory()304     C2SoftAmrNbEncFactory()
305         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
306               GetCodec2PlatformComponentStore()->getParamReflector())) {}
307 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)308     virtual c2_status_t createComponent(
309             c2_node_id_t id,
310             std::shared_ptr<C2Component>* const component,
311             std::function<void(C2Component*)> deleter) override {
312         *component = std::shared_ptr<C2Component>(
313             new C2SoftAmrNbEnc(
314                 COMPONENT_NAME, id,
315                 std::make_shared<C2SoftAmrNbEnc::IntfImpl>(mHelper)),
316             deleter);
317         return C2_OK;
318     }
319 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)320     virtual c2_status_t createInterface(
321             c2_node_id_t id,
322             std::shared_ptr<C2ComponentInterface>* const interface,
323             std::function<void(C2ComponentInterface*)> deleter) override {
324         *interface = std::shared_ptr<C2ComponentInterface>(
325             new SimpleInterface<C2SoftAmrNbEnc::IntfImpl>(
326                 COMPONENT_NAME, id,
327                 std::make_shared<C2SoftAmrNbEnc::IntfImpl>(mHelper)),
328             deleter);
329         return C2_OK;
330     }
331 
332     virtual ~C2SoftAmrNbEncFactory() override = default;
333 
334 private:
335     std::shared_ptr<C2ReflectorHelper> mHelper;
336 };
337 
338 }  // namespace android
339 
CreateCodec2Factory()340 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
341     ALOGV("in %s", __func__);
342     return new ::android::C2SoftAmrNbEncFactory();
343 }
344 
DestroyCodec2Factory(::C2ComponentFactory * factory)345 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
346     ALOGV("in %s", __func__);
347     delete factory;
348 }
349