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