blob: 0ac7a17bd5246b6e9728d3048901118616ed6581 [file] [log] [blame]
Andrew Top6f0aefd2018-08-15 16:02:40 -07001// Copyright 2018 The Cobalt Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "starboard/shared/opus/opus_audio_decoder.h"
16
Chad Duffinac9ac062019-07-23 10:06:45 -070017#include "starboard/common/log.h"
18#include "starboard/common/string.h"
Andrew Top6f0aefd2018-08-15 16:02:40 -070019#include "starboard/memory.h"
20#include "starboard/shared/starboard/media/media_util.h"
Andrew Top6f0aefd2018-08-15 16:02:40 -070021
22namespace starboard {
23namespace shared {
24namespace opus {
25
26namespace {
Andrew Topcab77702019-09-17 13:14:36 -070027
28typedef struct {
29 int nb_streams;
30 int nb_coupled_streams;
31 unsigned char mapping[8];
32} VorbisLayout;
33
34/* Index is nb_channel-1 */
35static const VorbisLayout vorbis_mappings[8] = {
36 {1, 0, {0}}, /* 1: mono */
37 {1, 1, {0, 1}}, /* 2: stereo */
38 {2, 1, {0, 2, 1}}, /* 3: 1-d surround */
39 {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */
40 {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */
41 {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */
42 {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */
43 {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
44};
45
Andrew Top6f0aefd2018-08-15 16:02:40 -070046} // namespace
47
Chad Duffinac9ac062019-07-23 10:06:45 -070048OpusAudioDecoder::OpusAudioDecoder(
49 const SbMediaAudioSampleInfo& audio_sample_info)
50 : audio_sample_info_(audio_sample_info) {
Andrew Top6f0aefd2018-08-15 16:02:40 -070051 int error;
Andrew Topcab77702019-09-17 13:14:36 -070052 int channels = audio_sample_info_.number_of_channels;
53 if (channels > 8 || channels < 1) {
54 SB_LOG(ERROR) << "Can't create decoder with " << channels << " channels";
55 return;
56 }
57
58 decoder_ = opus_multistream_decoder_create(
59 audio_sample_info_.samples_per_second, channels,
60 vorbis_mappings[channels - 1].nb_streams,
61 vorbis_mappings[channels - 1].nb_coupled_streams,
62 vorbis_mappings[channels - 1].mapping, &error);
Andrew Top6f0aefd2018-08-15 16:02:40 -070063 if (error != OPUS_OK) {
64 SB_LOG(ERROR) << "Failed to create decoder with error: "
65 << opus_strerror(error);
66 decoder_ = NULL;
67 return;
68 }
69 SB_DCHECK(decoder_ != NULL);
70}
71
72OpusAudioDecoder::~OpusAudioDecoder() {
73 if (decoder_) {
Andrew Topcab77702019-09-17 13:14:36 -070074 opus_multistream_decoder_destroy(decoder_);
Andrew Top6f0aefd2018-08-15 16:02:40 -070075 }
76}
77
78void OpusAudioDecoder::Initialize(const OutputCB& output_cb,
79 const ErrorCB& error_cb) {
80 SB_DCHECK(BelongsToCurrentThread());
81 SB_DCHECK(output_cb);
82 SB_DCHECK(!output_cb_);
83 SB_DCHECK(error_cb);
84 SB_DCHECK(!error_cb_);
85
86 output_cb_ = output_cb;
87 error_cb_ = error_cb;
88}
89
90void OpusAudioDecoder::Decode(const scoped_refptr<InputBuffer>& input_buffer,
91 const ConsumedCB& consumed_cb) {
92 SB_DCHECK(BelongsToCurrentThread());
93 SB_DCHECK(input_buffer);
94 SB_DCHECK(output_cb_);
95
Andrew Top6f0aefd2018-08-15 16:02:40 -070096 if (stream_ended_) {
97 SB_LOG(ERROR) << "Decode() is called after WriteEndOfStream() is called.";
98 return;
99 }
100
Andrew Topa7b1cfa2019-12-18 19:15:07 -0800101 scoped_refptr<DecodedAudio> decoded_audio = new DecodedAudio(
102 audio_sample_info_.number_of_channels, GetSampleType(),
103 kSbMediaAudioFrameStorageTypeInterleaved, input_buffer->timestamp(),
104 audio_sample_info_.number_of_channels * frames_per_au_ *
105 starboard::media::GetBytesPerSample(GetSampleType()));
106
Andrew Top6f0aefd2018-08-15 16:02:40 -0700107#if SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
Andrew Topcab77702019-09-17 13:14:36 -0700108 const char kDecodeFunctionName[] = "opus_multistream_decode";
109 int decoded_frames = opus_multistream_decode(
Andrew Top6f0aefd2018-08-15 16:02:40 -0700110 decoder_, static_cast<const unsigned char*>(input_buffer->data()),
111 input_buffer->size(),
Andrew Topa7b1cfa2019-12-18 19:15:07 -0800112 reinterpret_cast<opus_int16*>(decoded_audio->buffer()), frames_per_au_,
113 0);
Andrew Top6f0aefd2018-08-15 16:02:40 -0700114#else // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
Andrew Topcab77702019-09-17 13:14:36 -0700115 const char kDecodeFunctionName[] = "opus_multistream_decode_float";
116 int decoded_frames = opus_multistream_decode_float(
Andrew Top6f0aefd2018-08-15 16:02:40 -0700117 decoder_, static_cast<const unsigned char*>(input_buffer->data()),
Andrew Topa7b1cfa2019-12-18 19:15:07 -0800118 input_buffer->size(), reinterpret_cast<float*>(decoded_audio->buffer()),
119 frames_per_au_, 0);
Andrew Top6f0aefd2018-08-15 16:02:40 -0700120#endif // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
Andrew Topa7b1cfa2019-12-18 19:15:07 -0800121 if (decoded_frames == OPUS_BUFFER_TOO_SMALL &&
122 frames_per_au_ < kMaxOpusFramesPerAU) {
123 frames_per_au_ = kMaxOpusFramesPerAU;
124 // Send to decode again with the new |frames_per_au_|.
125 Decode(input_buffer, consumed_cb);
126 return;
127 }
Andrew Top6f0aefd2018-08-15 16:02:40 -0700128 if (decoded_frames <= 0) {
Andrew Topa7b1cfa2019-12-18 19:15:07 -0800129 // When the following check fails, it indicates that |frames_per_au_| is
130 // greater than or equal to |kMaxOpusFramesPerAU|, which should never happen
131 // for Opus.
132 SB_DCHECK(decoded_frames != OPUS_BUFFER_TOO_SMALL);
133
Andrew Top6f0aefd2018-08-15 16:02:40 -0700134 // TODO: Consider fill it with silence.
135 SB_LOG(ERROR) << kDecodeFunctionName
136 << "() failed with error code: " << decoded_frames;
137 error_cb_(kSbPlayerErrorDecode,
138 FormatString("%s() failed with error code: %d",
139 kDecodeFunctionName, decoded_frames));
140 return;
141 }
142
Andrew Topa7b1cfa2019-12-18 19:15:07 -0800143 frames_per_au_ = decoded_frames;
144 decoded_audio->ShrinkTo(audio_sample_info_.number_of_channels *
145 frames_per_au_ *
146 starboard::media::GetBytesPerSample(GetSampleType()));
147
Andrew Top6f0aefd2018-08-15 16:02:40 -0700148 decoded_audios_.push(decoded_audio);
Andrew Topa7b1cfa2019-12-18 19:15:07 -0800149 Schedule(consumed_cb);
Andrew Top6f0aefd2018-08-15 16:02:40 -0700150 Schedule(output_cb_);
151}
152
153void OpusAudioDecoder::WriteEndOfStream() {
154 SB_DCHECK(BelongsToCurrentThread());
155 SB_DCHECK(output_cb_);
156
157 // Opus has no dependent frames so we needn't flush the decoder. Set the
158 // flag to ensure that Decode() is not called when the stream is ended.
159 stream_ended_ = true;
160 // Put EOS into the queue.
161 decoded_audios_.push(new DecodedAudio);
162
163 Schedule(output_cb_);
164}
165
Andrew Top63c7ad42019-11-25 16:10:13 -0800166scoped_refptr<OpusAudioDecoder::DecodedAudio> OpusAudioDecoder::Read(
167 int* samples_per_second) {
Andrew Top6f0aefd2018-08-15 16:02:40 -0700168 SB_DCHECK(BelongsToCurrentThread());
169 SB_DCHECK(output_cb_);
170 SB_DCHECK(!decoded_audios_.empty());
171
172 scoped_refptr<DecodedAudio> result;
173 if (!decoded_audios_.empty()) {
174 result = decoded_audios_.front();
175 decoded_audios_.pop();
176 }
Andrew Top63c7ad42019-11-25 16:10:13 -0800177 *samples_per_second = audio_sample_info_.samples_per_second;
Andrew Top6f0aefd2018-08-15 16:02:40 -0700178 return result;
179}
180
181void OpusAudioDecoder::Reset() {
182 SB_DCHECK(BelongsToCurrentThread());
183
184 stream_ended_ = false;
185 while (!decoded_audios_.empty()) {
186 decoded_audios_.pop();
187 }
Andrew Top286dd782018-10-02 16:52:45 -0700188
189 CancelPendingJobs();
Andrew Top6f0aefd2018-08-15 16:02:40 -0700190}
191
192bool OpusAudioDecoder::is_valid() const {
193 return decoder_ != NULL;
194}
195
196SbMediaAudioSampleType OpusAudioDecoder::GetSampleType() const {
197 SB_DCHECK(BelongsToCurrentThread());
198#if SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
199 return kSbMediaAudioSampleTypeInt16;
200#else // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
201 return kSbMediaAudioSampleTypeFloat32;
202#endif // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES)
203}
204
Andrew Top6f0aefd2018-08-15 16:02:40 -0700205} // namespace opus
206} // namespace shared
207} // namespace starboard