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