• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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