1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/passthrough_dts_audio_decoder.h"
7 #include "base/task/bind_post_task.h"
8 #include "base/task/sequenced_task_runner.h"
9 #include "media/base/audio_buffer.h"
10 #include "media/formats/dts/dts_util.h"
14 PassthroughDTSAudioDecoder::PassthroughDTSAudioDecoder(
15 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
17 : task_runner_(task_runner),
18 media_log_(media_log),
19 pool_(base::MakeRefCounted<AudioBufferMemoryPool>()) {
20 DETACH_FROM_SEQUENCE(sequence_checker_);
23 PassthroughDTSAudioDecoder::~PassthroughDTSAudioDecoder() {
24 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
27 AudioDecoderType PassthroughDTSAudioDecoder::GetDecoderType() const {
28 return AudioDecoderType::kPassthroughDTS;
31 void PassthroughDTSAudioDecoder::Initialize(const AudioDecoderConfig& config,
32 CdmContext* /* cdm_context */,
34 const OutputCB& output_cb,
35 const WaitingCB& /* waiting_cb */) {
36 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
37 DCHECK(config.IsValidConfig());
38 InitCB bound_init_cb = base::BindPostTaskToCurrentDefault(std::move(init_cb));
39 if (config.is_encrypted()) {
40 std::move(bound_init_cb)
41 .Run(DecoderStatus(DecoderStatus::Codes::kUnsupportedEncryptionMode,
42 "PassthroughDTSAudioDecoder does not support "
43 "encrypted content"));
47 if (config.target_output_sample_format() != kSampleFormatDts) {
48 std::move(bound_init_cb)
50 DecoderStatus(DecoderStatus::Codes::kUnsupportedConfig,
51 "PassthroughDTSAudioDecoder does not support codec"));
57 output_cb_ = base::BindPostTaskToCurrentDefault(output_cb);
58 std::move(bound_init_cb).Run(OkStatus());
61 void PassthroughDTSAudioDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
63 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
65 DecodeCB decode_cb_bound =
66 base::BindPostTaskToCurrentDefault(std::move(decode_cb));
68 if (buffer->end_of_stream()) {
69 std::move(decode_cb_bound).Run(DecoderStatus::Codes::kOk);
73 ProcessBuffer(*buffer, std::move(decode_cb_bound));
76 void PassthroughDTSAudioDecoder::Reset(base::OnceClosure closure) {
77 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
79 task_runner_->PostTask(FROM_HERE, std::move(closure));
82 void PassthroughDTSAudioDecoder::ProcessBuffer(const DecoderBuffer& buffer,
84 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
86 // Make sure we are notified if http://crbug.com/49709 returns. Issue also
87 // occurs with some damaged files.
88 if (!buffer.end_of_stream() && buffer.timestamp() == kNoTimestamp) {
89 DVLOG(1) << "Received a buffer without timestamps!";
90 std::move(decode_cb).Run(DecoderStatus::Codes::kFailed);
93 EncapsulateFrame(buffer);
95 std::move(decode_cb).Run(DecoderStatus::Codes::kOk);
98 void PassthroughDTSAudioDecoder::EncapsulateFrame(const DecoderBuffer& buffer) {
99 if (config_.target_output_sample_format() != kSampleFormatDts)
101 const size_t samples_per_frame = dts::GetDTSSamplesPerFrame(config_.codec());
102 const size_t dts_frame_size = 2 * 2 * samples_per_frame;
103 std::vector<uint8_t> output_buffer(dts_frame_size);
105 // Encapsulated a compressed DTS frame per IEC61937
106 base::span<const uint8_t> input_data;
107 input_data = base::span<const uint8_t>(buffer.data(), buffer.data_size());
108 dts::WrapDTSWithIEC61937(input_data, output_buffer, config_.codec());
110 // Create a mono channel "buffer" to hold IEC encapsulated bitstream
111 uint8_t* output_channels[1] = {output_buffer.data()};
112 scoped_refptr<AudioBuffer> output = AudioBuffer::CopyBitstreamFrom(
113 kSampleFormatIECDts, CHANNEL_LAYOUT_MONO, 1, config_.samples_per_second(),
114 samples_per_frame, output_channels, dts_frame_size, buffer.timestamp());
115 output_cb_.Run(output);