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