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