1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chromecast/media/cma/decoder/external_audio_decoder_wrapper.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/no_destructor.h"
16 #include "base/scoped_native_library.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/time/time.h"
19 #include "chromecast/media/api/decoder_buffer_base.h"
20 #include "media/base/audio_bus.h"
21 #include "media/base/audio_sample_types.h"
22 #include "media/base/decoder_buffer.h"
23
24 namespace chromecast {
25 namespace media {
26
27 namespace {
28
29 const char kDefaultExternalDecoderPath[] = "libcast_external_decoder.so";
30
31 const char kSupportedConfigFunction[] =
32 "ExternalAudioDecoder_IsSupportedConfig";
33 const char kCreateFunction[] = "ExternalAudioDecoder_CreateDecoder";
34 const char kDeleteFunction[] = "ExternalAudioDecoder_DeleteDecoder";
35
36 const size_t kMinConversionBufferSize = 256;
37
38 class ExternalDecoderLib {
39 public:
ExternalDecoderLib()40 ExternalDecoderLib() : lib_(base::FilePath(kDefaultExternalDecoderPath)) {
41 if (lib_.is_valid()) {
42 supported_config_func_ = reinterpret_cast<IsSupportedConfigFunction>(
43 lib_.GetFunctionPointer(kSupportedConfigFunction));
44 create_func_ = reinterpret_cast<CreateFunction>(
45 lib_.GetFunctionPointer(kCreateFunction));
46 delete_func_ = reinterpret_cast<DeleteFunction>(
47 lib_.GetFunctionPointer(kDeleteFunction));
48
49 LOG_IF(ERROR, !supported_config_func_)
50 << "Missing function: " << kSupportedConfigFunction;
51 LOG_IF(ERROR, !create_func_) << "Missing function: " << kCreateFunction;
52 LOG_IF(ERROR, !delete_func_) << "Missing function: " << kDeleteFunction;
53 }
54 }
55
56 ExternalDecoderLib(const ExternalDecoderLib&) = delete;
57 ExternalDecoderLib& operator=(const ExternalDecoderLib&) = delete;
58
59 ~ExternalDecoderLib() = default;
60
IsSupportedConfig(const AudioConfig & config)61 bool IsSupportedConfig(const AudioConfig& config) {
62 if (!supported_config_func_ || !create_func_ || !delete_func_) {
63 return false;
64 }
65
66 return supported_config_func_(config);
67 }
68
CreateDecoder(ExternalAudioDecoder::Delegate * delegate,const chromecast::media::AudioConfig & config)69 ExternalAudioDecoder* CreateDecoder(
70 ExternalAudioDecoder::Delegate* delegate,
71 const chromecast::media::AudioConfig& config) {
72 if (!create_func_ || !delete_func_) {
73 return nullptr;
74 }
75
76 return create_func_(delegate, config);
77 }
78
DeleteDecoder(ExternalAudioDecoder * decoder)79 void DeleteDecoder(ExternalAudioDecoder* decoder) {
80 DCHECK(delete_func_);
81 delete_func_(decoder);
82 }
83
84 private:
85 using IsSupportedConfigFunction =
86 decltype(&ExternalAudioDecoder_IsSupportedConfig);
87 using CreateFunction = decltype(&ExternalAudioDecoder_CreateDecoder);
88 using DeleteFunction = decltype(&ExternalAudioDecoder_DeleteDecoder);
89
90 base::ScopedNativeLibrary lib_;
91 IsSupportedConfigFunction supported_config_func_ = nullptr;
92 CreateFunction create_func_ = nullptr;
93 DeleteFunction delete_func_ = nullptr;
94 };
95
GetLib()96 ExternalDecoderLib& GetLib() {
97 static base::NoDestructor<ExternalDecoderLib> g_lib;
98 return *g_lib;
99 }
100
BuildOutputConfig(const AudioConfig & input_config,CastAudioDecoder::OutputFormat output_format,ExternalAudioDecoder * decoder)101 AudioConfig BuildOutputConfig(const AudioConfig& input_config,
102 CastAudioDecoder::OutputFormat output_format,
103 ExternalAudioDecoder* decoder) {
104 AudioConfig output_config = input_config;
105 output_config.encryption_scheme = EncryptionScheme::kUnencrypted;
106 output_config.codec = kCodecPCM;
107 output_config.sample_format =
108 (output_format == CastAudioDecoder::kOutputSigned16
109 ? kSampleFormatS16
110 : kSampleFormatPlanarF32);
111 output_config.channel_number = decoder->GetNumOutputChannels();
112 if (output_config.channel_number <= 0) {
113 output_config.channel_number = input_config.channel_number;
114 }
115 return output_config;
116 }
117
118 } // namespace
119
120 class ExternalAudioDecoderWrapper::DecodedBuffer : public DecoderBufferBase {
121 public:
DecodedBuffer(StreamId stream_id,size_t capacity)122 DecodedBuffer(StreamId stream_id, size_t capacity)
123 : stream_id_(stream_id),
124 capacity_(capacity),
125 data_(std::make_unique<uint8_t[]>(capacity_)) {}
126
set_size(size_t size)127 void set_size(size_t size) {
128 DCHECK_LE(size, capacity_);
129 size_ = size;
130 }
131
132 // DecoderBufferBase implementation:
stream_id() const133 StreamId stream_id() const override { return stream_id_; }
timestamp() const134 int64_t timestamp() const override { return timestamp_.InMicroseconds(); }
set_timestamp(base::TimeDelta timestamp)135 void set_timestamp(base::TimeDelta timestamp) override {
136 timestamp_ = timestamp;
137 }
data() const138 const uint8_t* data() const override { return data_.get(); }
writable_data() const139 uint8_t* writable_data() const override { return data_.get(); }
data_size() const140 size_t data_size() const override { return size_; }
decrypt_config() const141 const CastDecryptConfig* decrypt_config() const override { return nullptr; }
end_of_stream() const142 bool end_of_stream() const override { return false; }
143
144 private:
145 ~DecodedBuffer() override = default;
146
147 const StreamId stream_id_;
148 const size_t capacity_;
149
150 const std::unique_ptr<uint8_t[]> data_;
151
152 base::TimeDelta timestamp_;
153 size_t size_ = 0;
154 };
155
156 // static
IsSupportedConfig(const AudioConfig & config)157 bool ExternalAudioDecoderWrapper::IsSupportedConfig(const AudioConfig& config) {
158 return GetLib().IsSupportedConfig(config);
159 }
160
ExternalAudioDecoderWrapper(scoped_refptr<base::SequencedTaskRunner> task_runner,const AudioConfig & config,CastAudioDecoder::OutputFormat output_format)161 ExternalAudioDecoderWrapper::ExternalAudioDecoderWrapper(
162 scoped_refptr<base::SequencedTaskRunner> task_runner,
163 const AudioConfig& config,
164 CastAudioDecoder::OutputFormat output_format)
165 : task_runner_(std::move(task_runner)),
166 output_format_(output_format),
167 decoder_(GetLib().CreateDecoder(this, config)),
168 output_config_(BuildOutputConfig(config, output_format_, decoder_)) {}
169
~ExternalAudioDecoderWrapper()170 ExternalAudioDecoderWrapper::~ExternalAudioDecoderWrapper() {
171 if (decoder_) {
172 GetLib().DeleteDecoder(decoder_);
173 }
174 }
175
GetOutputConfig() const176 const AudioConfig& ExternalAudioDecoderWrapper::GetOutputConfig() const {
177 return output_config_;
178 }
179
Decode(scoped_refptr<media::DecoderBufferBase> data,DecodeCallback decode_callback)180 void ExternalAudioDecoderWrapper::Decode(
181 scoped_refptr<media::DecoderBufferBase> data,
182 DecodeCallback decode_callback) {
183 DCHECK(task_runner_->RunsTasksInCurrentSequence());
184 // Post a task, since some callers don't expect a synchronous callback.
185 task_runner_->PostTask(
186 FROM_HERE, base::BindOnce(&ExternalAudioDecoderWrapper::DecodeDeferred,
187 weak_factory_.GetWeakPtr(), std::move(data),
188 std::move(decode_callback)));
189 }
190
DecodeDeferred(scoped_refptr<media::DecoderBufferBase> data,DecodeCallback decode_callback)191 void ExternalAudioDecoderWrapper::DecodeDeferred(
192 scoped_refptr<media::DecoderBufferBase> data,
193 DecodeCallback decode_callback) {
194 if (data->end_of_stream()) {
195 std::move(decode_callback).Run(kDecodeOk, output_config_, std::move(data));
196 return;
197 }
198
199 if (!decoder_ || !decoder_->Decode(*data)) {
200 std::move(decode_callback).Run(kDecodeError, output_config_, nullptr);
201 return;
202 }
203
204 size_t buffer_count = buffers_.size() - pending_buffer_;
205 scoped_refptr<DecodedBuffer> decoded;
206 if (buffer_count == 0) {
207 decoded = base::MakeRefCounted<DecodedBuffer>(output_config_.id, 0);
208 } else if (buffer_count == 1) {
209 decoded = std::move(buffers_.front());
210 } else {
211 size_t size = 0;
212 for (size_t i = 0; i < buffer_count; ++i) {
213 size += buffers_[i]->data_size();
214 }
215
216 decoded = base::MakeRefCounted<DecodedBuffer>(output_config_.id, size);
217 decoded->set_size(size);
218
219 const size_t frame_size = sizeof(float) * output_config_.channel_number;
220 size_t total_frames = size / frame_size;
221 for (int c = 0; c < output_config_.channel_number; ++c) {
222 uint8_t* dest =
223 decoded->writable_data() + c * total_frames * sizeof(float);
224 for (size_t i = 0; i < buffer_count; ++i) {
225 size_t frames = buffers_[i]->data_size() / frame_size;
226 void* src = buffers_[i]->writable_data() + c * frames * sizeof(float);
227 memcpy(dest, src, frames * sizeof(float));
228 dest += frames * sizeof(float);
229 }
230 }
231 }
232
233 buffers_.erase(buffers_.begin(), buffers_.begin() + buffer_count);
234
235 if (output_format_ == CastAudioDecoder::kOutputSigned16) {
236 ConvertToS16(decoded.get());
237 }
238
239 decoded->set_timestamp(base::TimeDelta::FromMicroseconds(data->timestamp()));
240 std::move(decode_callback).Run(kDecodeOk, output_config_, std::move(decoded));
241 }
242
ConvertToS16(DecodedBuffer * buffer)243 void ExternalAudioDecoderWrapper::ConvertToS16(DecodedBuffer* buffer) {
244 const int channels = output_config_.channel_number;
245 const size_t frame_size = sizeof(float) * channels;
246 const size_t frames = buffer->data_size() / frame_size;
247
248 if (!conversion_buffer_ ||
249 conversion_buffer_->frames() < static_cast<int>(frames) ||
250 conversion_buffer_->channels() != channels) {
251 conversion_buffer_ = ::media::AudioBus::Create(
252 channels, std::max(frames * 2, kMinConversionBufferSize));
253 }
254
255 const float* src = reinterpret_cast<const float*>(buffer->data());
256 for (int c = 0; c < channels; ++c) {
257 std::copy_n(src + c * frames, frames, conversion_buffer_->channel(c));
258 }
259
260 int16_t* dest = reinterpret_cast<int16_t*>(buffer->writable_data());
261 conversion_buffer_
262 ->ToInterleavedPartial<::media::SignedInt16SampleTypeTraits>(0, frames,
263 dest);
264
265 buffer->set_size(frames * channels * sizeof(int16_t));
266 }
267
AllocateBuffer(size_t bytes)268 void* ExternalAudioDecoderWrapper::AllocateBuffer(size_t bytes) {
269 auto buffer = base::MakeRefCounted<DecodedBuffer>(output_config_.id, bytes);
270 void* ptr = buffer->writable_data();
271 buffers_.push_back(std::move(buffer));
272 pending_buffer_ = true;
273 return ptr;
274 }
275
OnDecodedBuffer(size_t decoded_size_bytes,const AudioConfig & config)276 void ExternalAudioDecoderWrapper::OnDecodedBuffer(size_t decoded_size_bytes,
277 const AudioConfig& config) {
278 DCHECK(!buffers_.empty());
279 size_t frame_size = sizeof(float) * config.channel_number;
280 DCHECK_EQ(decoded_size_bytes % frame_size, 0u);
281
282 buffers_.back()->set_size(decoded_size_bytes);
283 output_config_.channel_number = config.channel_number;
284 output_config_.samples_per_second = config.samples_per_second;
285 pending_buffer_ = false;
286 }
287
288 } // namespace media
289 } // namespace chromecast
290