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