chromium/media/gpu/chromeos/oop_video_decoder.cc

// Copyright 2022 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/oop_video_decoder.h"

#include "base/memory/ptr_util.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "build/chromeos_buildflags.h"
#include "chromeos/components/cdm_factory_daemon/stable_cdm_context_impl.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "media/base/format_utils.h"
#include "media/base/video_util.h"
#include "media/gpu/buffer_validation.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/mojo/common/mojo_decoder_buffer_converter.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"

#if BUILDFLAG(USE_VAAPI)
#include "media/gpu/vaapi/vaapi_wrapper.h"
#endif  // BUILDFLAG(USE_VAAPI)

// Throughout this file, we have sprinkled many CHECK()s to assert invariants
// that should hold regardless of the behavior of the remote decoder or
// untrusted client. We use CHECK()s instead of DCHECK()s because
// OOPVideoDecoder and associated classes are very stateful so:
//
// a) They're hard to reason about.
// b) They're hard to fully exercise with tests.
// c) It's hard to reason if the violation of an invariant can have security
//    implications because once we enter into a bad state, everything is fair
//    game.
//
// Hence it's safer to crash and surface those crashes.
//
// More specifically:
//
// - It's illegal to call many methods if OOPVideoDecoder enters into an error
//   state (tracked by |has_error_|).
//
// - The media::VideoDecoder interface demands that its users don't call certain
//   methods while in specific states. An OOPVideoDecoder is used by an
//   in-process class (the VideoDecoderPipeline) to communicate with an
//   out-of-process video decoder. Therefore, we trust that the in-process user
//   of this class abides by the requirements of the media::VideoDecoder
//   interface and thus, we don't handle violations gracefully. In particular:
//
//   - No media::VideoDecoder methods should be called before the |init_cb|
//     passed to Initialize() is called. We track this interim state with
//     |init_cb_|.
//
//   - Initialize() should not be called while there are pending decodes (i.e.,
//     while !pending_decodes_.empty()).
//
//   - No media::VideoDecoder methods should be called before the |closure|
//     passed to Reset() is called. We track this interim state with
//     |reset_cb_|.

// TODO(b/220915557): OOPVideoDecoder cannot trust |remote_decoder_| (but
// |remote_decoder_| might trust us). We need to audit this class to make sure:
//
// - That OOPVideoDecoder validates everything coming from
//   |remote_video_decoder_|.
//
// - That OOPVideoDecoder meets the requirements of the media::VideoDecoder and
//   the media::VideoDecoderMixin interfaces. For example, we need to make sure
//   we guarantee statements like "all pending Decode() requests will be
//   finished or aborted before |closure| is called" (for
//   VideoDecoder::Reset()).
//
// - That OOPVideoDecoder asserts it's not being misused (which might cause us
//   to violate the requirements of the StableVideoDecoder interface). For
//   example, the StableVideoDecoder interface says for Decode(): "this must not
//   be called while there are pending Initialize(), Reset(), or Decode(EOS)
//   requests."

namespace media {

namespace {

// Size of the timestamp cache. We don't want the cache to grow without bounds.
// The maximum size is chosen to be the same as in the VaapiVideoDecoder.
constexpr size_t kTimestampCacheSize =;

// Converts |mojo_frame| to a media::FrameResource after performing some
// validation. The reason we do validation/conversion here and not in the mojo
// traits is that we don't want every incoming stable::mojom::VideoFrame to
// result in a media::FrameResource: we'd like to re-use buffers based on the
// incoming |mojo_frame|->gpu_memory_buffer_handle.id; if that incoming
// |mojo_frame| is a frame that we already know about, we can re-use the
// underlying buffer without creating a media::FrameResource.
scoped_refptr<FrameResource> MojoVideoFrameToFrameResource(
    stable::mojom::VideoFramePtr mojo_frame) {}

// A singleton helper class that makes it easy to manage requests to wait until
// the supported video decoder configurations are known and cache those
// configurations.
//
// All public methods are thread- and sequence-safe.
class OOPVideoDecoderSupportedConfigsManager {};

}  // namespace

// static
std::unique_ptr<VideoDecoderMixin> OOPVideoDecoder::Create(
    mojo::PendingRemote<stable::mojom::StableVideoDecoder>
        pending_remote_decoder,
    std::unique_ptr<media::MediaLog> media_log,
    scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
    base::WeakPtr<VideoDecoderMixin::Client> client) {}

// static
void OOPVideoDecoder::NotifySupportKnown(
    mojo::PendingRemote<stable::mojom::StableVideoDecoder> oop_video_decoder,
    base::OnceCallback<
        void(mojo::PendingRemote<stable::mojom::StableVideoDecoder>)> cb) {}

// static
std::optional<SupportedVideoDecoderConfigs>
OOPVideoDecoder::GetSupportedConfigs() {}

// static
void OOPVideoDecoder::ResetGlobalStateForTesting() {}

OOPVideoDecoder::OOPVideoDecoder(
    std::unique_ptr<media::MediaLog> media_log,
    scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
    base::WeakPtr<VideoDecoderMixin::Client> client,
    mojo::PendingRemote<stable::mojom::StableVideoDecoder>
        pending_remote_decoder)
    :{}

OOPVideoDecoder::~OOPVideoDecoder() {}

void OOPVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                 bool low_delay,
                                 CdmContext* cdm_context,
                                 InitCB init_cb,
                                 const PipelineOutputCB& output_cb,
                                 const WaitingCB& waiting_cb) {}

void OOPVideoDecoder::OnInitializeDone(const DecoderStatus& status,
                                       bool needs_bitstream_conversion,
                                       int32_t max_decode_requests,
                                       VideoDecoderType decoder_type,
                                       bool needs_transcryption) {}

void OOPVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
                             DecodeCB decode_cb) {}

void OOPVideoDecoder::OnDecodeDone(uint64_t decode_id,
                                   bool is_flush_cb,
                                   const DecoderStatus& status) {}

void OOPVideoDecoder::DeferDecodeCallback(DecodeCB decode_cb,
                                          const DecoderStatus& status) {}

void OOPVideoDecoder::CallDeferredDecodeCallback(DecodeCB decode_cb,
                                                 const DecoderStatus& status) {}

bool OOPVideoDecoder::HasPendingDecodeCallbacks() const {}

void OOPVideoDecoder::Reset(base::OnceClosure reset_cb) {}

void OOPVideoDecoder::OnResetDone() {}

void OOPVideoDecoder::CallResetCallback() {}

void OOPVideoDecoder::Stop() {}

void OOPVideoDecoder::ReleaseVideoFrame(
    const base::UnguessableToken& release_token) {}

void OOPVideoDecoder::ApplyResolutionChange() {}

bool OOPVideoDecoder::NeedsBitstreamConversion() const {}

bool OOPVideoDecoder::CanReadWithoutStalling() const {}

int OOPVideoDecoder::GetMaxDecodeRequests() const {}

VideoDecoderType OOPVideoDecoder::GetDecoderType() const {}

bool OOPVideoDecoder::IsPlatformDecoder() const {}

bool OOPVideoDecoder::NeedsTranscryption() {}

void OOPVideoDecoder::OnVideoFrameDecoded(
    stable::mojom::VideoFramePtr frame,
    bool can_read_without_stalling,
    const base::UnguessableToken& release_token) {}

void OOPVideoDecoder::OnWaiting(WaitingReason reason) {}

void OOPVideoDecoder::AddLogRecord(const MediaLogRecord& event) {}

FrameResource* OOPVideoDecoder::GetOriginalFrame(
    gfx::GenericSharedMemoryId frame_id) {}

}  // namespace media