blob: 902d78d98f3245b561d54ed18e8eb31e1dd88ddb [file] [log] [blame]
// Copyright 2021 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.
#ifndef COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_DECODER_H_
#define COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_DECODER_H_
#include <map>
#include <memory>
#include <queue>
#include <vector>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "components/arc/mojom/video_decode_accelerator.mojom.h"
#include "media/base/decoder_buffer.h"
#include "media/base/video_decoder.h"
#include "media/gpu/chromeos/vda_video_frame_pool.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace arc {
class ProtectedBufferManager;
// The GpuArcVideoDecoder listens to mojo IPC requests and forwards these to an
// instance of media::VideoDecoder. Decoded frames are passed back to the mojo
// client.
//
// Note: Even though currently the underlying decoder uses the
// media::VideoDecoder interface, the mojo communication with the client still
// uses the mojo::VideoDecodeAccelerator interface. A new mojo::VideoDecoder
// interface will be introduced in a future step.
// TODO(dstaessens): Switch to a new VD-based mojo client.
class GpuArcVideoDecoder : public mojom::VideoDecodeAccelerator,
public media::VdaVideoFramePool::VdaDelegate {
public:
GpuArcVideoDecoder(
scoped_refptr<ProtectedBufferManager> protected_buffer_manager);
~GpuArcVideoDecoder() override;
GpuArcVideoDecoder(const GpuArcVideoDecoder&) = delete;
GpuArcVideoDecoder& operator=(const GpuArcVideoDecoder&) = delete;
GpuArcVideoDecoder(GpuArcVideoDecoder&&) = delete;
GpuArcVideoDecoder& operator=(GpuArcVideoDecoder&&) = delete;
// Implementation of mojom::VideoDecodeAccelerator.
void Initialize(mojom::VideoDecodeAcceleratorConfigPtr config,
mojo::PendingRemote<mojom::VideoDecodeClient> client,
InitializeCallback callback) override;
void Decode(mojom::BitstreamBufferPtr bitstream_buffer) override;
void AssignPictureBuffers(uint32_t count) override;
void ImportBufferForPicture(int32_t picture_buffer_id,
mojom::HalPixelFormat format,
mojo::ScopedHandle handle,
std::vector<VideoFramePlane> planes,
mojom::BufferModifierPtr modifier) override;
void ReusePictureBuffer(int32_t picture_buffer_id) override;
void Flush(FlushCallback callback) override;
void Reset(ResetCallback callback) override;
// Implementation of VdaVideoFramePool::VdaDelegate.
void RequestFrames(const media::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) override;
// Called when all references to a video frame have been dropped.
void OnFrameReleased(scoped_refptr<media::VideoFrame> origin_frame);
private:
// Buffer allocation flow (used on initialization and resolution changes):
// 1. The VdaVideoFramePool calls RequestFrames() to request N buffers. The
// request is forwarded to the mojo client using ProvidePictureBuffers().
// 2. The mojo client calls AssignPictureBuffers().
// 3. The mojo client calls ImportBufferForPicture() N times.
// 4. After sending a decoded frame to the client using PictureReady(), the
// client calls ReusePictureBuffer() when the buffer can be recycled.
enum class DecoderState {
kUninitialized, // The decoder is not initialized yet
kAwaitingAssignPictureBuffers, // Waiting for AssignPictureBuffers()
kAwaitingFirstImport, // Wait for ImportBufferForPicture()
kDecoding, // Ready to decode requests
kError // An error occurred
};
using Request = base::OnceClosure;
using DmabufId = media::DmabufVideoFramePool::DmabufId;
// Called by the decoder when initialization is done.
void OnInitializeDone(media::Status status);
// Called by the decoder when the specified buffer has been decoded.
void OnDecodeDone(int32_t bitstream_buffer_id, media::Status status);
// Called by the decoder when a decoded frame is ready.
void OnFrameReady(scoped_refptr<media::VideoFrame> frame);
// Called by the decoder when a flush request has been completed.
void OnFlushDone(media::Status status);
// Called by the decoder when a reset request has been completed.
void OnResetDone();
// Called when an error occurred.
void OnError(base::Location location, Result error);
// Report the initialization status to the client.
void HandleInitializeDone(Result result);
// Handle all requests that are currently in the |requests_| queue.
void HandleRequests();
// Handle the specified request. If the decoder is currently resetting the
// request will be queued and handled once OnResetDone() is called.
void HandleRequest(Request request);
// Handle a decode request of the specified |buffer|.
void HandleDecodeRequest(int bitstream_id,
scoped_refptr<media::DecoderBuffer> buffer);
// Handle a flush request with specified |callback|. Multiple simultaneous
// flush requests are allowed and will be handled in FIFO order.
void HandleFlushRequest(FlushCallback callback);
// Handle a reset request with specified |callback|. All ongoing flush
// operations will be reported as canceled.
void HandleResetRequest(ResetCallback callback);
// Create a decoder buffer from the specified |fd|.
scoped_refptr<media::DecoderBuffer> CreateDecoderBuffer(base::ScopedFD fd,
uint32_t offset,
uint32_t bytes_used);
// Create a GPU memory handle from the specified |fd|.
gfx::GpuMemoryBufferHandle CreateGpuMemoryHandle(
base::ScopedFD fd,
const std::vector<VideoFramePlane>& planes,
media::VideoPixelFormat pixel_format,
uint64_t modifier);
// Create a video frame from the specified |gmb_handle|.
scoped_refptr<media::VideoFrame> CreateVideoFrame(
gfx::GpuMemoryBufferHandle gmb_handle,
media::VideoPixelFormat pixel_format) const;
// The number of currently active instances. Always accessed on the same
// thread, so we don't need to use a lock.
static size_t num_instances_;
// Current state of the video decoder.
DecoderState decoder_state_ = DecoderState::kUninitialized;
// The remote mojo client.
mojo::Remote<mojom::VideoDecodeClient> client_;
// The local video decoder.
std::unique_ptr<media::VideoDecoder> decoder_;
// callback used to notify the video frame pool of new video frame formats,
// used when the pool requests new frames using RequestFrames().
NotifyLayoutChangedCb notify_layout_changed_cb_;
// Callback used to insert new frames in the video frame pool.
ImportFrameCb import_frame_cb_;
// Initialization callback, used while the decoder is being initialized.
InitializeCallback init_callback_;
// The list of callbacks associated with any in-progress flush requests.
std::queue<FlushCallback> flush_callbacks_;
// The callback associated with the ongoing reset request if any.
ResetCallback reset_callback_;
// Requests currently waiting until resetting the decoder has completed.
std::queue<Request> requests_;
// The coded size currently used for video frames.
gfx::Size coded_size_;
// The coded size requested by the decoder, will be applied once the Mojo
// client called AssignPictureBuffers().
gfx::Size requested_coded_size_;
// The current video frame layout.
absl::optional<media::VideoFrameLayout> video_frame_layout_;
// The number of output buffers.
size_t output_buffer_count_ = 0;
// The video frames currently in use by the client and their associated
// picture buffer ids. We need to hold references to video frames to prevent
// them from being returned to the video frame pool for reuse while they are
// still in use by our client. The use count is tracked as the same frame
// might be sent multiple times to the client when using the VP9
// 'show_existing_frame' feature.
std::map<int32_t, std::pair<scoped_refptr<media::VideoFrame>, size_t>>
client_video_frames_;
// Map of video frame's DmabufId to the associated picture buffer id.
std::map<DmabufId, int32_t> frame_id_to_picture_id_;
// The protected buffer manager, used when decoding an encrypted video.
scoped_refptr<ProtectedBufferManager> protected_buffer_manager_;
// Whether we're decoding an encrypted video.
absl::optional<bool> secure_mode_;
// The client task runner and its sequence checker. All methods should be run
// on this task runner.
scoped_refptr<base::SequencedTaskRunner> client_task_runner_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtr<GpuArcVideoDecoder> weak_this_;
base::WeakPtrFactory<GpuArcVideoDecoder> weak_this_factory_{this};
};
} // namespace arc
#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_DECODER_H_