Commit dbd2aa88 authored by Ricky Liang's avatar Ricky Liang Committed by Commit Bot

Video capture with GpuMemoryBuffer - ImageCapture.grabFrame()

This CL enables the blink ImageCapture.grabFrame() implementatio to grab
video frames backed by GpuMemoryBuffer.

Bug: 982201
Test: https://googlechrome.github.io/samples/image-capture/grab-frame-take-photo.html
Change-Id: I9eada1924aaeffd447f55140cd0a166e88f9582e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1864759Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Commit-Queue: Ricky Liang <jcliang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708886}
parent 48c65805
...@@ -6,4 +6,5 @@ include_rules = [ ...@@ -6,4 +6,5 @@ include_rules = [
"+skia/ext/platform_canvas.h", "+skia/ext/platform_canvas.h",
"+third_party/libyuv", "+third_party/libyuv",
"+third_party/skia/include/core", "+third_party/skia/include/core",
"+ui/gfx/gpu_memory_buffer.h",
] ]
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "third_party/libyuv/include/libyuv.h" #include "third_party/libyuv/include/libyuv.h"
#include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/gpu_memory_buffer.h"
namespace WTF { namespace WTF {
// Template specialization of [1], needed to be able to pass callbacks // Template specialization of [1], needed to be able to pass callbacks
...@@ -79,7 +80,8 @@ void ImageCaptureFrameGrabber::SingleShotFrameHandler::OnVideoFrameOnIOThread( ...@@ -79,7 +80,8 @@ void ImageCaptureFrameGrabber::SingleShotFrameHandler::OnVideoFrameOnIOThread(
scoped_refptr<media::VideoFrame> frame, scoped_refptr<media::VideoFrame> frame,
base::TimeTicks /* current_time */) { base::TimeTicks /* current_time */) {
DCHECK(frame->format() == media::PIXEL_FORMAT_I420 || DCHECK(frame->format() == media::PIXEL_FORMAT_I420 ||
frame->format() == media::PIXEL_FORMAT_I420A); frame->format() == media::PIXEL_FORMAT_I420A ||
frame->format() == media::PIXEL_FORMAT_NV12);
if (first_frame_received_) if (first_frame_received_)
return; return;
...@@ -107,25 +109,68 @@ void ImageCaptureFrameGrabber::SingleShotFrameHandler::OnVideoFrameOnIOThread( ...@@ -107,25 +109,68 @@ void ImageCaptureFrameGrabber::SingleShotFrameHandler::OnVideoFrameOnIOThread(
const uint32_t destination_pixel_format = const uint32_t destination_pixel_format =
(kN32_SkColorType == kRGBA_8888_SkColorType) ? libyuv::FOURCC_ABGR (kN32_SkColorType == kRGBA_8888_SkColorType) ? libyuv::FOURCC_ABGR
: libyuv::FOURCC_ARGB; : libyuv::FOURCC_ARGB;
uint8_t* destination_plane = static_cast<uint8_t*>(pixmap.writable_addr());
libyuv::ConvertFromI420(frame->visible_data(media::VideoFrame::kYPlane), int destination_stride = pixmap.width() * 4;
frame->stride(media::VideoFrame::kYPlane), int destination_width = pixmap.width();
frame->visible_data(media::VideoFrame::kUPlane), int destination_height = pixmap.height();
frame->stride(media::VideoFrame::kUPlane),
frame->visible_data(media::VideoFrame::kVPlane), if (frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
frame->stride(media::VideoFrame::kVPlane), auto* gmb = frame->GetGpuMemoryBuffer();
static_cast<uint8_t*>(pixmap.writable_addr()), if (!gmb->Map()) {
pixmap.width() * 4, pixmap.width(), pixmap.height(), DLOG(ERROR) << "Error mapping GpuMemoryBuffer video frame";
destination_pixel_format); std::move(wrapper_callback).Run(sk_sp<SkImage>());
return;
if (frame->format() == media::PIXEL_FORMAT_I420A) { }
DCHECK(!info.isOpaque());
// This function copies any plane into the alpha channel of an ARGB image. // NV12 is the only supported pixel format at the moment.
libyuv::ARGBCopyYToAlpha(frame->visible_data(media::VideoFrame::kAPlane), DCHECK_EQ(frame->format(), media::PIXEL_FORMAT_NV12);
frame->stride(media::VideoFrame::kAPlane), int y_stride = gmb->stride(0);
static_cast<uint8_t*>(pixmap.writable_addr()), int uv_stride = gmb->stride(1);
pixmap.width() * 4, pixmap.width(), const uint8_t* y_plane =
pixmap.height()); (static_cast<uint8_t*>(gmb->memory(0)) + frame->visible_rect().x() +
(frame->visible_rect().y() * y_stride));
// UV plane of NV12 has 2-byte pixel width, with half chroma subsampling
// both horizontally and vertically.
const uint8_t* uv_plane = (static_cast<uint8_t*>(gmb->memory(1)) +
((frame->visible_rect().x() * 2) / 2) +
((frame->visible_rect().y() / 2) * uv_stride));
switch (destination_pixel_format) {
case libyuv::FOURCC_ABGR:
libyuv::NV12ToABGR(y_plane, y_stride, uv_plane, uv_stride,
destination_plane, destination_stride,
destination_width, destination_height);
break;
case libyuv::FOURCC_ARGB:
libyuv::NV12ToARGB(y_plane, y_stride, uv_plane, uv_stride,
destination_plane, destination_stride,
destination_width, destination_height);
break;
default:
NOTREACHED();
}
gmb->Unmap();
} else {
DCHECK(frame->format() == media::PIXEL_FORMAT_I420 ||
frame->format() == media::PIXEL_FORMAT_I420A);
libyuv::ConvertFromI420(frame->visible_data(media::VideoFrame::kYPlane),
frame->stride(media::VideoFrame::kYPlane),
frame->visible_data(media::VideoFrame::kUPlane),
frame->stride(media::VideoFrame::kUPlane),
frame->visible_data(media::VideoFrame::kVPlane),
frame->stride(media::VideoFrame::kVPlane),
destination_plane, destination_stride,
destination_width, destination_height,
destination_pixel_format);
if (frame->format() == media::PIXEL_FORMAT_I420A) {
DCHECK(!info.isOpaque());
// This function copies any plane into the alpha channel of an ARGB image.
libyuv::ARGBCopyYToAlpha(frame->visible_data(media::VideoFrame::kAPlane),
frame->stride(media::VideoFrame::kAPlane),
destination_plane, destination_stride,
destination_width, destination_height);
}
} }
std::move(wrapper_callback).Run(surface->makeImageSnapshot()); std::move(wrapper_callback).Run(surface->makeImageSnapshot());
......
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