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