#include "media/gpu/chromeos/vd_video_decode_accelerator.h"
#include <memory>
#include <vector>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/not_fatal_until.h"
#include "base/task/sequenced_task_runner.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "media/base/format_utils.h"
#include "media/base/video_color_space.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "media/base/video_frame_metadata.h"
#include "media/base/video_transformation.h"
#include "media/base/video_types.h"
#include "media/base/waiting.h"
#include "media/gpu/buffer_validation.h"
#include "media/gpu/chromeos/gpu_buffer_layout.h"
#include "media/gpu/chromeos/native_pixmap_frame_resource.h"
#include "media/gpu/chromeos/platform_video_frame_utils.h"
#include "media/gpu/macros.h"
#include "media/media_buildflags.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gl/gl_bindings.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h"
#include "media/gpu/chromeos/secure_buffer.pb.h"
#include "third_party/cros_system_api/constants/cdm_oemcrypto.h"
#endif
namespace media {
namespace {
base::TimeDelta BitstreamIdToFakeTimestamp(int32_t bitstream_id) { … }
int32_t FakeTimestampToBitstreamId(base::TimeDelta timestamp) { … }
std::vector<ColorPlaneLayout> ExtractColorPlaneLayout(
const gfx::GpuMemoryBufferHandle& gmb_handle) { … }
template <class T>
std::string VectorToString(const std::vector<T>& vec) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
scoped_refptr<DecoderBuffer> DecryptBitstreamBuffer(
BitstreamBuffer bitstream_buffer) {
auto mem_region = bitstream_buffer.DuplicateRegion();
if (!mem_region.IsValid()) {
DVLOG(2) << "Invalid shared memory region";
return nullptr;
}
const size_t available_size =
mem_region.GetSize() -
base::checked_cast<size_t>(bitstream_buffer.offset());
auto mapping = mem_region.Map();
if (!mapping.IsValid()) {
DVLOG(2) << "Failed mapping shared memory";
return nullptr;
}
uint8_t* data = mapping.GetMemoryAs<uint8_t>();
if (!data) {
DVLOG(2) << "Failed accessing shared memory";
return nullptr;
}
data += bitstream_buffer.offset();
if (available_size <= cdm_oemcrypto::kSecureBufferHeaderSize ||
memcmp(data, cdm_oemcrypto::kSecureBufferTag,
cdm_oemcrypto::kSecureBufferTagLen)) {
return bitstream_buffer.ToDecoderBuffer();
}
VLOG(2) << "Detected secure buffer format in VDVDA";
uint32_t proto_size = 0;
memcpy(&proto_size, data + cdm_oemcrypto::kSecureBufferTagLen,
sizeof(uint32_t));
if (proto_size > cdm_oemcrypto::kSecureBufferHeaderSize -
cdm_oemcrypto::kSecureBufferProtoOffset) {
DVLOG(2) << "Proto size goes beyond header size";
return nullptr;
}
std::string serialized_proto(
data + cdm_oemcrypto::kSecureBufferProtoOffset,
data + cdm_oemcrypto::kSecureBufferProtoOffset + proto_size);
chromeos::cdm::ArcSecureBufferForChrome buffer_proto;
if (!buffer_proto.ParseFromString(serialized_proto)) {
DVLOG(2) << "Failed deserializing secure buffer proto";
return nullptr;
}
std::vector<media::SubsampleEntry> subsamples;
size_t buffer_size = 0;
for (const auto& subsample : buffer_proto.subsample()) {
buffer_size += subsample.clear_bytes() + subsample.cypher_bytes();
subsamples.emplace_back(subsample.clear_bytes(), subsample.cypher_bytes());
}
std::optional<EncryptionPattern> pattern = std::nullopt;
if (buffer_proto.has_pattern()) {
pattern.emplace(buffer_proto.pattern().cypher_bytes(),
buffer_proto.pattern().clear_bytes());
}
scoped_refptr<DecoderBuffer> buffer = bitstream_buffer.ToDecoderBuffer(
cdm_oemcrypto::kSecureBufferHeaderSize, buffer_size);
if (!buffer) {
DVLOG(2) << "Secure buffer data goes beyond shared memory size";
return nullptr;
}
if (buffer_proto.encryption_scheme() !=
chromeos::cdm::ArcSecureBufferForChrome::NONE) {
buffer->set_decrypt_config(std::make_unique<DecryptConfig>(
buffer_proto.encryption_scheme() ==
chromeos::cdm::ArcSecureBufferForChrome::CBCS
? EncryptionScheme::kCbcs
: EncryptionScheme::kCenc,
buffer_proto.key_id(), buffer_proto.iv(), std::move(subsamples),
std::move(pattern)));
}
return buffer;
}
#endif
}
std::unique_ptr<VideoDecodeAccelerator> VdVideoDecodeAccelerator::Create(
CreateVideoDecoderCb create_vd_cb,
Client* client,
const Config& config,
scoped_refptr<base::SequencedTaskRunner> task_runner) { … }
VdVideoDecodeAccelerator::VdVideoDecodeAccelerator(
CreateVideoDecoderCb create_vd_cb,
scoped_refptr<base::SequencedTaskRunner> client_task_runner)
: … { … }
void VdVideoDecodeAccelerator::Destroy() { … }
VdVideoDecodeAccelerator::~VdVideoDecodeAccelerator() { … }
bool VdVideoDecodeAccelerator::Initialize(const Config& config,
Client* client) { … }
bool VdVideoDecodeAccelerator::Initialize(const Config& config,
Client* client,
bool low_delay) { … }
void VdVideoDecodeAccelerator::OnInitializeDone(DecoderStatus status) { … }
void VdVideoDecodeAccelerator::Decode(BitstreamBuffer bitstream_buffer) { … }
void VdVideoDecodeAccelerator::Decode(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) { … }
void VdVideoDecodeAccelerator::OnDecodeDone(int32_t bitstream_buffer_id,
DecoderStatus status) { … }
void VdVideoDecodeAccelerator::OnFrameReady(scoped_refptr<VideoFrame> frame) { … }
void VdVideoDecodeAccelerator::Flush() { … }
void VdVideoDecodeAccelerator::OnFlushDone(DecoderStatus status) { … }
void VdVideoDecodeAccelerator::Reset() { … }
void VdVideoDecodeAccelerator::OnResetDone() { … }
void VdVideoDecodeAccelerator::RequestFrames(
const Fourcc& fourcc,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
size_t max_num_frames,
NotifyLayoutChangedCb notify_layout_changed_cb,
ImportFrameCb import_frame_cb) { … }
VideoFrame::StorageType VdVideoDecodeAccelerator::GetFrameStorageType() const { … }
void VdVideoDecodeAccelerator::AssignPictureBuffers(
const std::vector<PictureBuffer>& buffers) { … }
void VdVideoDecodeAccelerator::ImportBufferForPicture(
int32_t picture_buffer_id,
VideoPixelFormat pixel_format,
gfx::GpuMemoryBufferHandle gmb_handle) { … }
std::optional<Picture> VdVideoDecodeAccelerator::GetPicture(
const VideoFrame& frame) { … }
void VdVideoDecodeAccelerator::OnFrameReleasedThunk(
std::optional<base::WeakPtr<VdVideoDecodeAccelerator>> weak_this,
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<FrameResource> origin_frame) { … }
void VdVideoDecodeAccelerator::OnFrameReleased(
scoped_refptr<FrameResource> origin_frame) { … }
void VdVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { … }
void VdVideoDecodeAccelerator::OnError(base::Location location, Error error) { … }
}