• 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 "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(const char * name,c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & helper)107 C2SoftAmrNbEnc::C2SoftAmrNbEnc(const char* name, c2_node_id_t id,
108                                const std::shared_ptr<C2ReflectorHelper>& helper)
109     : C2SoftAmrNbEnc(name, id, std::make_shared<IntfImpl>(helper)) {
110 }
111 
~C2SoftAmrNbEnc()112 C2SoftAmrNbEnc::~C2SoftAmrNbEnc() {
113     onRelease();
114 }
115 
onInit()116 c2_status_t C2SoftAmrNbEnc::onInit() {
117     bool dtx_enable = false;
118 
119     if (AMREncodeInit(&mEncState, &mSidState, dtx_enable) != 0)
120         return C2_CORRUPTED;
121     // TODO: get mode directly from config
122     switch(mIntf->getBitrate()) {
123         case 4750: mMode = MR475;
124             break;
125         case 5150: mMode = MR515;
126             break;
127         case 5900: mMode = MR59;
128             break;
129         case 6700: mMode = MR67;
130             break;
131         case 7400: mMode = MR74;
132             break;
133         case 7950: mMode = MR795;
134             break;
135         case 10200: mMode = MR102;
136             break;
137         case 12200: mMode = MR122;
138             break;
139         default: mMode = MR795;
140     }
141     mIsFirst = true;
142     mSignalledError = false;
143     mSignalledOutputEos = false;
144     mAnchorTimeStamp = 0;
145     mProcessedSamples = 0;
146     mFilledLen = 0;
147 
148     return C2_OK;
149 }
150 
onRelease()151 void C2SoftAmrNbEnc::onRelease() {
152     if (mEncState) {
153         AMREncodeExit(&mEncState, &mSidState);
154         mEncState = mSidState = nullptr;
155     }
156 }
157 
onStop()158 c2_status_t C2SoftAmrNbEnc::onStop() {
159     if (AMREncodeReset(mEncState, mSidState) != 0)
160         return C2_CORRUPTED;
161     mIsFirst = true;
162     mSignalledError = false;
163     mSignalledOutputEos = false;
164     mAnchorTimeStamp = 0;
165     mProcessedSamples = 0;
166     mFilledLen = 0;
167 
168     return C2_OK;
169 }
170 
onReset()171 void C2SoftAmrNbEnc::onReset() {
172     (void) onStop();
173 }
174 
onFlush_sm()175 c2_status_t C2SoftAmrNbEnc::onFlush_sm() {
176     return onStop();
177 }
178 
fillEmptyWork(const std::unique_ptr<C2Work> & work)179 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
180     work->worklets.front()->output.flags = work->input.flags;
181     work->worklets.front()->output.buffers.clear();
182     work->worklets.front()->output.ordinal = work->input.ordinal;
183     work->workletsProcessed = 1u;
184 }
185 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)186 void C2SoftAmrNbEnc::process(
187         const std::unique_ptr<C2Work> &work,
188         const std::shared_ptr<C2BlockPool> &pool) {
189     // Initialize output work
190     work->result = C2_OK;
191     work->workletsProcessed = 1u;
192     work->worklets.front()->output.flags = work->input.flags;
193 
194     if (mSignalledError || mSignalledOutputEos) {
195         work->result = C2_BAD_VALUE;
196         return;
197     }
198 
199     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
200     size_t inOffset = 0u;
201     size_t inSize = 0u;
202     C2ReadView rView = mDummyReadView;
203     if (!work->input.buffers.empty()) {
204         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
205         inSize = rView.capacity();
206         if (inSize && rView.error()) {
207             ALOGE("read view map failed %d", rView.error());
208             work->result = C2_CORRUPTED;
209             return;
210         }
211     }
212 
213     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
214           inSize, (int)work->input.ordinal.timestamp.peeku(),
215           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
216 
217     size_t outCapacity = kNumBytesPerInputFrame;
218     outCapacity += mFilledLen + inSize;
219     std::shared_ptr<C2LinearBlock> outputBlock;
220     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
221     c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &outputBlock);
222     if (err != C2_OK) {
223         ALOGE("fetchLinearBlock for Output failed with status %d", err);
224         work->result = C2_NO_MEMORY;
225         return;
226     }
227     C2WriteView wView = outputBlock->map().get();
228     if (wView.error()) {
229         ALOGE("write view map failed %d", wView.error());
230         work->result = C2_CORRUPTED;
231         return;
232     }
233     int64_t outTimeStamp =
234         mProcessedSamples * 1000000ll / mIntf->getSampleRate();
235     size_t inPos = 0;
236     size_t outPos = 0;
237     while (inPos < inSize || eos) {
238         const uint8_t *inPtr = rView.data() + inOffset;
239         int validSamples = mFilledLen / sizeof(int16_t);
240         if ((inPos + (kNumBytesPerInputFrame - mFilledLen)) <= inSize) {
241             memcpy(mInputFrame + validSamples, inPtr + inPos,
242                    (kNumBytesPerInputFrame - mFilledLen));
243             inPos += (kNumBytesPerInputFrame - mFilledLen);
244         } else {
245             memcpy(mInputFrame + validSamples, inPtr + inPos, (inSize - inPos));
246             mFilledLen += (inSize - inPos);
247             inPos += (inSize - inPos);
248             if (eos && (mFilledLen > 0)) {
249                 validSamples = mFilledLen / sizeof(int16_t);
250                 memset(mInputFrame + validSamples, 0, (kNumBytesPerInputFrame - mFilledLen));
251             } else break;
252         }
253         Frame_Type_3GPP frameType;
254         int numEncBytes = AMREncode(mEncState, mSidState, mMode, mInputFrame,
255                                     wView.data() + outPos, &frameType,
256                                     AMR_TX_WMF);
257         if (numEncBytes < 0 || numEncBytes > ((int)outCapacity - (int)outPos)) {
258             ALOGE("encodeFrame call failed, state [%d %zu %zu]", numEncBytes, outPos, outCapacity);
259             mSignalledError = true;
260             work->result = C2_CORRUPTED;
261             return;
262         }
263         // Convert header byte from WMF to IETF format.
264         if (numEncBytes > 0)
265             wView.data()[outPos] = ((wView.data()[outPos] << 3) | 4) & 0x7c;
266         outPos += numEncBytes;
267         mProcessedSamples += kNumSamplesPerFrame;
268         mFilledLen = 0;
269     }
270     ALOGV("causal sample size %d", mFilledLen);
271     if (mIsFirst && outPos != 0) {
272         mIsFirst = false;
273         mAnchorTimeStamp = work->input.ordinal.timestamp.peekll();
274     }
275     fillEmptyWork(work);
276     if (outPos != 0) {
277         work->worklets.front()->output.buffers.push_back(
278                 createLinearBuffer(std::move(outputBlock), 0, outPos));
279         work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
280 
281     }
282     if (eos) {
283         mSignalledOutputEos = true;
284         ALOGV("signalled EOS");
285     }
286 }
287 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)288 c2_status_t C2SoftAmrNbEnc::drain(
289         uint32_t drainMode,
290         const std::shared_ptr<C2BlockPool> &pool) {
291     (void) pool;
292     if (drainMode == NO_DRAIN) {
293         ALOGW("drain with NO_DRAIN: no-op");
294         return C2_OK;
295     }
296     if (drainMode == DRAIN_CHAIN) {
297         ALOGW("DRAIN_CHAIN not supported");
298         return C2_OMITTED;
299     }
300 
301     onFlush_sm();
302     return C2_OK;
303 }
304 
305 class C2SoftAmrNbEncFactory : public C2ComponentFactory {
306 public:
C2SoftAmrNbEncFactory()307     C2SoftAmrNbEncFactory()
308         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
309               GetCodec2PlatformComponentStore()->getParamReflector())) {}
310 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)311     virtual c2_status_t createComponent(
312             c2_node_id_t id,
313             std::shared_ptr<C2Component>* const component,
314             std::function<void(C2Component*)> deleter) override {
315         *component = std::shared_ptr<C2Component>(
316             new C2SoftAmrNbEnc(
317                 COMPONENT_NAME, id,
318                 std::make_shared<C2SoftAmrNbEnc::IntfImpl>(mHelper)),
319             deleter);
320         return C2_OK;
321     }
322 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)323     virtual c2_status_t createInterface(
324             c2_node_id_t id,
325             std::shared_ptr<C2ComponentInterface>* const interface,
326             std::function<void(C2ComponentInterface*)> deleter) override {
327         *interface = std::shared_ptr<C2ComponentInterface>(
328             new SimpleInterface<C2SoftAmrNbEnc::IntfImpl>(
329                 COMPONENT_NAME, id,
330                 std::make_shared<C2SoftAmrNbEnc::IntfImpl>(mHelper)),
331             deleter);
332         return C2_OK;
333     }
334 
335     virtual ~C2SoftAmrNbEncFactory() override = default;
336 
337 private:
338     std::shared_ptr<C2ReflectorHelper> mHelper;
339 };
340 
341 }  // namespace android
342 
343 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()344 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
345     ALOGV("in %s", __func__);
346     return new ::android::C2SoftAmrNbEncFactory();
347 }
348 
349 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)350 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
351     ALOGV("in %s", __func__);
352     delete factory;
353 }
354