Commit 1f3c85d3 authored by Markus Handell's avatar Markus Handell Committed by Commit Bot

Mac: zero-copy frame encode for IOSurface-backed media::VideoFrames.

When forwarding a frame to Video Encode Accelerator, RTCVideoEncoder
would almost always create a frame copy unless the incoming
media::VideoFrame was backed by STORAGE_SHMEM. The copy would be backed
by STORAGE_SHMEM, which results in the video decode accelerator wrapping
the VideoFrame's memory in a CVPixelBufferRef.

Changes:
1) Break out code in media::VideoFrame::WrapIOSurface() that creates
   an IOSurface from a GMB handle.
2) Code is added to WrapVideoFrameInCVPixelBuffer to create a
   CVPixelBufferRef via GpuMemoryBuffer::CloneHandle().
3) RTCVideoEncoder is changed to pass on GMB-backed video frames.

Bug: 1127791, 1125879
Change-Id: I59dd1eae59ae4dffb591830152f44e470fb3cce5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2410244Reviewed-by: default avatarccameron <ccameron@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarHirokazu Honda <hiroh@chromium.org>
Commit-Queue: Markus Handell <handellm@google.com>
Cr-Commit-Position: refs/heads/master@{#809450}
parent 8a4cf1cb
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "base/logging.h" #include "base/logging.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/mac/io_surface.h"
namespace media { namespace media {
...@@ -41,6 +43,27 @@ WrapVideoFrameInCVPixelBuffer(const VideoFrame& frame) { ...@@ -41,6 +43,27 @@ WrapVideoFrameInCVPixelBuffer(const VideoFrame& frame) {
return pixel_buffer; return pixel_buffer;
} }
// If the frame has a GMB, yank out its IOSurface if possible.
if (frame.GetGpuMemoryBuffer()) {
gfx::GpuMemoryBufferHandle handle =
frame.GetGpuMemoryBuffer()->CloneHandle();
if (handle.type == gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER) {
base::ScopedCFTypeRef<IOSurfaceRef> io_surface =
gfx::IOSurfaceMachPortToIOSurface(std::move(handle.mach_port));
if (io_surface) {
const CVReturn cv_return = CVPixelBufferCreateWithIOSurface(
nullptr, io_surface, nullptr, pixel_buffer.InitializeInto());
if (cv_return == kCVReturnSuccess) {
VLOG(3) << "Returning IOSurface-based CVPixelBuffer.";
return pixel_buffer;
}
pixel_buffer.reset();
}
}
}
VLOG(3) << "Returning RAM based CVPixelBuffer.";
// VideoFrame only supports YUV formats and most of them are 'YVU' ordered, // VideoFrame only supports YUV formats and most of them are 'YVU' ordered,
// which CVPixelBuffer does not support. This means we effectively can only // which CVPixelBuffer does not support. This means we effectively can only
// represent I420 and NV12 frames. In addition, VideoFrame does not carry // represent I420 and NV12 frames. In addition, VideoFrame does not carry
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#include "ui/gfx/buffer_format_util.h" #include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point.h"
#include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/gpu_memory_buffer.h"
#if defined(OS_MAC)
#include "ui/gfx/mac/io_surface.h"
#endif
namespace media { namespace media {
...@@ -694,14 +697,9 @@ scoped_refptr<VideoFrame> VideoFrame::WrapIOSurface( ...@@ -694,14 +697,9 @@ scoped_refptr<VideoFrame> VideoFrame::WrapIOSurface(
DLOG(ERROR) << "Non-IOSurface handle."; DLOG(ERROR) << "Non-IOSurface handle.";
return nullptr; return nullptr;
} }
if (!handle.mach_port) { base::ScopedCFTypeRef<IOSurfaceRef> io_surface =
DLOG(ERROR) << "Invalid mach port."; gfx::IOSurfaceMachPortToIOSurface(std::move(handle.mach_port));
return nullptr;
}
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
IOSurfaceLookupFromMachPort(handle.mach_port));
if (!io_surface) { if (!io_surface) {
DLOG(ERROR) << "Unable to lookup IOSurface.";
return nullptr; return nullptr;
} }
......
...@@ -1047,17 +1047,23 @@ void RTCVideoEncoder::Impl::EncodeOneFrame() { ...@@ -1047,17 +1047,23 @@ void RTCVideoEncoder::Impl::EncodeOneFrame() {
} }
const int index = input_buffers_free_.back(); const int index = input_buffers_free_.back();
bool requires_copy = false;
scoped_refptr<media::VideoFrame> frame; scoped_refptr<media::VideoFrame> frame;
if (next_frame->video_frame_buffer()->type() == const bool is_native_frame = next_frame->video_frame_buffer()->type() ==
webrtc::VideoFrameBuffer::Type::kNative) { webrtc::VideoFrameBuffer::Type::kNative;
// All non-native frames require a copy because we can't tell if non-copy
// conditions are met.
bool requires_copy = !is_native_frame;
if (!requires_copy) {
frame = static_cast<blink::WebRtcVideoFrameAdapter*>( frame = static_cast<blink::WebRtcVideoFrameAdapter*>(
next_frame->video_frame_buffer().get()) next_frame->video_frame_buffer().get())
->getMediaVideoFrame(); ->getMediaVideoFrame();
requires_copy = RequiresSizeChange(*frame) || const media::VideoFrame::StorageType storage = frame->storage_type();
frame->storage_type() != media::VideoFrame::STORAGE_SHMEM; const bool is_shmem_frame = storage == media::VideoFrame::STORAGE_SHMEM;
} else { const bool is_gmb_frame =
requires_copy = true; storage == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER;
requires_copy =
RequiresSizeChange(*frame) || !(is_shmem_frame || is_gmb_frame);
} }
if (requires_copy) { if (requires_copy) {
......
...@@ -292,4 +292,19 @@ void IOSurfaceSetColorSpace(IOSurfaceRef io_surface, ...@@ -292,4 +292,19 @@ void IOSurfaceSetColorSpace(IOSurfaceRef io_surface,
} }
} }
GFX_EXPORT base::ScopedCFTypeRef<IOSurfaceRef> IOSurfaceMachPortToIOSurface(
ScopedRefCountedIOSurfaceMachPort io_surface_mach_port) {
base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
if (!io_surface_mach_port) {
DLOG(ERROR) << "Invalid mach port.";
return io_surface;
}
io_surface.reset(IOSurfaceLookupFromMachPort(io_surface_mach_port));
if (!io_surface) {
DLOG(ERROR) << "Unable to lookup IOSurface.";
return io_surface;
}
return io_surface;
}
} // namespace gfx } // namespace gfx
...@@ -76,6 +76,10 @@ GFX_EXPORT void IOSurfaceSetColorSpace(IOSurfaceRef io_surface, ...@@ -76,6 +76,10 @@ GFX_EXPORT void IOSurfaceSetColorSpace(IOSurfaceRef io_surface,
GFX_EXPORT uint32_t GFX_EXPORT uint32_t
BufferFormatToIOSurfacePixelFormat(gfx::BufferFormat format); BufferFormatToIOSurfacePixelFormat(gfx::BufferFormat format);
// Return an IOSurface consuming |io_surface_mach_port|.
GFX_EXPORT base::ScopedCFTypeRef<IOSurfaceRef> IOSurfaceMachPortToIOSurface(
ScopedRefCountedIOSurfaceMachPort io_surface_mach_port);
} // namespace gfx } // namespace gfx
#endif // UI_GFX_MAC_IO_SURFACE_H_ #endif // UI_GFX_MAC_IO_SURFACE_H_
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