blob: 14c31ca50ca4b375659691ed79596a2f2ed3c4ba [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/filters/passthrough_dts_audio_decoder.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "media/base/audio_buffer.h"
#include "media/formats/dts/dts_util.h"
namespace media {
PassthroughDTSAudioDecoder::PassthroughDTSAudioDecoder(
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
MediaLog* media_log)
: task_runner_(task_runner),
media_log_(media_log),
pool_(base::MakeRefCounted<AudioBufferMemoryPool>()) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
PassthroughDTSAudioDecoder::~PassthroughDTSAudioDecoder() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
AudioDecoderType PassthroughDTSAudioDecoder::GetDecoderType() const {
return AudioDecoderType::kPassthroughDTS;
}
void PassthroughDTSAudioDecoder::Initialize(const AudioDecoderConfig& config,
CdmContext* /* cdm_context */,
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& /* waiting_cb */) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(config.IsValidConfig());
InitCB bound_init_cb = base::BindPostTaskToCurrentDefault(std::move(init_cb));
if (config.is_encrypted()) {
std::move(bound_init_cb)
.Run(DecoderStatus(DecoderStatus::Codes::kUnsupportedEncryptionMode,
"PassthroughDTSAudioDecoder does not support "
"encrypted content"));
return;
}
if (config.target_output_sample_format() != kSampleFormatDts) {
std::move(bound_init_cb)
.Run(
DecoderStatus(DecoderStatus::Codes::kUnsupportedConfig,
"PassthroughDTSAudioDecoder does not support codec"));
return;
}
// Success!
config_ = config;
output_cb_ = base::BindPostTaskToCurrentDefault(output_cb);
std::move(bound_init_cb).Run(OkStatus());
}
void PassthroughDTSAudioDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
DecodeCB decode_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(decode_cb);
DecodeCB decode_cb_bound =
base::BindPostTaskToCurrentDefault(std::move(decode_cb));
if (buffer->end_of_stream()) {
std::move(decode_cb_bound).Run(DecoderStatus::Codes::kOk);
return;
}
ProcessBuffer(*buffer, std::move(decode_cb_bound));
}
void PassthroughDTSAudioDecoder::Reset(base::OnceClosure closure) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
task_runner_->PostTask(FROM_HERE, std::move(closure));
}
void PassthroughDTSAudioDecoder::ProcessBuffer(const DecoderBuffer& buffer,
DecodeCB decode_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Make sure we are notified if http://crbug.com/49709 returns. Issue also
// occurs with some damaged files.
if (!buffer.end_of_stream() && buffer.timestamp() == kNoTimestamp) {
DVLOG(1) << "Received a buffer without timestamps!";
std::move(decode_cb).Run(DecoderStatus::Codes::kFailed);
return;
}
EncapsulateFrame(buffer);
std::move(decode_cb).Run(DecoderStatus::Codes::kOk);
}
void PassthroughDTSAudioDecoder::EncapsulateFrame(const DecoderBuffer& buffer) {
if (config_.target_output_sample_format() != kSampleFormatDts)
return;
const size_t samples_per_frame = dts::GetDTSSamplesPerFrame(config_.codec());
const size_t dts_frame_size = 2 * 2 * samples_per_frame;
std::vector<uint8_t> output_buffer(dts_frame_size);
// Encapsulated a compressed DTS frame per IEC61937
base::span<const uint8_t> input_data;
input_data = base::span<const uint8_t>(buffer.data(), buffer.data_size());
dts::WrapDTSWithIEC61937(input_data, output_buffer, config_.codec());
// Create a mono channel "buffer" to hold IEC encapsulated bitstream
uint8_t* output_channels[1] = {output_buffer.data()};
scoped_refptr<AudioBuffer> output = AudioBuffer::CopyBitstreamFrom(
kSampleFormatIECDts, CHANNEL_LAYOUT_MONO, 1, config_.samples_per_second(),
samples_per_frame, output_channels, dts_frame_size, buffer.timestamp());
output_cb_.Run(output);
}
} // namespace media