Skip to content

Commit

Permalink
MacDesktopCaptureV2: Add cast support for NV12 IOSurfaces
Browse files Browse the repository at this point in the history
In mirroring::VideoCaptureClient, accept GpuMemoryBuffer backed
frames on macOS. These are handled by WrapUnacceleratedIOSurface,
which will allow CPU access (only) to the frames.

Also in mirroring::VideoCaptureClient accept NV12 formats.

In media::cast::Vp8Encoder::Encode, add support for NV12 formats.
This support is already present in VpxVideoEncoder::Encode, and this
is a copy-paste of that code, with slightly different comments.

Bug: 1185388
Change-Id: I25669486b1addfdc276a2876eb702ee92e206c5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2782061
Reviewed-by: mark a. foltz <mfoltz@chromium.org>
Commit-Queue: ccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#866001}
  • Loading branch information
ccameron-chromium authored and Chromium LUCI CQ committed Mar 24, 2021
1 parent 46fdf64 commit 6ced0c8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 16 deletions.
24 changes: 22 additions & 2 deletions components/mirroring/service/video_capture_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/no_destructor.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/video_frame.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
Expand Down Expand Up @@ -123,8 +124,15 @@ void VideoCaptureClient::OnNewBuffer(

if (!buffer_handle->is_read_only_shmem_region() &&
!buffer_handle->is_shared_buffer_handle()) {
#if defined(OS_MAC)
if (!buffer_handle->is_gpu_memory_buffer_handle()) {
NOTIMPLEMENTED();
return;
}
#else
NOTIMPLEMENTED();
return;
#endif
}
const auto insert_result = client_buffers_.emplace(
std::make_pair(buffer_id, std::move(buffer_handle)));
Expand All @@ -145,7 +153,8 @@ void VideoCaptureClient::OnBufferReady(
scaled_buffers.clear();

bool consume_buffer = !frame_deliver_callback_.is_null();
if (buffer->info->pixel_format != media::PIXEL_FORMAT_I420 &&
if (buffer->info->pixel_format != media::PIXEL_FORMAT_NV12 &&
buffer->info->pixel_format != media::PIXEL_FORMAT_I420 &&
buffer->info->pixel_format != media::PIXEL_FORMAT_Y16) {
consume_buffer = false;
LOG(DFATAL) << "Wrong pixel format, got pixel format:"
Expand Down Expand Up @@ -182,7 +191,18 @@ void VideoCaptureClient::OnBufferReady(
}
scoped_refptr<media::VideoFrame> frame;
BufferFinishedCallback buffer_finished_callback;
if (buffer_iter->second->is_shared_buffer_handle()) {
if (buffer_iter->second->is_gpu_memory_buffer_handle()) {
#if defined(OS_MAC)
frame = media::VideoFrame::WrapUnacceleratedIOSurface(
buffer_iter->second->get_gpu_memory_buffer_handle().Clone(),
buffer->info->visible_rect, buffer->info->timestamp);
buffer_finished_callback = media::BindToCurrentLoop(base::BindOnce(
&VideoCaptureClient::OnClientBufferFinished, weak_factory_.GetWeakPtr(),
buffer->buffer_id, base::ReadOnlySharedMemoryMapping()));
#else
NOTREACHED();
#endif
} else if (buffer_iter->second->is_shared_buffer_handle()) {
// TODO(crbug.com/843117): Remove this case after migrating
// media::VideoCaptureDeviceClient to the new shared memory API.
auto mapping_iter = mapped_buffers_.find(buffer->buffer_id);
Expand Down
46 changes: 32 additions & 14 deletions media/cast/sender/vp8_encoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -202,24 +202,42 @@ void Vp8Encoder::Encode(scoped_refptr<media::VideoFrame> video_frame,

// Wrapper for vpx_codec_encode() to access the YUV data in the |video_frame|.
// Only the VISIBLE rectangle within |video_frame| is exposed to the codec.
vpx_img_fmt_t vpx_format = video_frame->format() == PIXEL_FORMAT_NV12
? VPX_IMG_FMT_NV12
: VPX_IMG_FMT_I420;
vpx_image_t vpx_image;
vpx_image_t* const result = vpx_img_wrap(
&vpx_image,
VPX_IMG_FMT_I420,
frame_size.width(),
frame_size.height(),
1,
&vpx_image, vpx_format, frame_size.width(), frame_size.height(), 1,
video_frame->data(VideoFrame::kYPlane));
DCHECK_EQ(result, &vpx_image);
vpx_image.planes[VPX_PLANE_Y] =
video_frame->visible_data(VideoFrame::kYPlane);
vpx_image.planes[VPX_PLANE_U] =
video_frame->visible_data(VideoFrame::kUPlane);
vpx_image.planes[VPX_PLANE_V] =
video_frame->visible_data(VideoFrame::kVPlane);
vpx_image.stride[VPX_PLANE_Y] = video_frame->stride(VideoFrame::kYPlane);
vpx_image.stride[VPX_PLANE_U] = video_frame->stride(VideoFrame::kUPlane);
vpx_image.stride[VPX_PLANE_V] = video_frame->stride(VideoFrame::kVPlane);
switch (vpx_format) {
case VPX_IMG_FMT_I420:
vpx_image.planes[VPX_PLANE_Y] =
video_frame->visible_data(VideoFrame::kYPlane);
vpx_image.planes[VPX_PLANE_U] =
video_frame->visible_data(VideoFrame::kUPlane);
vpx_image.planes[VPX_PLANE_V] =
video_frame->visible_data(VideoFrame::kVPlane);
vpx_image.stride[VPX_PLANE_Y] = video_frame->stride(VideoFrame::kYPlane);
vpx_image.stride[VPX_PLANE_U] = video_frame->stride(VideoFrame::kUPlane);
vpx_image.stride[VPX_PLANE_V] = video_frame->stride(VideoFrame::kVPlane);
break;
case VPX_IMG_FMT_NV12:
vpx_image.planes[VPX_PLANE_Y] =
video_frame->visible_data(VideoFrame::kYPlane);
// In libvpx, the UV plane of NV12 frames is represented by two planes
// with the same stride, shifted by one byte.
vpx_image.planes[VPX_PLANE_U] =
video_frame->visible_data(VideoFrame::kUVPlane);
vpx_image.planes[VPX_PLANE_V] = vpx_image.planes[VPX_PLANE_U] + 1;
vpx_image.stride[VPX_PLANE_Y] = video_frame->stride(VideoFrame::kYPlane);
vpx_image.stride[VPX_PLANE_U] = video_frame->stride(VideoFrame::kUVPlane);
vpx_image.stride[VPX_PLANE_V] = video_frame->stride(VideoFrame::kUVPlane);
break;
default:
NOTREACHED();
break;
}

// The frame duration given to the VP8 codec affects a number of important
// behaviors, including: per-frame bandwidth, CPU time spent encoding,
Expand Down

0 comments on commit 6ced0c8

Please sign in to comment.