chromium/media/gpu/chromeos/vd_video_decode_accelerator.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#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)
// gn check does not account for BUILDFLAG(), so including these headers will
// make gn check fail for builds other than ash-chrome. See gn help nogncheck
// for more information.
#include "chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h"  // nogncheck
#include "media/gpu/chromeos/secure_buffer.pb.h"                  // nogncheck
#include "third_party/cros_system_api/constants/cdm_oemcrypto.h"  // nogncheck
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

namespace media {
namespace {

// VideoDecoder copies the timestamp from DecodeBuffer to its corresponding
// FrameResource. However, VideoDecodeAccelerator uses bitstream ID to find the
// corresponding output picture. Therefore, we store bitstream ID at the
// timestamp field. These two functions are used for converting between
// bitstream ID and fake timestamp.
base::TimeDelta BitstreamIdToFakeTimestamp(int32_t bitstream_id) {}

int32_t FakeTimestampToBitstreamId(base::TimeDelta timestamp) {}

std::vector<ColorPlaneLayout> ExtractColorPlaneLayout(
    const gfx::GpuMemoryBufferHandle& gmb_handle) {}

// TODO(akahuang): Move this function to a utility file.
template <class T>
std::string VectorToString(const std::vector<T>& vec) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
scoped_refptr<DecoderBuffer> DecryptBitstreamBuffer(
    BitstreamBuffer bitstream_buffer) {
  // Check to see if we have our secure buffer tag and then extract the
  // decrypt parameters.
  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;
  }
  // Checks if this buffer contains the details needed for HW protected video
  // decoding.
  // The header is 1KB in size (cdm_oemcrypto::kSecureBufferHeaderSize).
  // It consists of 3 components.
  // 1. Marker tag - cdm_oemcrypto::kSecureBufferTag
  // 2. unsigned 32-bit size of #3
  // 3. Serialized ArcSecureBufferForChrome proto
  uint8_t* data = mapping.GetMemoryAs<uint8_t>();
  if (!data) {
    DVLOG(2) << "Failed accessing shared memory";
    return nullptr;
  }
  // Apply the offset here so we don't need to worry about page alignment in the
  // mapping.
  data += bitstream_buffer.offset();
  if (available_size <= cdm_oemcrypto::kSecureBufferHeaderSize ||
      memcmp(data, cdm_oemcrypto::kSecureBufferTag,
             cdm_oemcrypto::kSecureBufferTagLen)) {
    // This occurs in Intel implementations when we are in a clear portion.
    return bitstream_buffer.ToDecoderBuffer();
  }
  VLOG(2) << "Detected secure buffer format in VDVDA";
  // Read the protobuf size.
  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;
  }
  // Read the serialized proto.
  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;
  }

  // Now extract the DecryptConfig info from the protobuf.
  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());
  }
  // Now create the DecryptConfig and set it in the decoder buffer.
  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  // BUILDFLAG(IS_CHROMEOS_ASH)

}  // namespace

// static
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) {}

// static
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) {}

}  // namespace media