1 /*
2  * Copyright (C) 2019 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 "C2SoftOpusEnc"
19 #include <utils/Log.h>
20 
21 #include <C2PlatformSupport.h>
22 #include <SimpleC2Interface.h>
23 #include <media/stagefright/foundation/MediaDefs.h>
24 #include <media/stagefright/foundation/OpusHeader.h>
25 #include "C2SoftOpusEnc.h"
26 
27 extern "C" {
28     #include <opus.h>
29     #include <opus_multistream.h>
30 }
31 
32 #define DEFAULT_FRAME_DURATION_MS 20
33 namespace android {
34 
35 namespace {
36 
37 constexpr char COMPONENT_NAME[] = "c2.android.opus.encoder";
38 
39 }  // namespace
40 
41 static const int kMaxNumChannelsSupported = 2;
42 
43 class C2SoftOpusEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
44 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)45     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
46         : SimpleInterface<void>::BaseParams(
47                 helper,
48                 COMPONENT_NAME,
49                 C2Component::KIND_ENCODER,
50                 C2Component::DOMAIN_AUDIO,
51                 MEDIA_MIMETYPE_AUDIO_OPUS) {
52         noPrivateBuffers();
53         noInputReferences();
54         noOutputReferences();
55         noInputLatency();
56         noTimeStretch();
57         setDerivedInstance(this);
58 
59         addParameter(
60                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
61                 .withConstValue(new C2ComponentAttributesSetting(
62                     C2Component::ATTRIB_IS_TEMPORAL))
63                 .build());
64 
65         addParameter(
66                 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
67                 .withDefault(new C2StreamSampleRateInfo::input(0u, 48000))
68                 .withFields({C2F(mSampleRate, value).oneOf({
69                     8000, 12000, 16000, 24000, 48000})})
70                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
71                 .build());
72 
73         addParameter(
74                 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
75                 .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
76                 .withFields({C2F(mChannelCount, value).inRange(1, kMaxNumChannelsSupported)})
77                 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
78                 .build());
79 
80         addParameter(
81                 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
82                 .withDefault(new C2StreamBitrateInfo::output(0u, 128000))
83                 .withFields({C2F(mBitrate, value).inRange(500, 512000)})
84                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
85                 .build());
86 
87         addParameter(
88                 DefineParam(mComplexity, C2_PARAMKEY_COMPLEXITY)
89                 .withDefault(new C2StreamComplexityTuning::output(0u, 10))
90                 .withFields({C2F(mComplexity, value).inRange(1, 10)})
91                 .withSetter(Setter<decltype(*mComplexity)>::NonStrictValueWithNoDeps)
92                 .build());
93 
94         addParameter(
95                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
96                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 3840))
97                 .build());
98     }
99 
getSampleRate() const100     uint32_t getSampleRate() const { return mSampleRate->value; }
getChannelCount() const101     uint32_t getChannelCount() const { return mChannelCount->value; }
getBitrate() const102     uint32_t getBitrate() const { return mBitrate->value; }
getComplexity() const103     uint32_t getComplexity() const { return mComplexity->value; }
104 
105 private:
106     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
107     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
108     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
109     std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
110     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
111 };
112 
C2SoftOpusEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)113 C2SoftOpusEnc::C2SoftOpusEnc(const char* name, c2_node_id_t id,
114                                const std::shared_ptr<IntfImpl>& intfImpl)
115     : SimpleC2Component(
116           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
117       mIntf(intfImpl),
118       mOutputBlock(nullptr),
119       mEncoder(nullptr),
120       mInputBufferPcm16(nullptr),
121       mOutIndex(0u) {
122 }
123 
~C2SoftOpusEnc()124 C2SoftOpusEnc::~C2SoftOpusEnc() {
125     onRelease();
126 }
127 
onInit()128 c2_status_t C2SoftOpusEnc::onInit() {
129     return initEncoder();
130 }
131 
configureEncoder()132 c2_status_t C2SoftOpusEnc::configureEncoder() {
133     static const unsigned char mono_mapping[256] = {0};
134     static const unsigned char stereo_mapping[256] = {0, 1};
135     mSampleRate = mIntf->getSampleRate();
136     mChannelCount = mIntf->getChannelCount();
137     uint32_t bitrate = mIntf->getBitrate();
138     int complexity = mIntf->getComplexity();
139     mNumSamplesPerFrame = mSampleRate / (1000 / mFrameDurationMs);
140     mNumPcmBytesPerInputFrame =
141         mChannelCount * mNumSamplesPerFrame * sizeof(int16_t);
142     int err = C2_OK;
143 
144     const unsigned char* mapping;
145     if (mChannelCount == 1) {
146         mapping = mono_mapping;
147     } else if (mChannelCount == 2) {
148         mapping = stereo_mapping;
149     } else {
150         ALOGE("Number of channels (%d) is not supported", mChannelCount);
151         return C2_BAD_VALUE;
152     }
153 
154     if (mEncoder != nullptr) {
155         opus_multistream_encoder_destroy(mEncoder);
156     }
157 
158     mEncoder = opus_multistream_encoder_create(mSampleRate, mChannelCount,
159         1, mChannelCount - 1, mapping, OPUS_APPLICATION_AUDIO, &err);
160     if (err) {
161         ALOGE("Could not create libopus encoder. Error code: %i", err);
162         return C2_CORRUPTED;
163     }
164 
165     // Complexity
166     if (opus_multistream_encoder_ctl(
167             mEncoder, OPUS_SET_COMPLEXITY(complexity)) != OPUS_OK) {
168         ALOGE("failed to set complexity");
169         return C2_BAD_VALUE;
170     }
171 
172     // DTX
173     if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_DTX(0) != OPUS_OK)) {
174         ALOGE("failed to set dtx");
175         return C2_BAD_VALUE;
176     }
177 
178     // Application
179     if (opus_multistream_encoder_ctl(mEncoder,
180             OPUS_SET_APPLICATION(OPUS_APPLICATION_AUDIO)) != OPUS_OK) {
181         ALOGE("failed to set application");
182         return C2_BAD_VALUE;
183     }
184 
185     // Signal type
186     if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_SIGNAL(OPUS_AUTO)) !=
187         OPUS_OK) {
188         ALOGE("failed to set signal");
189         return C2_BAD_VALUE;
190     }
191 
192     // Constrained VBR
193     if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR(1) != OPUS_OK)) {
194         ALOGE("failed to set vbr type");
195         return C2_BAD_VALUE;
196     }
197     if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR_CONSTRAINT(1) !=
198             OPUS_OK)) {
199         ALOGE("failed to set vbr constraint");
200         return C2_BAD_VALUE;
201     }
202 
203     // Bitrate
204     if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_BITRATE(bitrate)) !=
205             OPUS_OK) {
206         ALOGE("failed to set bitrate");
207         return C2_BAD_VALUE;
208     }
209 
210     // Set seek preroll to 80 ms
211     mSeekPreRoll = 80000000;
212     return C2_OK;
213 }
214 
initEncoder()215 c2_status_t C2SoftOpusEnc::initEncoder() {
216     mSignalledEos = false;
217     mSignalledError = false;
218     mHeaderGenerated = false;
219     mIsFirstFrame = true;
220     mEncoderFlushed = false;
221     mBufferAvailable = false;
222     mAnchorTimeStamp = 0ull;
223     mProcessedSamples = 0;
224     mFilledLen = 0;
225     mFrameDurationMs = DEFAULT_FRAME_DURATION_MS;
226     if (!mInputBufferPcm16) {
227         mInputBufferPcm16 =
228             (int16_t*)malloc(kFrameSize * kMaxNumChannels * sizeof(int16_t));
229     }
230     if (!mInputBufferPcm16) return C2_NO_MEMORY;
231 
232     /* Default Configurations */
233     c2_status_t status = configureEncoder();
234     return status;
235 }
236 
onStop()237 c2_status_t C2SoftOpusEnc::onStop() {
238     mSignalledEos = false;
239     mSignalledError = false;
240     mIsFirstFrame = true;
241     mEncoderFlushed = false;
242     mBufferAvailable = false;
243     mAnchorTimeStamp = 0ull;
244     mProcessedSamples = 0u;
245     mFilledLen = 0;
246     if (mEncoder) {
247         int status = opus_multistream_encoder_ctl(mEncoder, OPUS_RESET_STATE);
248         if (status != OPUS_OK) {
249             ALOGE("OPUS_RESET_STATE failed status = %s", opus_strerror(status));
250             mSignalledError = true;
251             return C2_CORRUPTED;
252         }
253     }
254     if (mOutputBlock) mOutputBlock.reset();
255     mOutputBlock = nullptr;
256 
257     return C2_OK;
258 }
259 
onReset()260 void C2SoftOpusEnc::onReset() {
261     (void)onStop();
262 }
263 
onRelease()264 void C2SoftOpusEnc::onRelease() {
265     (void)onStop();
266     if (mInputBufferPcm16) {
267         free(mInputBufferPcm16);
268         mInputBufferPcm16 = nullptr;
269     }
270     if (mEncoder) {
271         opus_multistream_encoder_destroy(mEncoder);
272         mEncoder = nullptr;
273     }
274 }
275 
onFlush_sm()276 c2_status_t C2SoftOpusEnc::onFlush_sm() {
277     return onStop();
278 }
279 
280 // Drain the encoder to get last frames (if any)
drainEncoder(uint8_t * outPtr)281 int C2SoftOpusEnc::drainEncoder(uint8_t* outPtr) {
282     memset((uint8_t *)mInputBufferPcm16 + mFilledLen, 0,
283         (mNumPcmBytesPerInputFrame - mFilledLen));
284     int encodedBytes = opus_multistream_encode(
285         mEncoder, mInputBufferPcm16, mNumSamplesPerFrame, outPtr, kMaxPayload);
286     if (encodedBytes > mOutputBlock->capacity()) {
287         ALOGE("not enough space left to write encoded data, dropping %d bytes",
288               mBytesEncoded);
289         // a fatal error would stop the encoding
290         return -1;
291     }
292     ALOGV("encoded %i Opus bytes from %zu PCM bytes", encodedBytes,
293           mNumPcmBytesPerInputFrame);
294     mEncoderFlushed = true;
295     mFilledLen = 0;
296     return encodedBytes;
297 }
298 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)299 void C2SoftOpusEnc::process(const std::unique_ptr<C2Work>& work,
300                             const std::shared_ptr<C2BlockPool>& pool) {
301     // Initialize output work
302     work->result = C2_OK;
303     work->workletsProcessed = 1u;
304     work->worklets.front()->output.flags = work->input.flags;
305 
306     if (mSignalledError || mSignalledEos) {
307         work->result = C2_BAD_VALUE;
308         return;
309     }
310 
311     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
312     C2ReadView rView = mDummyReadView;
313     size_t inOffset = 0u;
314     size_t inSize = 0u;
315     c2_status_t err = C2_OK;
316     if (!work->input.buffers.empty()) {
317         rView =
318             work->input.buffers[0]->data().linearBlocks().front().map().get();
319         inSize = rView.capacity();
320         if (inSize && rView.error()) {
321             ALOGE("read view map failed %d", rView.error());
322             work->result = C2_CORRUPTED;
323             return;
324         }
325     }
326 
327     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
328           inSize, (int)work->input.ordinal.timestamp.peeku(),
329           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
330 
331     if (!mEncoder) {
332         if (initEncoder() != C2_OK) {
333             ALOGE("initEncoder failed with status %d", err);
334             work->result = err;
335             mSignalledError = true;
336             return;
337         }
338     }
339     if (mIsFirstFrame && inSize > 0) {
340         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
341         mIsFirstFrame = false;
342     }
343 
344     C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
345     err = pool->fetchLinearBlock(kMaxPayload, usage, &mOutputBlock);
346     if (err != C2_OK) {
347         ALOGE("fetchLinearBlock for Output failed with status %d", err);
348         work->result = C2_NO_MEMORY;
349         return;
350     }
351 
352     C2WriteView wView = mOutputBlock->map().get();
353     if (wView.error()) {
354         ALOGE("write view map failed %d", wView.error());
355         work->result = C2_CORRUPTED;
356         mOutputBlock.reset();
357         return;
358     }
359 
360     size_t inPos = 0;
361     size_t processSize = 0;
362     mBytesEncoded = 0;
363     uint64_t outTimeStamp = 0u;
364     std::shared_ptr<C2Buffer> buffer;
365     uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
366     const uint8_t* inPtr = rView.data() + inOffset;
367 
368     class FillWork {
369     public:
370         FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
371                  const std::shared_ptr<C2Buffer> &buffer)
372             : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {
373         }
374         ~FillWork() = default;
375 
376         void operator()(const std::unique_ptr<C2Work>& work) {
377             work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
378             work->worklets.front()->output.buffers.clear();
379             work->worklets.front()->output.ordinal = mOrdinal;
380             work->workletsProcessed = 1u;
381             work->result = C2_OK;
382             if (mBuffer) {
383                 work->worklets.front()->output.buffers.push_back(mBuffer);
384             }
385             ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
386                   mOrdinal.timestamp.peekll(),
387                   mOrdinal.frameIndex.peekll(),
388                   mBuffer ? "" : "o");
389         }
390 
391     private:
392         const uint32_t mFlags;
393         const C2WorkOrdinalStruct mOrdinal;
394         const std::shared_ptr<C2Buffer> mBuffer;
395     };
396 
397     C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
398 
399     if (!mHeaderGenerated) {
400         uint8_t header[AOPUS_UNIFIED_CSD_MAXSIZE];
401         memset(header, 0, sizeof(header));
402 
403         // Get codecDelay
404         int32_t lookahead;
405         if (opus_multistream_encoder_ctl(mEncoder, OPUS_GET_LOOKAHEAD(&lookahead)) !=
406                 OPUS_OK) {
407             ALOGE("failed to get lookahead");
408             mSignalledError = true;
409             work->result = C2_CORRUPTED;
410             return;
411         }
412         mCodecDelay = lookahead * 1000000000ll / mSampleRate;
413 
414         OpusHeader opusHeader;
415         memset(&opusHeader, 0, sizeof(opusHeader));
416         opusHeader.channels = mChannelCount;
417         opusHeader.num_streams = mChannelCount;
418         opusHeader.num_coupled = 0;
419         opusHeader.channel_mapping = ((mChannelCount > 8) ? 255 : (mChannelCount > 2));
420         opusHeader.gain_db = 0;
421         opusHeader.skip_samples = lookahead;
422         int headerLen = WriteOpusHeaders(opusHeader, mSampleRate, header,
423             sizeof(header), mCodecDelay, mSeekPreRoll);
424 
425         std::unique_ptr<C2StreamInitDataInfo::output> csd =
426             C2StreamInitDataInfo::output::AllocUnique(headerLen, 0u);
427         if (!csd) {
428             ALOGE("CSD allocation failed");
429             mSignalledError = true;
430             work->result = C2_NO_MEMORY;
431             return;
432         }
433         ALOGV("put csd, %d bytes", headerLen);
434         memcpy(csd->m.value, header, headerLen);
435         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
436         mHeaderGenerated = true;
437     }
438 
439     /*
440      * For buffer size which is not a multiple of mNumPcmBytesPerInputFrame, we will
441      * accumulate the input and keep it. Once the input is filled with expected number
442      * of bytes, we will send it to encoder. mFilledLen manages the bytes of input yet
443      * to be processed. The next call will fill mNumPcmBytesPerInputFrame - mFilledLen
444      * bytes to input and send it to the encoder.
445      */
446     while (inPos < inSize) {
447         const uint8_t* pcmBytes = inPtr + inPos;
448         int filledSamples = mFilledLen / sizeof(int16_t);
449         if ((inPos + (mNumPcmBytesPerInputFrame - mFilledLen)) <= inSize) {
450             processSize = mNumPcmBytesPerInputFrame - mFilledLen;
451             mBufferAvailable = true;
452         } else {
453             processSize = inSize - inPos;
454             mBufferAvailable = false;
455             if (eos) {
456                 memset(mInputBufferPcm16 + filledSamples, 0,
457                        (mNumPcmBytesPerInputFrame - mFilledLen));
458                 mBufferAvailable = true;
459             }
460         }
461         const unsigned nInputSamples = processSize / sizeof(int16_t);
462 
463         for (unsigned i = 0; i < nInputSamples; i++) {
464             int32_t data = pcmBytes[2 * i + 1] << 8 | pcmBytes[2 * i];
465             data = ((data & 0xFFFF) ^ 0x8000) - 0x8000;
466             mInputBufferPcm16[i + filledSamples] = data;
467         }
468         inPos += processSize;
469         mFilledLen += processSize;
470         if (!mBufferAvailable) break;
471         uint8_t* outPtr = wView.data() + mBytesEncoded;
472         int encodedBytes =
473             opus_multistream_encode(mEncoder, mInputBufferPcm16,
474                                     mNumSamplesPerFrame, outPtr, kMaxPayload - mBytesEncoded);
475         ALOGV("encoded %i Opus bytes from %zu PCM bytes", encodedBytes,
476               processSize);
477 
478         if (encodedBytes < 0 || encodedBytes > (kMaxPayload - mBytesEncoded)) {
479             ALOGE("opus_encode failed, encodedBytes : %d", encodedBytes);
480             mSignalledError = true;
481             work->result = C2_CORRUPTED;
482             return;
483         }
484         if (buffer) {
485             outOrdinal.frameIndex = mOutIndex++;
486             outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
487             cloneAndSend(
488                 inputIndex, work,
489                 FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
490             buffer.reset();
491         }
492         if (encodedBytes > 0) {
493             buffer =
494                 createLinearBuffer(mOutputBlock, mBytesEncoded, encodedBytes);
495         }
496         mBytesEncoded += encodedBytes;
497         mProcessedSamples += (filledSamples + nInputSamples);
498         outTimeStamp =
499             mProcessedSamples * 1000000ll / mChannelCount / mSampleRate;
500         if ((processSize + mFilledLen) < mNumPcmBytesPerInputFrame)
501             mEncoderFlushed = true;
502         mFilledLen = 0;
503     }
504 
505     uint32_t flags = 0;
506     if (eos) {
507         ALOGV("signalled eos");
508         mSignalledEos = true;
509         if (!mEncoderFlushed) {
510             if (buffer) {
511                 outOrdinal.frameIndex = mOutIndex++;
512                 outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
513                 cloneAndSend(
514                     inputIndex, work,
515                     FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
516                 buffer.reset();
517             }
518             // drain the encoder for last buffer
519             drainInternal(pool, work);
520         }
521         flags = C2FrameData::FLAG_END_OF_STREAM;
522     }
523     if (buffer) {
524         outOrdinal.frameIndex = mOutIndex++;
525         outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
526         FillWork((C2FrameData::flags_t)(flags), outOrdinal, buffer)(work);
527         buffer.reset();
528     }
529     mOutputBlock = nullptr;
530 }
531 
drainInternal(const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)532 c2_status_t C2SoftOpusEnc::drainInternal(
533         const std::shared_ptr<C2BlockPool>& pool,
534         const std::unique_ptr<C2Work>& work) {
535     mBytesEncoded = 0;
536     std::shared_ptr<C2Buffer> buffer = nullptr;
537     C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
538     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
539 
540     C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
541     c2_status_t err = pool->fetchLinearBlock(kMaxPayload, usage, &mOutputBlock);
542     if (err != C2_OK) {
543         ALOGE("fetchLinearBlock for Output failed with status %d", err);
544         return C2_NO_MEMORY;
545     }
546 
547     C2WriteView wView = mOutputBlock->map().get();
548     if (wView.error()) {
549         ALOGE("write view map failed %d", wView.error());
550         mOutputBlock.reset();
551         return C2_CORRUPTED;
552     }
553 
554     int encBytes = drainEncoder(wView.data());
555     if (encBytes > 0) mBytesEncoded += encBytes;
556     if (mBytesEncoded > 0) {
557         buffer = createLinearBuffer(mOutputBlock, 0, mBytesEncoded);
558         mOutputBlock.reset();
559     }
560     mProcessedSamples += (mNumPcmBytesPerInputFrame / sizeof(int16_t));
561     uint64_t outTimeStamp =
562         mProcessedSamples * 1000000ll / mChannelCount / mSampleRate;
563     outOrdinal.frameIndex = mOutIndex++;
564     outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
565     work->worklets.front()->output.flags =
566         (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0);
567     work->worklets.front()->output.buffers.clear();
568     work->worklets.front()->output.ordinal = outOrdinal;
569     work->workletsProcessed = 1u;
570     work->result = C2_OK;
571     if (buffer) {
572         work->worklets.front()->output.buffers.push_back(buffer);
573     }
574     mOutputBlock = nullptr;
575     return C2_OK;
576 }
577 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)578 c2_status_t C2SoftOpusEnc::drain(uint32_t drainMode,
579                                  const std::shared_ptr<C2BlockPool>& pool) {
580     if (drainMode == NO_DRAIN) {
581         ALOGW("drain with NO_DRAIN: no-op");
582         return C2_OK;
583     }
584     if (drainMode == DRAIN_CHAIN) {
585         ALOGW("DRAIN_CHAIN not supported");
586         return C2_OMITTED;
587     }
588     mIsFirstFrame = true;
589     mAnchorTimeStamp = 0ull;
590     mProcessedSamples = 0u;
591     return drainInternal(pool, nullptr);
592 }
593 
594 class C2SoftOpusEncFactory : public C2ComponentFactory {
595 public:
C2SoftOpusEncFactory()596     C2SoftOpusEncFactory()
597         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
598               GetCodec2PlatformComponentStore()->getParamReflector())) {}
599 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)600     virtual c2_status_t createComponent(
601         c2_node_id_t id, std::shared_ptr<C2Component>* const component,
602         std::function<void(C2Component*)> deleter) override {
603         *component = std::shared_ptr<C2Component>(
604             new C2SoftOpusEnc(
605                 COMPONENT_NAME, id,
606                 std::make_shared<C2SoftOpusEnc::IntfImpl>(mHelper)),
607             deleter);
608         return C2_OK;
609     }
610 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)611     virtual c2_status_t createInterface(
612         c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
613         std::function<void(C2ComponentInterface*)> deleter) override {
614         *interface = std::shared_ptr<C2ComponentInterface>(
615             new SimpleInterface<C2SoftOpusEnc::IntfImpl>(
616                 COMPONENT_NAME, id,
617                 std::make_shared<C2SoftOpusEnc::IntfImpl>(mHelper)),
618             deleter);
619         return C2_OK;
620     }
621 
622     virtual ~C2SoftOpusEncFactory() override = default;
623 private:
624     std::shared_ptr<C2ReflectorHelper> mHelper;
625 };
626 
627 }  // namespace android
628 
CreateCodec2Factory()629 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
630     ALOGV("in %s", __func__);
631     return new ::android::C2SoftOpusEncFactory();
632 }
633 
DestroyCodec2Factory(::C2ComponentFactory * factory)634 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
635     ALOGV("in %s", __func__);
636     delete factory;
637 }
638