blob: 7bc0f131712fe63ec3dfe70437b27c516c4d9a9c [file] [log] [blame]
// Copyright 2020 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 MEDIA_GPU_CHROMEOS_VDA_VIDEO_FRAME_POOL_H_
#define MEDIA_GPU_CHROMEOS_VDA_VIDEO_FRAME_POOL_H_
#include "base/containers/queue.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "media/base/video_frame.h"
#include "media/gpu/chromeos/dmabuf_video_frame_pool.h"
#include "media/gpu/chromeos/fourcc.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
class WaitableEvent;
}
namespace media {
class GpuBufferLayout;
// This class is used by VdVideoDecodeAccelerator, which adapts
// VideoDecodeAccelerator to VideoDecoder interface.
// The mission is to allocate and manage DMA-buf VideoFrame by delegating the
// requests of buffer allocation to a VideoDecodeAccelerator instance, and
// provide VideoFrame to the VideoDecoder instance.
// The communication with VdVideoDecodeAccelerator, which inherits
// VdaDelegate, is executed on |vda_task_runner_|, and the communication with
// VideoDecoder instance is on |parent_task_runner_|.
class VdaVideoFramePool : public DmabufVideoFramePool {
public:
class VdaDelegate {
public:
// Callback for returning the layout of requested buffer.
using NotifyLayoutChangedCb =
base::OnceCallback<void(absl::optional<GpuBufferLayout>)>;
// Callback for importing available frames to this pool.
using ImportFrameCb =
base::RepeatingCallback<void(scoped_refptr<VideoFrame>)>;
// Request new frames from VDA's client. VdaDelegate has to return the
// layout of frames by calling |notify_layout_changed_cb|.
// After that, VdaDelegate should pass frames by calling
// |import_frame_cb|.
// Note: RequestFrames(), |notify_layout_changed_cb|, and |import_frame_cb|
// should be called on VdaVideoFramePool's |vda_task_runner_|.
virtual void 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) = 0;
};
VdaVideoFramePool(base::WeakPtr<VdaDelegate> vda,
scoped_refptr<base::SequencedTaskRunner> vda_task_runner);
~VdaVideoFramePool() override;
// DmabufVideoFramePool implementation.
StatusOr<GpuBufferLayout> Initialize(const Fourcc& fourcc,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
size_t max_num_frames,
bool use_protected) override;
scoped_refptr<VideoFrame> GetFrame() override;
bool IsExhausted() override;
void NotifyWhenFrameAvailable(base::OnceClosure cb) override;
void ReleaseAllFrames() override;
private:
// Update the layout of the buffers. |vda_| calls this as
// NotifyLayoutChangedCb.
void OnRequestFramesDone(base::WaitableEvent* done,
absl::optional<GpuBufferLayout> layout);
// Thunk to post ImportFrame() to |task_runner|.
// Because this thunk may be called in any thread, We don't want to
// dereference WeakPtr. Therefore we wrap the WeakPtr by absl::optional to
// avoid the task runner defererencing the WeakPtr.
static void ImportFrameThunk(
scoped_refptr<base::SequencedTaskRunner> task_runner,
absl::optional<base::WeakPtr<VdaVideoFramePool>> weak_this,
scoped_refptr<VideoFrame> frame);
// Import an available frame.
void ImportFrame(scoped_refptr<VideoFrame> frame);
// Call |frame_available_cb_| when the pool is not exhausted.
void CallFrameAvailableCbIfNeeded();
// WeakPtr of VdaDelegate instance, bound at |vda_task_runner_|.
base::WeakPtr<VdaDelegate> vda_;
// Task runner that interacts with VdaDelegate. All VdaDelegate's methods
// and their callbacks should be called on this task runner.
// Note: DmabufVideoFrame's public methods like Initialize() and GetFrame()
// should be called on |parent_task_runner_|.
scoped_refptr<base::SequencedTaskRunner> vda_task_runner_;
// The callback which is called when the pool is not exhausted.
base::OnceClosure frame_available_cb_;
// The layout of the frames in |frame_pool_|.
absl::optional<GpuBufferLayout> layout_;
// Data passed from Initialize().
size_t max_num_frames_ = 0;
absl::optional<Fourcc> fourcc_;
gfx::Size coded_size_;
gfx::Rect visible_rect_;
gfx::Size natural_size_;
base::queue<scoped_refptr<VideoFrame>> frame_pool_;
// Sequence checker for |parent_task_runner_|.
SEQUENCE_CHECKER(parent_sequence_checker_);
// The weak pointer of this, bound at |parent_task_runner_|.
base::WeakPtr<VdaVideoFramePool> weak_this_;
base::WeakPtrFactory<VdaVideoFramePool> weak_this_factory_{this};
};
} // namespace media
#endif // MEDIA_GPU_CHROMEOS_VDA_VIDEO_FRAME_POOL_H_