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