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