1 /*
2 * Copyright (C) 2018 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 "C2SoftOpusDec"
19 #include <log/log.h>
20
21 #include <media/stagefright/foundation/MediaDefs.h>
22 #include <media/stagefright/foundation/OpusHeader.h>
23 #include <C2PlatformSupport.h>
24 #include <SimpleC2Interface.h>
25 #include "C2SoftOpusDec.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.decoder";
37
38 } // namespace
39
40 class C2SoftOpusDec::IntfImpl : public SimpleInterface<void>::BaseParams {
41 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)42 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
43 : SimpleInterface<void>::BaseParams(
44 helper,
45 COMPONENT_NAME,
46 C2Component::KIND_DECODER,
47 C2Component::DOMAIN_AUDIO,
48 MEDIA_MIMETYPE_AUDIO_OPUS) {
49 noPrivateBuffers();
50 noInputReferences();
51 noOutputReferences();
52 noInputLatency();
53 noTimeStretch();
54 setDerivedInstance(this);
55
56 addParameter(
57 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
58 .withConstValue(new C2ComponentAttributesSetting(
59 C2Component::ATTRIB_IS_TEMPORAL))
60 .build());
61
62 addParameter(
63 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
64 .withDefault(new C2StreamSampleRateInfo::output(0u, 48000))
65 .withFields({C2F(mSampleRate, value).inRange(8000, 48000)})
66 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
67 .build());
68
69 addParameter(
70 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
71 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
72 .withFields({C2F(mChannelCount, value).inRange(1, 8)})
73 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
74 .build());
75
76 addParameter(
77 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
78 .withDefault(new C2StreamBitrateInfo::input(0u, 6000))
79 .withFields({C2F(mBitrate, value).inRange(6000, 510000)})
80 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
81 .build());
82
83 addParameter(
84 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
85 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 960 * 6))
86 .build());
87 }
88
89 private:
90 std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
91 std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
92 std::shared_ptr<C2StreamBitrateInfo::input> mBitrate;
93 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
94 };
95
C2SoftOpusDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)96 C2SoftOpusDec::C2SoftOpusDec(const char *name, c2_node_id_t id,
97 const std::shared_ptr<IntfImpl>& intfImpl)
98 : SimpleC2Component(
99 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
100 mIntf(intfImpl),
101 mDecoder(nullptr) {
102 }
103
C2SoftOpusDec(const char * name,c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & helper)104 C2SoftOpusDec::C2SoftOpusDec(const char *name, c2_node_id_t id,
105 const std::shared_ptr<C2ReflectorHelper>& helper)
106 : C2SoftOpusDec(name, id, std::make_shared<IntfImpl>(helper)) {
107 }
108
~C2SoftOpusDec()109 C2SoftOpusDec::~C2SoftOpusDec() {
110 onRelease();
111 }
112
onInit()113 c2_status_t C2SoftOpusDec::onInit() {
114 status_t err = initDecoder();
115 return err == OK ? C2_OK : C2_NO_MEMORY;
116 }
117
onStop()118 c2_status_t C2SoftOpusDec::onStop() {
119 if (mDecoder) {
120 opus_multistream_decoder_destroy(mDecoder);
121 mDecoder = nullptr;
122 }
123 memset(&mHeader, 0, sizeof(mHeader));
124 mCodecDelay = 0;
125 mSeekPreRoll = 0;
126 mSamplesToDiscard = 0;
127 mInputBufferCount = 0;
128 mSignalledError = false;
129 mSignalledOutputEos = false;
130
131 return C2_OK;
132 }
133
onReset()134 void C2SoftOpusDec::onReset() {
135 (void)onStop();
136 }
137
onRelease()138 void C2SoftOpusDec::onRelease() {
139 if (mDecoder) {
140 opus_multistream_decoder_destroy(mDecoder);
141 mDecoder = nullptr;
142 }
143 }
144
initDecoder()145 status_t C2SoftOpusDec::initDecoder() {
146 memset(&mHeader, 0, sizeof(mHeader));
147 mCodecDelay = 0;
148 mSeekPreRoll = 0;
149 mSamplesToDiscard = 0;
150 mInputBufferCount = 0;
151 mSignalledError = false;
152 mSignalledOutputEos = false;
153
154 return OK;
155 }
156
onFlush_sm()157 c2_status_t C2SoftOpusDec::onFlush_sm() {
158 if (mDecoder) {
159 opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE);
160 mSamplesToDiscard = mSeekPreRoll;
161 mSignalledOutputEos = false;
162 }
163 return C2_OK;
164 }
165
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)166 c2_status_t C2SoftOpusDec::drain(
167 uint32_t drainMode,
168 const std::shared_ptr<C2BlockPool> &pool) {
169 (void) pool;
170 if (drainMode == NO_DRAIN) {
171 ALOGW("drain with NO_DRAIN: no-op");
172 return C2_OK;
173 }
174 if (drainMode == DRAIN_CHAIN) {
175 ALOGW("DRAIN_CHAIN not supported");
176 return C2_OMITTED;
177 }
178
179 return C2_OK;
180 }
181
fillEmptyWork(const std::unique_ptr<C2Work> & work)182 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
183 work->worklets.front()->output.flags = work->input.flags;
184 work->worklets.front()->output.buffers.clear();
185 work->worklets.front()->output.ordinal = work->input.ordinal;
186 work->workletsProcessed = 1u;
187 }
188
189 static const int kRate = 48000;
190
191 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
192 // mappings for up to 8 channels. This information is part of the Vorbis I
193 // Specification:
194 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
195 static const int kMaxChannels = 8;
196
197 // Maximum packet size used in Xiph's opusdec.
198 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
199
200 // Default audio output channel layout. Used to initialize |stream_map| in
201 // OpusHeader, and passed to opus_multistream_decoder_create() when the header
202 // does not contain mapping information. The values are valid only for mono and
203 // stereo output: Opus streams with more than 2 channels require a stream map.
204 static const int kMaxChannelsWithDefaultLayout = 2;
205 static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 };
206
207
208 // Convert nanoseconds to number of samples.
ns_to_samples(uint64_t ns,int rate)209 static uint64_t ns_to_samples(uint64_t ns, int rate) {
210 return static_cast<double>(ns) * rate / 1000000000;
211 }
212
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)213 void C2SoftOpusDec::process(
214 const std::unique_ptr<C2Work> &work,
215 const std::shared_ptr<C2BlockPool> &pool) {
216 // Initialize output work
217 work->result = C2_OK;
218 work->workletsProcessed = 1u;
219 work->worklets.front()->output.configUpdate.clear();
220 work->worklets.front()->output.flags = work->input.flags;
221
222 if (mSignalledError || mSignalledOutputEos) {
223 work->result = C2_BAD_VALUE;
224 return;
225 }
226
227 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
228 size_t inOffset = 0u;
229 size_t inSize = 0u;
230 C2ReadView rView = mDummyReadView;
231 if (!work->input.buffers.empty()) {
232 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
233 inSize = rView.capacity();
234 if (inSize && rView.error()) {
235 ALOGE("read view map failed %d", rView.error());
236 work->result = C2_CORRUPTED;
237 return;
238 }
239 }
240 if (inSize == 0) {
241 fillEmptyWork(work);
242 if (eos) {
243 mSignalledOutputEos = true;
244 ALOGV("signalled EOS");
245 }
246 return;
247 }
248
249 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
250 (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
251 const uint8_t *data = rView.data() + inOffset;
252 if (mInputBufferCount < 3) {
253 if (mInputBufferCount == 0) {
254 size_t opusHeadSize = 0;
255 size_t codecDelayBufSize = 0;
256 size_t seekPreRollBufSize = 0;
257 void *opusHeadBuf = NULL;
258 void *codecDelayBuf = NULL;
259 void *seekPreRollBuf = NULL;
260
261 if (!GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
262 &opusHeadSize, &codecDelayBuf,
263 &codecDelayBufSize, &seekPreRollBuf,
264 &seekPreRollBufSize)) {
265 ALOGE("%s encountered error in GetOpusHeaderBuffers", __func__);
266 mSignalledError = true;
267 work->result = C2_CORRUPTED;
268 return;
269 }
270
271 if (!ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &mHeader)) {
272 ALOGE("%s Encountered error while Parsing Opus Header.", __func__);
273 mSignalledError = true;
274 work->result = C2_CORRUPTED;
275 return;
276 }
277 uint8_t channel_mapping[kMaxChannels] = {0};
278 if (mHeader.channels <= kMaxChannelsWithDefaultLayout) {
279 memcpy(&channel_mapping,
280 kDefaultOpusChannelLayout,
281 kMaxChannelsWithDefaultLayout);
282 } else {
283 memcpy(&channel_mapping,
284 mHeader.stream_map,
285 mHeader.channels);
286 }
287 int status = OPUS_INVALID_STATE;
288 mDecoder = opus_multistream_decoder_create(kRate,
289 mHeader.channels,
290 mHeader.num_streams,
291 mHeader.num_coupled,
292 channel_mapping,
293 &status);
294 if (!mDecoder || status != OPUS_OK) {
295 ALOGE("opus_multistream_decoder_create failed status = %s",
296 opus_strerror(status));
297 mSignalledError = true;
298 work->result = C2_CORRUPTED;
299 return;
300 }
301 status = opus_multistream_decoder_ctl(mDecoder,
302 OPUS_SET_GAIN(mHeader.gain_db));
303 if (status != OPUS_OK) {
304 ALOGE("Failed to set OPUS header gain; status = %s",
305 opus_strerror(status));
306 mSignalledError = true;
307 work->result = C2_CORRUPTED;
308 return;
309 }
310
311 if (codecDelayBuf && codecDelayBufSize == sizeof(uint64_t)) {
312 uint64_t value;
313 memcpy(&value, codecDelayBuf, sizeof(uint64_t));
314 mCodecDelay = ns_to_samples(value, kRate);
315 mSamplesToDiscard = mCodecDelay;
316 ++mInputBufferCount;
317 }
318 if (seekPreRollBuf && seekPreRollBufSize == sizeof(uint64_t)) {
319 uint64_t value;
320 memcpy(&value, seekPreRollBuf, sizeof(uint64_t));
321 mSeekPreRoll = ns_to_samples(value, kRate);
322 ++mInputBufferCount;
323 }
324 } else {
325 if (inSize < 8) {
326 ALOGE("Input sample size is too small.");
327 mSignalledError = true;
328 work->result = C2_CORRUPTED;
329 return;
330 }
331 int64_t samples = ns_to_samples( *(reinterpret_cast<int64_t*>
332 (const_cast<uint8_t *> (data))), kRate);
333 if (mInputBufferCount == 1) {
334 mCodecDelay = samples;
335 mSamplesToDiscard = mCodecDelay;
336 }
337 else {
338 mSeekPreRoll = samples;
339 }
340 }
341
342 ++mInputBufferCount;
343 if (mInputBufferCount == 3) {
344 ALOGI("Configuring decoder: %d Hz, %d channels",
345 kRate, mHeader.channels);
346 C2StreamSampleRateInfo::output sampleRateInfo(0u, kRate);
347 C2StreamChannelCountInfo::output channelCountInfo(0u, mHeader.channels);
348 std::vector<std::unique_ptr<C2SettingResult>> failures;
349 c2_status_t err = mIntf->config(
350 { &sampleRateInfo, &channelCountInfo },
351 C2_MAY_BLOCK,
352 &failures);
353 if (err == OK) {
354 work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(sampleRateInfo));
355 work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(channelCountInfo));
356 } else {
357 ALOGE("Config Update failed");
358 mSignalledError = true;
359 work->result = C2_CORRUPTED;
360 return;
361 }
362 }
363 fillEmptyWork(work);
364 if (eos) {
365 mSignalledOutputEos = true;
366 ALOGV("signalled EOS");
367 }
368 return;
369 }
370
371 // Ignore CSD re-submissions.
372 if ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
373 fillEmptyWork(work);
374 return;
375 }
376
377 // When seeking to zero, |mCodecDelay| samples has to be discarded
378 // instead of |mSeekPreRoll| samples (as we would when seeking to any
379 // other timestamp).
380 if (work->input.ordinal.timestamp.peeku() == 0) mSamplesToDiscard = mCodecDelay;
381
382 std::shared_ptr<C2LinearBlock> block;
383 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
384 c2_status_t err = pool->fetchLinearBlock(
385 kMaxNumSamplesPerBuffer * kMaxChannels * sizeof(int16_t),
386 usage, &block);
387 if (err != C2_OK) {
388 ALOGE("fetchLinearBlock for Output failed with status %d", err);
389 work->result = C2_NO_MEMORY;
390 return;
391 }
392 C2WriteView wView = block->map().get();
393 if (wView.error()) {
394 ALOGE("write view map failed %d", wView.error());
395 work->result = C2_CORRUPTED;
396 return;
397 }
398
399 int numSamples = opus_multistream_decode(mDecoder,
400 data,
401 inSize,
402 reinterpret_cast<int16_t *> (wView.data()),
403 kMaxOpusOutputPacketSizeSamples,
404 0);
405 if (numSamples < 0) {
406 ALOGE("opus_multistream_decode returned numSamples %d", numSamples);
407 numSamples = 0;
408 mSignalledError = true;
409 work->result = C2_CORRUPTED;
410 return;
411 }
412
413 int outOffset = 0;
414 if (mSamplesToDiscard > 0) {
415 if (mSamplesToDiscard > numSamples) {
416 mSamplesToDiscard -= numSamples;
417 numSamples = 0;
418 } else {
419 numSamples -= mSamplesToDiscard;
420 outOffset = mSamplesToDiscard * sizeof(int16_t) * mHeader.channels;
421 mSamplesToDiscard = 0;
422 }
423 }
424
425 if (numSamples) {
426 int outSize = numSamples * sizeof(int16_t) * mHeader.channels;
427 ALOGV("out buffer attr. offset %d size %d ", outOffset, outSize);
428
429 work->worklets.front()->output.flags = work->input.flags;
430 work->worklets.front()->output.buffers.clear();
431 work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, outOffset, outSize));
432 work->worklets.front()->output.ordinal = work->input.ordinal;
433 work->workletsProcessed = 1u;
434 } else {
435 fillEmptyWork(work);
436 block.reset();
437 }
438 if (eos) {
439 mSignalledOutputEos = true;
440 ALOGV("signalled EOS");
441 }
442 }
443
444 class C2SoftOpusDecFactory : public C2ComponentFactory {
445 public:
C2SoftOpusDecFactory()446 C2SoftOpusDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
447 GetCodec2PlatformComponentStore()->getParamReflector())) {
448 }
449
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)450 virtual c2_status_t createComponent(
451 c2_node_id_t id,
452 std::shared_ptr<C2Component>* const component,
453 std::function<void(C2Component*)> deleter) override {
454 *component = std::shared_ptr<C2Component>(
455 new C2SoftOpusDec(COMPONENT_NAME,
456 id,
457 std::make_shared<C2SoftOpusDec::IntfImpl>(mHelper)),
458 deleter);
459 return C2_OK;
460 }
461
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)462 virtual c2_status_t createInterface(
463 c2_node_id_t id,
464 std::shared_ptr<C2ComponentInterface>* const interface,
465 std::function<void(C2ComponentInterface*)> deleter) override {
466 *interface = std::shared_ptr<C2ComponentInterface>(
467 new SimpleInterface<C2SoftOpusDec::IntfImpl>(
468 COMPONENT_NAME, id, std::make_shared<C2SoftOpusDec::IntfImpl>(mHelper)),
469 deleter);
470 return C2_OK;
471 }
472
473 virtual ~C2SoftOpusDecFactory() override = default;
474
475 private:
476 std::shared_ptr<C2ReflectorHelper> mHelper;
477 };
478
479 } // namespace android
480
481 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()482 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
483 ALOGV("in %s", __func__);
484 return new ::android::C2SoftOpusDecFactory();
485 }
486
487 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)488 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
489 ALOGV("in %s", __func__);
490 delete factory;
491 }
492