blob: 67a5d235e22caafd9028115dd2e62e4b91546db3 [file] [log] [blame]
// Copyright 2019 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_LINUX_MAILBOX_VIDEO_FRAME_CONVERTER_H_
#define MEDIA_GPU_LINUX_MAILBOX_VIDEO_FRAME_CONVERTER_H_
#include <map>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "media/base/video_decoder.h"
#include "media/base/video_frame.h"
#include "media/gpu/command_buffer_helper.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/video_frame_converter.h"
namespace media {
// The linux VideoDecoder implementations request DMA-buf VideoFrame from the
// DmabufVideoFramePool, and store the decoded data into DMA-buf. However the
// client of the VideoDecoder may only accept mailbox VideoFrame.
// This class is used for converting DMA-buf VideoFrame to mailbox VideoFrame.
// After conversion, the mailbox VideoFrame will retain a reference of the
// VideoFrame passed to ConvertFrame().
class MEDIA_GPU_EXPORT MailboxVideoFrameConverter : public VideoFrameConverter {
public:
using UnwrapFrameCB =
base::RepeatingCallback<VideoFrame*(const VideoFrame& wrapped_frame)>;
using GetCommandBufferStubCB = base::OnceCallback<gpu::CommandBufferStub*()>;
// In order to recycle VideoFrame, the DmabufVideoFramePool implementation may
// wrap the frame. We want to create texture only once for the same buffer, so
// we need to get the original frame at ConvertFrame(). |unwrap_frame_cb| is
// the callback used to get the original frame.
// |get_stub_cb| is the callback used to get the CommandBufferStub, which is
// used to create CommandBufferHelper.
MailboxVideoFrameConverter(
UnwrapFrameCB unwrap_frame_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
GetCommandBufferStubCB get_stub_cb);
~MailboxVideoFrameConverter() override;
// Convert DMA-buf VideoFrame to mailbox VideoFrame.
// For each frame, we bind DMA-buf to GL texture and create mailbox at GPU
// thread, and block working thread waiting for the result.
// The mailbox of each frame will be stored at |mailbox_table_|. When
// converting a frame second time, we just lookup the table instead of
// creating texture and mailbox at GPU thread.
scoped_refptr<VideoFrame> ConvertFrame(
scoped_refptr<VideoFrame> frame) override;
private:
bool CreateCommandBufferHelper();
// Generate mailbox for the DMA-buf VideoFrame. This method runs on the GPU
// thread.
// |origin_frame| is unwrapped from |frame| passed from ConvertFrame().
void GenerateMailbox(VideoFrame* origin_frame,
gpu::Mailbox* mailbox,
base::WaitableEvent* event);
// Register the mapping between DMA-buf VideoFrame and the mailbox.
void RegisterMailbox(VideoFrame* origin_frame, const gpu::Mailbox& mailbox);
// Thunk for calling UnregisterMailbox() on |task_runner|.
// Because this thunk may be called in any thread, We cannot dereference
// WeakPtr. Therefore we wrap the WeakPtr by base::Optional to avoid task
// runner defererence the WeakPtr.
static void UnregisterMailboxThunk(
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::Optional<base::WeakPtr<MailboxVideoFrameConverter>> converter,
int origin_frame_id);
// Remove the mapping between DMA-buf VideoFrame and the mailbox.
void UnregisterMailbox(int origin_frame_id);
// Destruction callback of converted frame. |frame| is the frame passed from
// ConvertFrame().
void OnMailboxHoldersReleased(scoped_refptr<VideoFrame> frame,
const gpu::SyncToken& sync_token);
// In DmabufVideoFramePool, we recycle the unused frames. To do that, each
// time a frame is requested from the pool it is wrapped inside another frame.
// A destruction callback is then added to this wrapped frame to automatically
// return it to the pool upon destruction. Unfortunately this means that a new
// frame is returned each time, and we need a way to uniquely identify the
// underlying frame to avoid converting the same frame multiple times.
// |unwrap_frame_cb_| is used to get the origin frame.
UnwrapFrameCB unwrap_frame_cb_;
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
GetCommandBufferStubCB get_stub_cb_;
// The interface to communicate with command buffer. We use this to create and
// destroy texture, wait for SyncToken, and generate mailbox.
scoped_refptr<CommandBufferHelper> command_buffer_helper_;
// Mapping from the unique_id of origin frame to its corresponding mailbox.
std::map<int, gpu::Mailbox> mailbox_table_;
// The weak pointer of this, bound to |parent_task_runner_|.
// Used at the VideoFrame destruction callback.
base::WeakPtr<MailboxVideoFrameConverter> weak_this_;
base::WeakPtrFactory<MailboxVideoFrameConverter> weak_this_factory_;
DISALLOW_COPY_AND_ASSIGN(MailboxVideoFrameConverter);
};
} // namespace media
#endif // MEDIA_GPU_LINUX_MAILBOX_VIDEO_FRAME_CONVERTER_H_