Commit 78d3c701 authored by Hirokazu Honda's avatar Hirokazu Honda Committed by Commit Bot

media/gpu/V4L2VEA: Enable to encode GpuMemoryBuffer based VideoFrame

This CL enables V4L2VideoEncodeAccelerator to encode GpuMemoryBuffer based
VideoFrame. GpuMemoryBuffer is preferred to DMABUF on encoding because
GpumemoryBuffer interface support Map() and multiplatform support (e.g.
Android and Windows). V4L2VideoEncodeAccelerator still can encode DMABUF
based VideoFrame.

Bug: 1001413
Test: video_encode_accelerator_unittest on kevin with crrev.com/c/1808939
Change-Id: I1bc19d47bea88077cb778cb2c7c70618d22731a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1808946
Commit-Queue: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: default avatarAlexandre Courbot <acourbot@chromium.org>
Cr-Commit-Position: refs/heads/master@{#697534}
parent b7d2e020
...@@ -121,22 +121,29 @@ gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferHandle( ...@@ -121,22 +121,29 @@ gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferHandle(
DCHECK(video_frame); DCHECK(video_frame);
gfx::GpuMemoryBufferHandle handle; gfx::GpuMemoryBufferHandle handle;
switch (video_frame->storage_type()) {
case VideoFrame::STORAGE_GPU_MEMORY_BUFFER:
handle = video_frame->GetGpuMemoryBuffer()->CloneHandle();
break;
#if defined(OS_LINUX) #if defined(OS_LINUX)
handle.type = gfx::NATIVE_PIXMAP; case VideoFrame::STORAGE_DMABUFS: {
handle.type = gfx::NATIVE_PIXMAP;
std::vector<base::ScopedFD> duped_fds = std::vector<base::ScopedFD> duped_fds =
DuplicateFDs(video_frame->DmabufFds()); DuplicateFDs(video_frame->DmabufFds());
const size_t num_planes = VideoFrame::NumPlanes(video_frame->format()); const size_t num_planes = VideoFrame::NumPlanes(video_frame->format());
DCHECK_EQ(video_frame->layout().planes().size(), num_planes); DCHECK_EQ(video_frame->layout().planes().size(), num_planes);
handle.native_pixmap_handle.modifier = video_frame->layout().modifier(); handle.native_pixmap_handle.modifier = video_frame->layout().modifier();
for (size_t i = 0; i < num_planes; ++i) { for (size_t i = 0; i < num_planes; ++i) {
const auto& plane = video_frame->layout().planes()[i]; const auto& plane = video_frame->layout().planes()[i];
handle.native_pixmap_handle.planes.emplace_back( handle.native_pixmap_handle.planes.emplace_back(
plane.stride, plane.offset, plane.size, std::move(duped_fds[i])); plane.stride, plane.offset, plane.size, std::move(duped_fds[i]));
} }
#else
NOTREACHED();
#endif // defined(OS_LINUX) #endif // defined(OS_LINUX)
} break;
default:
NOTREACHED() << "Unsupported storage type: "
<< video_frame->storage_type();
}
return handle; return handle;
} }
...@@ -147,7 +154,11 @@ scoped_refptr<gfx::NativePixmapDmaBuf> CreateNativePixmapDmaBuf( ...@@ -147,7 +154,11 @@ scoped_refptr<gfx::NativePixmapDmaBuf> CreateNativePixmapDmaBuf(
// Create a native pixmap from the frame's memory buffer handle. // Create a native pixmap from the frame's memory buffer handle.
gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle = gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle =
CreateGpuMemoryBufferHandle(video_frame); CreateGpuMemoryBufferHandle(video_frame);
DCHECK(!gpu_memory_buffer_handle.is_null()); if (gpu_memory_buffer_handle.is_null() ||
gpu_memory_buffer_handle.type != gfx::NATIVE_PIXMAP) {
VLOGF(1) << "Failed to create native GpuMemoryBufferHandle";
return nullptr;
}
auto buffer_format = auto buffer_format =
VideoPixelFormatToGfxBufferFormat(video_frame->layout().format()); VideoPixelFormatToGfxBufferFormat(video_frame->layout().format());
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "media/gpu/macros.h" #include "media/gpu/macros.h"
#include "media/gpu/v4l2/generic_v4l2_device.h" #include "media/gpu/v4l2/generic_v4l2_device.h"
#include "media/gpu/v4l2/v4l2_decode_surface.h" #include "media/gpu/v4l2/v4l2_decode_surface.h"
#include "ui/gfx/native_pixmap_handle.h"
#if defined(ARCH_CPU_ARMEL) #if defined(ARCH_CPU_ARMEL)
#include "media/gpu/v4l2/tegra_v4l2_device.h" #include "media/gpu/v4l2/tegra_v4l2_device.h"
...@@ -483,6 +484,31 @@ bool V4L2WritableBufferRef::QueueDMABuf( ...@@ -483,6 +484,31 @@ bool V4L2WritableBufferRef::QueueDMABuf(
return std::move(self).DoQueue(); return std::move(self).DoQueue();
} }
bool V4L2WritableBufferRef::QueueDMABuf(
const std::vector<gfx::NativePixmapPlane>& planes) && {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(IsValid());
// Move ourselves so our data gets freed no matter when we return
V4L2WritableBufferRef self(std::move(*this));
if (self.Memory() != V4L2_MEMORY_DMABUF) {
VLOGF(1) << "Called on invalid buffer type!";
return false;
}
size_t num_planes = self.PlanesCount();
// TODO(hiroh): Strengthen this check with v4l2 pixel format.
if (planes.size() < num_planes) {
VLOGF(1) << "The given number of fds is less than required one";
return false;
}
for (size_t i = 0; i < num_planes; i++)
self.buffer_data_->v4l2_buffer_.m.planes[i].m.fd = planes[i].fd.get();
return std::move(self).DoQueue();
}
size_t V4L2WritableBufferRef::PlanesCount() const { size_t V4L2WritableBufferRef::PlanesCount() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(IsValid()); DCHECK(IsValid());
......
...@@ -48,6 +48,10 @@ ...@@ -48,6 +48,10 @@
#define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1') #define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1')
#endif #endif
namespace gfx {
struct NativePixmapPlane;
} // namespace gfx
namespace media { namespace media {
class V4L2Queue; class V4L2Queue;
...@@ -96,6 +100,15 @@ class MEDIA_GPU_EXPORT V4L2WritableBufferRef { ...@@ -96,6 +100,15 @@ class MEDIA_GPU_EXPORT V4L2WritableBufferRef {
// In case of error, false is returned and the buffer is returned to the free // In case of error, false is returned and the buffer is returned to the free
// list. // list.
bool QueueDMABuf(const std::vector<base::ScopedFD>& fds) &&; bool QueueDMABuf(const std::vector<base::ScopedFD>& fds) &&;
// Queue a DMABUF buffer, assigning file descriptors of |planes| for planes.
// It is allowed the number of |planes| might be greater than the number of
// planes of this buffer. It happens when the v4l2 pixel format is single
// planar. The fd of the first plane of |planes| is only used in that case.
// If successful, true is returned and the reference to the buffer is dropped
// so this reference becomes invalid.
// In case of error, false is returned and the buffer is returned to the free
// list.
bool QueueDMABuf(const std::vector<gfx::NativePixmapPlane>& planes) &&;
// Returns the number of planes in this buffer. // Returns the number of planes in this buffer.
size_t PlanesCount() const; size_t PlanesCount() const;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "media/base/video_types.h" #include "media/base/video_types.h"
#include "media/gpu/gpu_video_encode_accelerator_helpers.h" #include "media/gpu/gpu_video_encode_accelerator_helpers.h"
#include "media/gpu/image_processor_factory.h" #include "media/gpu/image_processor_factory.h"
#include "media/gpu/linux/platform_video_frame_utils.h"
#include "media/gpu/macros.h" #include "media/gpu/macros.h"
#include "media/video/h264_level_limits.h" #include "media/video/h264_level_limits.h"
#include "media/video/h264_parser.h" #include "media/video/h264_parser.h"
...@@ -1047,6 +1048,18 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() { ...@@ -1047,6 +1048,18 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
DCHECK_EQ(device_input_layout_->format(), frame->format()); DCHECK_EQ(device_input_layout_->format(), frame->format());
size_t num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt( size_t num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt(
V4L2Device::VideoFrameLayoutToV4L2PixFmt(*device_input_layout_)); V4L2Device::VideoFrameLayoutToV4L2PixFmt(*device_input_layout_));
// Create GpuMemoryBufferHandle for native_input_mode.
gfx::GpuMemoryBufferHandle gmb_handle;
if (input_buf.Memory() == V4L2_MEMORY_DMABUF) {
gmb_handle = CreateGpuMemoryBufferHandle(frame.get());
if (gmb_handle.is_null() || gmb_handle.type != gfx::NATIVE_PIXMAP) {
VLOGF(1) << "Failed to create native GpuMemoryBufferHandle";
NOTIFY_ERROR(kPlatformFailureError);
return false;
}
}
for (size_t i = 0; i < num_planes; ++i) { for (size_t i = 0; i < num_planes; ++i) {
// Single-buffer input format may have multiple color planes, so bytesused // Single-buffer input format may have multiple color planes, so bytesused
// of the single buffer should be sum of each color planes' size. // of the single buffer should be sum of each color planes' size.
...@@ -1068,7 +1081,8 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() { ...@@ -1068,7 +1081,8 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
break; break;
case V4L2_MEMORY_DMABUF: { case V4L2_MEMORY_DMABUF: {
const auto& planes = frame->layout().planes(); const std::vector<gfx::NativePixmapPlane>& planes =
gmb_handle.native_pixmap_handle.planes;
// TODO(crbug.com/901264): The way to pass an offset within a DMA-buf is // TODO(crbug.com/901264): The way to pass an offset within a DMA-buf is
// not defined in V4L2 specification, so we abuse data_offset for now. // not defined in V4L2 specification, so we abuse data_offset for now.
// Fix it when we have the right interface, including any necessary // Fix it when we have the right interface, including any necessary
...@@ -1098,7 +1112,7 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() { ...@@ -1098,7 +1112,7 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
break; break;
} }
case V4L2_MEMORY_DMABUF: { case V4L2_MEMORY_DMABUF: {
std::move(input_buf).QueueDMABuf(frame->DmabufFds()); std::move(input_buf).QueueDMABuf(gmb_handle.native_pixmap_handle.planes);
break; break;
} }
default: default:
...@@ -1107,6 +1121,11 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() { ...@@ -1107,6 +1121,11 @@ bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
return false; return false;
} }
// Keep |gmb_handle| alive as long as |frame| is alive so that fds passed
// to the driver are valid during encoding.
frame->AddDestructionObserver(
base::BindOnce([](gfx::GpuMemoryBufferHandle) {}, std::move(gmb_handle)));
InputRecord& input_record = input_buffer_map_[buffer_id]; InputRecord& input_record = input_buffer_map_[buffer_id];
input_record.frame = frame; input_record.frame = frame;
input_record.ip_output_buffer_index = frame_info.ip_output_buffer_index; input_record.ip_output_buffer_index = frame_info.ip_output_buffer_index;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment