Commit 9d616b48 authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

Mac zero copy capture: Add software IOSurface support

The capture process knows nothing about whether or not hardware
acceleration is enabled, and cannot therefore be told not to send
GpuMemoryBuffers when there is no GpuMemoryBuffer support.

Add a path whereby a media::VideoFrame can be created to wrap an
IOSurface-backed gfx::GpuMemoryBufferHandle. This will be used when
the capture process gives Blink a GpuMemoryBuffer handle, but there no
longer exists hardware acceleration support (because of being disabled
statically or dynamically).

Bug: 1125879
Change-Id: Id87ca3d832e68a3501ed12540d3d265f23cd0362
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2415575
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarccameron <ccameron@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808244}
parent aaab8ee4
...@@ -395,6 +395,7 @@ source_set("base") { ...@@ -395,6 +395,7 @@ source_set("base") {
"CoreVideo.framework", "CoreVideo.framework",
"CoreFoundation.framework", "CoreFoundation.framework",
"CoreGraphics.framework", "CoreGraphics.framework",
"IOSurface.framework",
] ]
} else if (is_win) { } else if (is_win) {
sources += [ "user_input_monitor_win.cc" ] sources += [ "user_input_monitor_win.cc" ]
......
...@@ -646,6 +646,77 @@ scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs( ...@@ -646,6 +646,77 @@ scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs(
#endif #endif
#if defined(OS_MAC) #if defined(OS_MAC)
// static
scoped_refptr<VideoFrame> VideoFrame::WrapIOSurface(
gfx::GpuMemoryBufferHandle handle,
const gfx::Rect& visible_rect,
base::TimeDelta timestamp) {
if (handle.type != gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER) {
DLOG(ERROR) << "Non-IOSurface handle.";
return nullptr;
}
if (!handle.mach_port) {
DLOG(ERROR) << "Invalid mach port.";
return nullptr;
}
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
IOSurfaceLookupFromMachPort(handle.mach_port));
if (!io_surface) {
DLOG(ERROR) << "Unable to lookup IOSurface.";
return nullptr;
}
// Only support NV12 IOSurfaces.
const OSType cv_pixel_format = IOSurfaceGetPixelFormat(io_surface);
if (cv_pixel_format != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {
DLOG(ERROR) << "Invalid (non-NV12) pixel format.";
return nullptr;
}
const VideoPixelFormat pixel_format = PIXEL_FORMAT_NV12;
// Retrieve the layout parameters for |io_surface_|.
const size_t num_planes = IOSurfaceGetPlaneCount(io_surface);
const gfx::Size size(IOSurfaceGetWidth(io_surface),
IOSurfaceGetHeight(io_surface));
std::vector<int32_t> strides;
for (size_t i = 0; i < num_planes; ++i)
strides.push_back(IOSurfaceGetBytesPerRowOfPlane(io_surface, i));
base::Optional<VideoFrameLayout> layout =
media::VideoFrameLayout::CreateWithStrides(pixel_format, size, strides);
if (!layout) {
DLOG(ERROR) << "Invalid layout.";
return nullptr;
}
const StorageType storage_type = STORAGE_UNOWNED_MEMORY;
if (!IsValidConfig(pixel_format, storage_type, size, visible_rect, size)) {
DLOG(ERROR) << "Invalid config.";
return nullptr;
}
// Lock the IOSurface for CPU read access. After the VideoFrame is created,
// add a destruction callback to unlock the IOSurface.
kern_return_t lock_result =
IOSurfaceLock(io_surface, kIOSurfaceLockReadOnly, nullptr);
if (lock_result != kIOReturnSuccess) {
DLOG(ERROR) << "Failed to lock IOSurface.";
return nullptr;
}
auto unlock_lambda = [](base::ScopedCFTypeRef<IOSurfaceRef> io_surface) {
IOSurfaceUnlock(io_surface, kIOSurfaceLockReadOnly, nullptr);
};
scoped_refptr<VideoFrame> frame =
new VideoFrame(*layout, storage_type, visible_rect, size, timestamp);
for (size_t i = 0; i < num_planes; ++i) {
frame->data_[i] = reinterpret_cast<uint8_t*>(
IOSurfaceGetBaseAddressOfPlane(io_surface, i));
}
frame->AddDestructionObserver(
base::BindOnce(unlock_lambda, std::move(io_surface)));
return frame;
}
// static // static
scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer( scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer(
CVPixelBufferRef cv_pixel_buffer, CVPixelBufferRef cv_pixel_buffer,
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
namespace gfx { namespace gfx {
class GpuMemoryBuffer; class GpuMemoryBuffer;
struct GpuMemoryBufferHandle;
} }
namespace media { namespace media {
...@@ -277,6 +278,13 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { ...@@ -277,6 +278,13 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
static scoped_refptr<VideoFrame> WrapCVPixelBuffer( static scoped_refptr<VideoFrame> WrapCVPixelBuffer(
CVPixelBufferRef cv_pixel_buffer, CVPixelBufferRef cv_pixel_buffer,
base::TimeDelta timestamp); base::TimeDelta timestamp);
// Wraps a provided IOSurface with a VideoFrame. The IOSurface is retained
// and locked for the lifetime of the VideoFrame.
static scoped_refptr<VideoFrame> WrapIOSurface(
gfx::GpuMemoryBufferHandle handle,
const gfx::Rect& visible_rect,
base::TimeDelta timestamp);
#endif #endif
// Wraps |frame|. |visible_rect| must be a sub rect within // Wraps |frame|. |visible_rect| must be a sub rect within
......
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