blob: d6517ea827600485b2f5e589c2788ffa7ebeeb91 [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
Harish Mahendrakara0a5fde2019-05-17 11:41:18 -070041static const int kMaxNumChannelsSupported = 2;
42
Rakesh Kumar66d9d062019-03-12 17:46:17 +053043class C2SoftOpusEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
Manisha Jajooc237cbc2018-11-16 18:56:20 +053044public:
45 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
Rakesh Kumar66d9d062019-03-12 17:46:17 +053046 : 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();
Manisha Jajooc237cbc2018-11-16 18:56:20 +053057 setDerivedInstance(this);
58
59 addParameter(
Rakesh Kumar66d9d062019-03-12 17:46:17 +053060 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
61 .withConstValue(new C2ComponentAttributesSetting(
62 C2Component::ATTRIB_IS_TEMPORAL))
Manisha Jajooc237cbc2018-11-16 18:56:20 +053063 .build());
64
65 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -080066 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
Manisha Jajooc237cbc2018-11-16 18:56:20 +053067 .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(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -080074 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
Manisha Jajooc237cbc2018-11-16 18:56:20 +053075 .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
Harish Mahendrakara0a5fde2019-05-17 11:41:18 -070076 .withFields({C2F(mChannelCount, value).inRange(1, kMaxNumChannelsSupported)})
Manisha Jajooc237cbc2018-11-16 18:56:20 +053077 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
78 .build());
79
80 addParameter(
Lajos Molnar3bb81cd2019-02-20 15:10:30 -080081 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
82 .withDefault(new C2StreamBitrateInfo::output(0u, 128000))
Manisha Jajooc237cbc2018-11-16 18:56:20 +053083 .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
100 uint32_t getSampleRate() const { return mSampleRate->value; }
101 uint32_t getChannelCount() const { return mChannelCount->value; }
102 uint32_t getBitrate() const { return mBitrate->value; }
103 uint32_t getComplexity() const { return mComplexity->value; }
104
105private:
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530106 std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
107 std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800108 std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530109 std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
110 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
111};
112
113C2SoftOpusEnc::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
124C2SoftOpusEnc::~C2SoftOpusEnc() {
125 onRelease();
126}
127
128c2_status_t C2SoftOpusEnc::onInit() {
129 return initEncoder();
130}
131
132c2_status_t C2SoftOpusEnc::configureEncoder() {
Harish Mahendrakara0a5fde2019-05-17 11:41:18 -0700133 static const unsigned char mono_mapping[256] = {0};
134 static const unsigned char stereo_mapping[256] = {0, 1};
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530135 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
Harish Mahendrakara0a5fde2019-05-17 11:41:18 -0700144 const unsigned char* mapping;
145 if (mChannelCount == 1) {
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530146 mapping = mono_mapping;
147 } else if (mChannelCount == 2) {
148 mapping = stereo_mapping;
149 } else {
Harish Mahendrakara0a5fde2019-05-17 11:41:18 -0700150 ALOGE("Number of channels (%d) is not supported", mChannelCount);
151 return C2_BAD_VALUE;
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530152 }
153
154 if (mEncoder != nullptr) {
155 opus_multistream_encoder_destroy(mEncoder);
156 }
157
158 mEncoder = opus_multistream_encoder_create(mSampleRate, mChannelCount,
Harish Mahendrakara0a5fde2019-05-17 11:41:18 -0700159 1, mChannelCount - 1, mapping, OPUS_APPLICATION_AUDIO, &err);
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530160 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
James O'Learyffd6cbc2019-04-26 10:56:03 -0400192 // Constrained VBR
193 if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR(1) != OPUS_OK)) {
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530194 ALOGE("failed to set vbr type");
195 return C2_BAD_VALUE;
196 }
James O'Learyffd6cbc2019-04-26 10:56:03 -0400197 if (opus_multistream_encoder_ctl(mEncoder, OPUS_SET_VBR_CONSTRAINT(1) !=
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530198 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 // Get codecDelay
211 int32_t lookahead;
212 if (opus_multistream_encoder_ctl(mEncoder, OPUS_GET_LOOKAHEAD(&lookahead)) !=
213 OPUS_OK) {
214 ALOGE("failed to get lookahead");
215 return C2_BAD_VALUE;
216 }
217 mCodecDelay = lookahead * 1000000000ll / mSampleRate;
218
219 // Set seek preroll to 80 ms
220 mSeekPreRoll = 80000000;
221 return C2_OK;
222}
223
224c2_status_t C2SoftOpusEnc::initEncoder() {
225 mSignalledEos = false;
226 mSignalledError = false;
227 mHeaderGenerated = false;
228 mIsFirstFrame = true;
229 mEncoderFlushed = false;
230 mBufferAvailable = false;
231 mAnchorTimeStamp = 0ull;
232 mProcessedSamples = 0;
233 mFilledLen = 0;
234 mFrameDurationMs = DEFAULT_FRAME_DURATION_MS;
235 if (!mInputBufferPcm16) {
236 mInputBufferPcm16 =
237 (int16_t*)malloc(kFrameSize * kMaxNumChannels * sizeof(int16_t));
238 }
239 if (!mInputBufferPcm16) return C2_NO_MEMORY;
240
241 /* Default Configurations */
242 c2_status_t status = configureEncoder();
243 return status;
244}
245
246c2_status_t C2SoftOpusEnc::onStop() {
247 mSignalledEos = false;
248 mSignalledError = false;
249 mIsFirstFrame = true;
250 mEncoderFlushed = false;
251 mBufferAvailable = false;
252 mAnchorTimeStamp = 0ull;
253 mProcessedSamples = 0u;
254 mFilledLen = 0;
255 if (mEncoder) {
256 int status = opus_multistream_encoder_ctl(mEncoder, OPUS_RESET_STATE);
257 if (status != OPUS_OK) {
258 ALOGE("OPUS_RESET_STATE failed status = %s", opus_strerror(status));
259 mSignalledError = true;
260 return C2_CORRUPTED;
261 }
262 }
263 if (mOutputBlock) mOutputBlock.reset();
264 mOutputBlock = nullptr;
265
266 return C2_OK;
267}
268
269void C2SoftOpusEnc::onReset() {
270 (void)onStop();
271}
272
273void C2SoftOpusEnc::onRelease() {
274 (void)onStop();
275 if (mInputBufferPcm16) {
276 free(mInputBufferPcm16);
277 mInputBufferPcm16 = nullptr;
278 }
279 if (mEncoder) {
280 opus_multistream_encoder_destroy(mEncoder);
281 mEncoder = nullptr;
282 }
283}
284
285c2_status_t C2SoftOpusEnc::onFlush_sm() {
286 return onStop();
287}
288
289// Drain the encoder to get last frames (if any)
290int C2SoftOpusEnc::drainEncoder(uint8_t* outPtr) {
291 memset((uint8_t *)mInputBufferPcm16 + mFilledLen, 0,
292 (mNumPcmBytesPerInputFrame - mFilledLen));
293 int encodedBytes = opus_multistream_encode(
294 mEncoder, mInputBufferPcm16, mNumSamplesPerFrame, outPtr, kMaxPayload);
295 if (encodedBytes > mOutputBlock->capacity()) {
296 ALOGE("not enough space left to write encoded data, dropping %d bytes",
297 mBytesEncoded);
298 // a fatal error would stop the encoding
299 return -1;
300 }
301 ALOGV("encoded %i Opus bytes from %zu PCM bytes", encodedBytes,
302 mNumPcmBytesPerInputFrame);
303 mEncoderFlushed = true;
304 mFilledLen = 0;
305 return encodedBytes;
306}
307
308void C2SoftOpusEnc::process(const std::unique_ptr<C2Work>& work,
309 const std::shared_ptr<C2BlockPool>& pool) {
310 // Initialize output work
311 work->result = C2_OK;
312 work->workletsProcessed = 1u;
313 work->worklets.front()->output.flags = work->input.flags;
314
315 if (mSignalledError || mSignalledEos) {
316 work->result = C2_BAD_VALUE;
317 return;
318 }
319
320 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
321 C2ReadView rView = mDummyReadView;
322 size_t inOffset = 0u;
323 size_t inSize = 0u;
324 c2_status_t err = C2_OK;
325 if (!work->input.buffers.empty()) {
326 rView =
327 work->input.buffers[0]->data().linearBlocks().front().map().get();
328 inSize = rView.capacity();
329 if (inSize && rView.error()) {
330 ALOGE("read view map failed %d", rView.error());
331 work->result = C2_CORRUPTED;
332 return;
333 }
334 }
335
336 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
337 inSize, (int)work->input.ordinal.timestamp.peeku(),
338 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
339
340 if (!mEncoder) {
341 if (initEncoder() != C2_OK) {
342 ALOGE("initEncoder failed with status %d", err);
343 work->result = err;
344 mSignalledError = true;
345 return;
346 }
347 }
Wonsik Kim353e1672019-01-07 16:31:29 -0800348 if (mIsFirstFrame && inSize > 0) {
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530349 mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
350 mIsFirstFrame = false;
351 }
352
353 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
354 err = pool->fetchLinearBlock(kMaxPayload, usage, &mOutputBlock);
355 if (err != C2_OK) {
356 ALOGE("fetchLinearBlock for Output failed with status %d", err);
357 work->result = C2_NO_MEMORY;
358 return;
359 }
360
361 C2WriteView wView = mOutputBlock->map().get();
362 if (wView.error()) {
363 ALOGE("write view map failed %d", wView.error());
364 work->result = C2_CORRUPTED;
365 mOutputBlock.reset();
366 return;
367 }
368
369 size_t inPos = 0;
370 size_t processSize = 0;
371 mBytesEncoded = 0;
372 uint64_t outTimeStamp = 0u;
373 std::shared_ptr<C2Buffer> buffer;
374 uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
375 const uint8_t* inPtr = rView.data() + inOffset;
376
377 class FillWork {
378 public:
379 FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
380 const std::shared_ptr<C2Buffer> &buffer)
381 : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {
382 }
383 ~FillWork() = default;
384
385 void operator()(const std::unique_ptr<C2Work>& work) {
386 work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
387 work->worklets.front()->output.buffers.clear();
388 work->worklets.front()->output.ordinal = mOrdinal;
389 work->workletsProcessed = 1u;
390 work->result = C2_OK;
391 if (mBuffer) {
392 work->worklets.front()->output.buffers.push_back(mBuffer);
393 }
394 ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
395 mOrdinal.timestamp.peekll(),
396 mOrdinal.frameIndex.peekll(),
397 mBuffer ? "" : "o");
398 }
399
400 private:
401 const uint32_t mFlags;
402 const C2WorkOrdinalStruct mOrdinal;
403 const std::shared_ptr<C2Buffer> mBuffer;
404 };
405
406 C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
407
408 if (!mHeaderGenerated) {
409 uint8_t header[AOPUS_UNIFIED_CSD_MAXSIZE];
410 memset(header, 0, sizeof(header));
411 OpusHeader opusHeader;
412 opusHeader.channels = mChannelCount;
413 opusHeader.num_streams = mChannelCount;
414 opusHeader.num_coupled = 0;
415 opusHeader.channel_mapping = ((mChannelCount > 8) ? 255 : (mChannelCount > 2));
416 opusHeader.gain_db = 0;
417 opusHeader.skip_samples = 0;
418 int headerLen = WriteOpusHeaders(opusHeader, mSampleRate, header,
419 sizeof(header), mCodecDelay, mSeekPreRoll);
420
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800421 std::unique_ptr<C2StreamInitDataInfo::output> csd =
422 C2StreamInitDataInfo::output::AllocUnique(headerLen, 0u);
Manisha Jajooc237cbc2018-11-16 18:56:20 +0530423 if (!csd) {
424 ALOGE("CSD allocation failed");
425 mSignalledError = true;
426 work->result = C2_NO_MEMORY;
427 return;
428 }
429 ALOGV("put csd, %d bytes", headerLen);
430 memcpy(csd->m.value, header, headerLen);
431 work->worklets.front()->output.configUpdate.push_back(std::move(csd));
432 mHeaderGenerated = true;
433 }
434
435 /*
436 * For buffer size which is not a multiple of mNumPcmBytesPerInputFrame, we will
437 * accumulate the input and keep it. Once the input is filled with expected number
438 * of bytes, we will send it to encoder. mFilledLen manages the bytes of input yet
439 * to be processed. The next call will fill mNumPcmBytesPerInputFrame - mFilledLen
440 * bytes to input and send it to the encoder.
441 */
442 while (inPos < inSize) {
443 const uint8_t* pcmBytes = inPtr + inPos;
444 int filledSamples = mFilledLen / sizeof(int16_t);
445 if ((inPos + (mNumPcmBytesPerInputFrame - mFilledLen)) <= inSize) {
446 processSize = mNumPcmBytesPerInputFrame - mFilledLen;
447 mBufferAvailable = true;
448 } else {
449 processSize = inSize - inPos;
450 mBufferAvailable = false;
451 if (eos) {
452 memset(mInputBufferPcm16 + filledSamples, 0,
453 (mNumPcmBytesPerInputFrame - mFilledLen));
454 mBufferAvailable = true;
455 }
456 }
457 const unsigned nInputSamples = processSize / sizeof(int16_t);
458
459 for (unsigned i = 0; i < nInputSamples; i++) {
460 int32_t data = pcmBytes[2 * i + 1] << 8 | pcmBytes[2 * i];
461 data = ((data & 0xFFFF) ^ 0x8000) - 0x8000;
462 mInputBufferPcm16[i + filledSamples] = data;
463 }
464 inPos += processSize;
465 mFilledLen += processSize;
466 if (!mBufferAvailable) break;
467 uint8_t* outPtr = wView.data() + mBytesEncoded;
468 int encodedBytes =
469 opus_multistream_encode(mEncoder, mInputBufferPcm16,
470 mNumSamplesPerFrame, outPtr, kMaxPayload);
471 ALOGV("encoded %i Opus bytes from %zu PCM bytes", encodedBytes,
472 processSize);
473
474 if (encodedBytes < 0 || encodedBytes > kMaxPayload) {
475 ALOGE("opus_encode failed, encodedBytes : %d", encodedBytes);
476 mSignalledError = true;
477 work->result = C2_CORRUPTED;
478 return;
479 }
480 if (buffer) {
481 outOrdinal.frameIndex = mOutIndex++;
482 outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
483 cloneAndSend(
484 inputIndex, work,
485 FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
486 buffer.reset();
487 }
488 if (encodedBytes > 0) {
489 buffer =
490 createLinearBuffer(mOutputBlock, mBytesEncoded, encodedBytes);
491 }
492 mBytesEncoded += encodedBytes;
493 mProcessedSamples += (filledSamples + nInputSamples);
494 outTimeStamp =
495 mProcessedSamples * 1000000ll / mChannelCount / mSampleRate;
496 if ((processSize + mFilledLen) < mNumPcmBytesPerInputFrame)
497 mEncoderFlushed = true;
498 mFilledLen = 0;
499 }
500
501 uint32_t flags = 0;
502 if (eos) {
503 ALOGV("signalled eos");
504 mSignalledEos = true;
505 if (!mEncoderFlushed) {
506 if (buffer) {
507 outOrdinal.frameIndex = mOutIndex++;
508 outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
509 cloneAndSend(
510 inputIndex, work,
511 FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
512 buffer.reset();
513 }
514 // drain the encoder for last buffer
515 drainInternal(pool, work);
516 }
517 flags = C2FrameData::FLAG_END_OF_STREAM;
518 }
519 if (buffer) {
520 outOrdinal.frameIndex = mOutIndex++;
521 outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
522 FillWork((C2FrameData::flags_t)(flags), outOrdinal, buffer)(work);
523 buffer.reset();
524 }
525 mOutputBlock = nullptr;
526}
527
528c2_status_t C2SoftOpusEnc::drainInternal(
529 const std::shared_ptr<C2BlockPool>& pool,
530 const std::unique_ptr<C2Work>& work) {
531 mBytesEncoded = 0;
532 std::shared_ptr<C2Buffer> buffer = nullptr;
533 C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
534 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
535
536 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
537 c2_status_t err = pool->fetchLinearBlock(kMaxPayload, usage, &mOutputBlock);
538 if (err != C2_OK) {
539 ALOGE("fetchLinearBlock for Output failed with status %d", err);
540 return C2_NO_MEMORY;
541 }
542
543 C2WriteView wView = mOutputBlock->map().get();
544 if (wView.error()) {
545 ALOGE("write view map failed %d", wView.error());
546 mOutputBlock.reset();
547 return C2_CORRUPTED;
548 }
549
550 int encBytes = drainEncoder(wView.data());
551 if (encBytes > 0) mBytesEncoded += encBytes;
552 if (mBytesEncoded > 0) {
553 buffer = createLinearBuffer(mOutputBlock, 0, mBytesEncoded);
554 mOutputBlock.reset();
555 }
556 mProcessedSamples += (mNumPcmBytesPerInputFrame / sizeof(int16_t));
557 uint64_t outTimeStamp =
558 mProcessedSamples * 1000000ll / mChannelCount / mSampleRate;
559 outOrdinal.frameIndex = mOutIndex++;
560 outOrdinal.timestamp = mAnchorTimeStamp + outTimeStamp;
561 work->worklets.front()->output.flags =
562 (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0);
563 work->worklets.front()->output.buffers.clear();
564 work->worklets.front()->output.ordinal = outOrdinal;
565 work->workletsProcessed = 1u;
566 work->result = C2_OK;
567 if (buffer) {
568 work->worklets.front()->output.buffers.push_back(buffer);
569 }
570 mOutputBlock = nullptr;
571 return C2_OK;
572}
573
574c2_status_t C2SoftOpusEnc::drain(uint32_t drainMode,
575 const std::shared_ptr<C2BlockPool>& pool) {
576 if (drainMode == NO_DRAIN) {
577 ALOGW("drain with NO_DRAIN: no-op");
578 return C2_OK;
579 }
580 if (drainMode == DRAIN_CHAIN) {
581 ALOGW("DRAIN_CHAIN not supported");
582 return C2_OMITTED;
583 }
584 mIsFirstFrame = true;
585 mAnchorTimeStamp = 0ull;
586 mProcessedSamples = 0u;
587 return drainInternal(pool, nullptr);
588}
589
590class C2SoftOpusEncFactory : public C2ComponentFactory {
591public:
592 C2SoftOpusEncFactory()
593 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
594 GetCodec2PlatformComponentStore()->getParamReflector())) {}
595
596 virtual c2_status_t createComponent(
597 c2_node_id_t id, std::shared_ptr<C2Component>* const component,
598 std::function<void(C2Component*)> deleter) override {
599 *component = std::shared_ptr<C2Component>(
600 new C2SoftOpusEnc(
601 COMPONENT_NAME, id,
602 std::make_shared<C2SoftOpusEnc::IntfImpl>(mHelper)),
603 deleter);
604 return C2_OK;
605 }
606
607 virtual c2_status_t createInterface(
608 c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
609 std::function<void(C2ComponentInterface*)> deleter) override {
610 *interface = std::shared_ptr<C2ComponentInterface>(
611 new SimpleInterface<C2SoftOpusEnc::IntfImpl>(
612 COMPONENT_NAME, id,
613 std::make_shared<C2SoftOpusEnc::IntfImpl>(mHelper)),
614 deleter);
615 return C2_OK;
616 }
617
618 virtual ~C2SoftOpusEncFactory() override = default;
619private:
620 std::shared_ptr<C2ReflectorHelper> mHelper;
621};
622
623} // namespace android
624
625extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
626 ALOGV("in %s", __func__);
627 return new ::android::C2SoftOpusEncFactory();
628}
629
630extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
631 ALOGV("in %s", __func__);
632 delete factory;
633}