#include "media/base/decoder_buffer.h"
#include <sstream>
#include <variant>
#include "base/containers/heap_array.h"
#include "base/debug/alias.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/stringprintf.h"
#include "base/types/pass_key.h"
#include "media/base/subsample_entry.h"
namespace media {
namespace {
template <class T>
class ExternalSharedMemoryAdapter : public DecoderBuffer::ExternalMemory {
public:
explicit ExternalSharedMemoryAdapter(T mapping)
: mapping_(std::move(mapping)) {}
const base::span<const uint8_t> Span() const override {
return mapping_.template GetMemoryAsSpan<const uint8_t>();
}
private:
T mapping_;
};
}
DecoderBuffer::DecoderBuffer(size_t size)
: data_(base::HeapArray<uint8_t>::Uninit(size)) {}
DecoderBuffer::DecoderBuffer(base::span<const uint8_t> data)
: data_(base::HeapArray<uint8_t>::CopiedFrom(data)) {}
DecoderBuffer::DecoderBuffer(base::HeapArray<uint8_t> data)
: data_(std::move(data)) {}
DecoderBuffer::DecoderBuffer(std::unique_ptr<ExternalMemory> external_memory)
: external_memory_(std::move(external_memory)) {}
DecoderBuffer::DecoderBuffer(DecoderBufferType decoder_buffer_type,
std::optional<ConfigVariant> next_config)
: is_end_of_stream_(decoder_buffer_type ==
DecoderBufferType::kEndOfStream) {
if (next_config) {
DCHECK(end_of_stream());
side_data_ = std::make_unique<DecoderBufferSideData>();
side_data_->next_config = std::move(next_config);
}
}
DecoderBuffer::DecoderBuffer(base::PassKey<DecoderBuffer>,
base::span<const uint8_t> data)
: DecoderBuffer(std::move(data)) {}
DecoderBuffer::DecoderBuffer(base::PassKey<DecoderBuffer>,
base::HeapArray<uint8_t> data)
: DecoderBuffer(std::move(data)) {}
DecoderBuffer::DecoderBuffer(base::PassKey<DecoderBuffer>,
std::unique_ptr<ExternalMemory> external_memory)
: DecoderBuffer(std::move(external_memory)) {}
DecoderBuffer::DecoderBuffer(base::PassKey<DecoderBuffer>,
DecoderBufferType decoder_buffer_type,
std::optional<ConfigVariant> next_config)
: DecoderBuffer(decoder_buffer_type, std::move(next_config)) {}
DecoderBuffer::~DecoderBuffer() = default;
scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(
base::span<const uint8_t> data) {
return base::MakeRefCounted<DecoderBuffer>(base::PassKey<DecoderBuffer>(),
data);
}
scoped_refptr<DecoderBuffer> DecoderBuffer::FromArray(
base::HeapArray<uint8_t> data) {
return base::MakeRefCounted<DecoderBuffer>(base::PassKey<DecoderBuffer>(),
std::move(data));
}
scoped_refptr<DecoderBuffer> DecoderBuffer::FromSharedMemoryRegion(
base::UnsafeSharedMemoryRegion region,
uint64_t offset,
size_t size) {
if (size == 0) {
return nullptr;
}
auto mapping = region.MapAt(offset, size);
if (!mapping.IsValid()) {
return nullptr;
}
return FromExternalMemory(
std::make_unique<
ExternalSharedMemoryAdapter<base::WritableSharedMemoryMapping>>(
std::move(mapping)));
}
scoped_refptr<DecoderBuffer> DecoderBuffer::FromSharedMemoryRegion(
base::ReadOnlySharedMemoryRegion region,
uint64_t offset,
size_t size) {
if (size == 0) {
return nullptr;
}
auto mapping = region.MapAt(offset, size);
if (!mapping.IsValid()) {
return nullptr;
}
return FromExternalMemory(
std::make_unique<
ExternalSharedMemoryAdapter<base::ReadOnlySharedMemoryMapping>>(
std::move(mapping)));
}
scoped_refptr<DecoderBuffer> DecoderBuffer::FromExternalMemory(
std::unique_ptr<ExternalMemory> external_memory) {
DCHECK(external_memory);
if (external_memory->Span().empty()) {
return nullptr;
}
return base::MakeRefCounted<DecoderBuffer>(base::PassKey<DecoderBuffer>(),
std::move(external_memory));
}
scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer(
std::optional<ConfigVariant> next_config) {
return base::MakeRefCounted<DecoderBuffer>(base::PassKey<DecoderBuffer>(),
DecoderBufferType::kEndOfStream,
std::move(next_config));
}
bool DecoderBuffer::DoSubsamplesMatch(const DecoderBuffer& buffer) {
if (buffer.end_of_stream()) {
return true;
}
if (!buffer.is_encrypted()) {
return true;
}
const auto& subsamples = buffer.decrypt_config()->subsamples();
if (subsamples.empty()) {
return true;
}
return VerifySubsamplesMatchSize(subsamples, buffer.size());
}
void DecoderBuffer::set_discard_padding(const DiscardPadding& discard_padding) {
DCHECK(!end_of_stream());
if (!side_data_ && discard_padding == DiscardPadding()) {
return;
}
WritableSideData().discard_padding = discard_padding;
}
DecoderBufferSideData& DecoderBuffer::WritableSideData() {
DCHECK(!end_of_stream());
if (!side_data()) {
side_data_ = std::make_unique<DecoderBufferSideData>();
}
return *side_data_;
}
void DecoderBuffer::set_side_data(
std::unique_ptr<DecoderBufferSideData> side_data) {
DCHECK(!end_of_stream());
side_data_ = std::move(side_data);
}
bool DecoderBuffer::MatchesMetadataForTesting(
const DecoderBuffer& buffer) const {
if (end_of_stream() != buffer.end_of_stream()) {
return false;
}
if (side_data_ && !side_data_->Matches(*buffer.side_data_)) {
return false;
}
if (end_of_stream()) {
return true;
}
if (timestamp() != buffer.timestamp() || duration() != buffer.duration() ||
is_key_frame() != buffer.is_key_frame()) {
return false;
}
if ((decrypt_config() == nullptr) != (buffer.decrypt_config() == nullptr))
return false;
return decrypt_config() ? decrypt_config()->Matches(*buffer.decrypt_config())
: true;
}
bool DecoderBuffer::MatchesForTesting(const DecoderBuffer& buffer) const {
if (!MatchesMetadataForTesting(buffer))
return false;
if (end_of_stream())
return true;
DCHECK(!buffer.end_of_stream());
return base::span(*this) == base::span(buffer);
}
std::string DecoderBuffer::AsHumanReadableString(bool verbose) const {
if (end_of_stream()) {
if (!next_config()) {
return "EOS";
}
std::string config;
const auto nc = next_config().value();
if (const auto* ac = std::get_if<media::AudioDecoderConfig>(&nc)) {
config = ac->AsHumanReadableString();
} else {
config = std::get<media::VideoDecoderConfig>(nc).AsHumanReadableString();
}
return base::StringPrintf("EOS config=(%s)", config.c_str());
}
std::ostringstream s;
s << "{timestamp=" << timestamp_.InMicroseconds()
<< " duration=" << duration_.InMicroseconds() << " size=" << size()
<< " is_key_frame=" << is_key_frame_
<< " encrypted=" << (decrypt_config_ != nullptr);
if (verbose) {
s << " side_data=" << !!side_data();
if (side_data()) {
s << " discard_padding (us)=("
<< side_data_->discard_padding.first.InMicroseconds() << ", "
<< side_data_->discard_padding.second.InMicroseconds() << ")";
}
if (decrypt_config_) {
s << " decrypt_config=" << (*decrypt_config_);
}
}
s << "}";
return s.str();
}
void DecoderBuffer::set_timestamp(base::TimeDelta timestamp) {
DCHECK(!end_of_stream());
timestamp_ = timestamp;
}
size_t DecoderBuffer::GetMemoryUsage() const {
size_t memory_usage = sizeof(DecoderBuffer);
if (end_of_stream()) {
return memory_usage;
}
memory_usage += size();
if (side_data()) {
memory_usage += sizeof(decltype(side_data_->spatial_layers)::value_type) *
side_data_->spatial_layers.capacity();
memory_usage += side_data_->alpha_data.size();
}
if (decrypt_config_) {
memory_usage += sizeof(DecryptConfig);
memory_usage += decrypt_config_->key_id().capacity();
memory_usage += decrypt_config_->iv().capacity();
memory_usage +=
sizeof(SubsampleEntry) * decrypt_config_->subsamples().capacity();
}
return memory_usage;
}
}