Commit 86d27cd0 authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Implement NV12 and GpuMemoryBuffer support for WebCodecs VideoFrames.

This allows for direct planar access to capture buffers on macOS.

R=sandersd

Bug: 1137288, 1141214
Change-Id: I6a4859a807f2d77fd2fdd87c61f8c15dbdfbb0ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2536035
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Dan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827059}
parent a7ad0f69
...@@ -19,6 +19,7 @@ include_rules = [ ...@@ -19,6 +19,7 @@ include_rules = [
"+ui/gfx/color_space.h", "+ui/gfx/color_space.h",
"+ui/gfx/geometry/rect.h", "+ui/gfx/geometry/rect.h",
"+ui/gfx/geometry/size.h", "+ui/gfx/geometry/size.h",
"+ui/gfx/gpu_memory_buffer.h",
] ]
specific_include_rules = { specific_include_rules = {
......
...@@ -8,16 +8,32 @@ ...@@ -8,16 +8,32 @@
#include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "ui/gfx/gpu_memory_buffer.h"
namespace blink { namespace blink {
namespace {
void CopyPlane(const uint8_t* plane,
size_t copy_size,
size_t trailing_zeros_size,
uint8_t* dest) {
// Copy plane bytes.
memcpy(dest, plane, copy_size);
// Zero trailing padding bytes.
memset(dest + copy_size, 0, trailing_zeros_size);
}
} // namespace
Plane::Plane(scoped_refptr<VideoFrameHandle> handle, size_t plane) Plane::Plane(scoped_refptr<VideoFrameHandle> handle, size_t plane)
: handle_(std::move(handle)), plane_(plane) { : handle_(std::move(handle)), plane_(plane) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
// Validate the plane index, but only if the handle is valid. // Validate the plane index, but only if the handle is valid.
auto local_frame = handle_->frame(); auto local_frame = handle_->frame();
if (local_frame) { if (local_frame) {
DCHECK(local_frame->IsMappable()); DCHECK(local_frame->IsMappable() || local_frame->HasGpuMemoryBuffer());
DCHECK_LT(plane, local_frame->layout().num_planes()); DCHECK_LT(plane, local_frame->layout().num_planes());
} }
#endif // DCHECK_IS_ON() #endif // DCHECK_IS_ON()
...@@ -86,11 +102,21 @@ void Plane::readInto(MaybeShared<DOMArrayBufferView> dst, ...@@ -86,11 +102,21 @@ void Plane::readInto(MaybeShared<DOMArrayBufferView> dst,
return; return;
} }
// Copy plane bytes. if (local_frame->IsMappable()) {
memcpy(base, local_frame->data(plane_), copy_size); CopyPlane(local_frame->data(plane_), copy_size, trailing_zeros_size, base);
return;
}
// Zero trailing padding bytes. DCHECK(local_frame->HasGpuMemoryBuffer());
memset(base + copy_size, 0, trailing_zeros_size); auto* gmb = local_frame->GetGpuMemoryBuffer();
if (!gmb->Map()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Could not map video frame into memory.");
return;
}
CopyPlane(static_cast<const uint8_t*>(gmb->memory(plane_)), copy_size,
trailing_zeros_size, base);
gmb->Unmap();
} }
} // namespace blink } // namespace blink
...@@ -219,10 +219,12 @@ VideoFrame* VideoFrame::Create(ImageBitmap* source, ...@@ -219,10 +219,12 @@ VideoFrame* VideoFrame::Create(ImageBitmap* source,
// static // static
bool VideoFrame::IsSupportedPlanarFormat(media::VideoFrame* frame) { bool VideoFrame::IsSupportedPlanarFormat(media::VideoFrame* frame) {
// For now only I420 in CPU memory is supported. // For now only I420 or NV12 in CPU or GPU memory is supported.
return frame && frame->IsMappable() && return frame && (frame->IsMappable() || frame->HasGpuMemoryBuffer()) &&
frame->format() == media::PIXEL_FORMAT_I420 && ((frame->format() == media::PIXEL_FORMAT_I420 &&
frame->layout().num_planes() == 3; frame->layout().num_planes() == 3) ||
(frame->format() == media::PIXEL_FORMAT_NV12 &&
frame->layout().num_planes() == 2));
} }
String VideoFrame::format() const { String VideoFrame::format() const {
...@@ -233,6 +235,8 @@ String VideoFrame::format() const { ...@@ -233,6 +235,8 @@ String VideoFrame::format() const {
switch (local_frame->format()) { switch (local_frame->format()) {
case media::PIXEL_FORMAT_I420: case media::PIXEL_FORMAT_I420:
return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kI420); return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kI420);
case media::PIXEL_FORMAT_NV12:
return V8VideoPixelFormat(V8VideoPixelFormat::Enum::kNV12);
default: default:
NOTREACHED(); NOTREACHED();
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
// https://github.com/WICG/web-codecs // https://github.com/WICG/web-codecs
enum VideoPixelFormat { enum VideoPixelFormat {
// 4:2:0 subsampled planar YUV // 4:2:0 subsampled 3 plane Y,U,V
"I420" "I420",
// 4:2:0 subsampled 2 plane Y,UV
"NV12",
}; };
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