Commit 422d099e authored by andresantoso's avatar andresantoso Committed by Commit bot

Add support for converting I420 software frames into NV12 hardware frames

Enhance MaybeCreateHardwareFrame() to be able to create a NV12 hardware
frame backed by a YUV_420_BIPLANAR GpuMemoryBuffer.

This code path is not enabled yet.

BUG=524582
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1307853003

Cr-Commit-Position: refs/heads/master@{#347864}
parent 995e9645
...@@ -25,6 +25,49 @@ namespace { ...@@ -25,6 +25,49 @@ namespace {
const ResourceFormat kRGBResourceFormat = RGBA_8888; const ResourceFormat kRGBResourceFormat = RGBA_8888;
VideoFrameExternalResources::ResourceType ResourceTypeForVideoFrame(
media::VideoFrame* video_frame) {
switch (video_frame->format()) {
case media::PIXEL_FORMAT_ARGB:
case media::PIXEL_FORMAT_XRGB:
case media::PIXEL_FORMAT_UYVY:
switch (video_frame->mailbox_holder(0).texture_target) {
case GL_TEXTURE_2D:
return (video_frame->format() == media::PIXEL_FORMAT_XRGB)
? VideoFrameExternalResources::RGB_RESOURCE
: VideoFrameExternalResources::RGBA_RESOURCE;
case GL_TEXTURE_EXTERNAL_OES:
return VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
case GL_TEXTURE_RECTANGLE_ARB:
return VideoFrameExternalResources::IO_SURFACE;
default:
NOTREACHED();
break;
}
break;
case media::PIXEL_FORMAT_I420:
return VideoFrameExternalResources::YUV_RESOURCE;
break;
case media::PIXEL_FORMAT_NV12:
DCHECK_EQ(static_cast<uint32_t>(GL_TEXTURE_RECTANGLE_ARB),
video_frame->mailbox_holder(0).texture_target);
return VideoFrameExternalResources::IO_SURFACE;
break;
case media::PIXEL_FORMAT_YV12:
case media::PIXEL_FORMAT_YV16:
case media::PIXEL_FORMAT_YV24:
case media::PIXEL_FORMAT_YV12A:
case media::PIXEL_FORMAT_NV21:
case media::PIXEL_FORMAT_YUY2:
case media::PIXEL_FORMAT_RGB24:
case media::PIXEL_FORMAT_RGB32:
case media::PIXEL_FORMAT_MJPEG:
case media::PIXEL_FORMAT_UNKNOWN:
break;
}
return VideoFrameExternalResources::NONE;
}
class SyncPointClientImpl : public media::VideoFrame::SyncPointClient { class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
public: public:
explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl, explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl,
...@@ -375,56 +418,21 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( ...@@ -375,56 +418,21 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
if (!context_provider_) if (!context_provider_)
return VideoFrameExternalResources(); return VideoFrameExternalResources();
const size_t textures = media::VideoFrame::NumPlanes(video_frame->format());
DCHECK_GE(textures, 1u);
VideoFrameExternalResources external_resources; VideoFrameExternalResources external_resources;
external_resources.read_lock_fences_enabled = true; external_resources.read_lock_fences_enabled = true;
switch (video_frame->format()) {
case media::PIXEL_FORMAT_ARGB: external_resources.type = ResourceTypeForVideoFrame(video_frame.get());
case media::PIXEL_FORMAT_XRGB: if (external_resources.type == VideoFrameExternalResources::NONE) {
case media::PIXEL_FORMAT_UYVY: DLOG(ERROR) << "Unsupported Texture format"
DCHECK_EQ(1u, textures); << media::VideoPixelFormatToString(video_frame->format());
switch (video_frame->mailbox_holder(0).texture_target) { return external_resources;
case GL_TEXTURE_2D:
external_resources.type =
(video_frame->format() == media::PIXEL_FORMAT_XRGB)
? VideoFrameExternalResources::RGB_RESOURCE
: VideoFrameExternalResources::RGBA_RESOURCE;
break;
case GL_TEXTURE_EXTERNAL_OES:
external_resources.type =
VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
break;
case GL_TEXTURE_RECTANGLE_ARB:
external_resources.type = VideoFrameExternalResources::IO_SURFACE;
break;
default:
NOTREACHED();
return VideoFrameExternalResources();
}
break;
case media::PIXEL_FORMAT_I420:
external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
break;
case media::PIXEL_FORMAT_YV12:
case media::PIXEL_FORMAT_YV16:
case media::PIXEL_FORMAT_YV24:
case media::PIXEL_FORMAT_YV12A:
case media::PIXEL_FORMAT_NV12:
case media::PIXEL_FORMAT_NV21:
case media::PIXEL_FORMAT_YUY2:
case media::PIXEL_FORMAT_RGB24:
case media::PIXEL_FORMAT_RGB32:
case media::PIXEL_FORMAT_MJPEG:
case media::PIXEL_FORMAT_UNKNOWN:
DLOG(ERROR) << "Unsupported Texture format"
<< media::VideoPixelFormatToString(video_frame->format());
return external_resources;
} }
DCHECK_NE(VideoFrameExternalResources::NONE, external_resources.type);
for (size_t i = 0; i < textures; ++i) { const size_t num_planes = media::VideoFrame::NumPlanes(video_frame->format());
for (size_t i = 0; i < num_planes; ++i) {
const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i); const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
if (mailbox_holder.mailbox.IsZero())
break;
external_resources.mailboxes.push_back( external_resources.mailboxes.push_back(
TextureMailbox(mailbox_holder.mailbox, mailbox_holder.texture_target, TextureMailbox(mailbox_holder.mailbox, mailbox_holder.texture_target,
mailbox_holder.sync_point, video_frame->coded_size(), mailbox_holder.sync_point, video_frame->coded_size(),
......
...@@ -220,7 +220,9 @@ scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( ...@@ -220,7 +220,9 @@ scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
const gfx::Rect& visible_rect, const gfx::Rect& visible_rect,
const gfx::Size& natural_size, const gfx::Size& natural_size,
base::TimeDelta timestamp) { base::TimeDelta timestamp) {
if (format != PIXEL_FORMAT_ARGB && format != PIXEL_FORMAT_UYVY) { if (format != PIXEL_FORMAT_ARGB &&
format != PIXEL_FORMAT_UYVY &&
format != PIXEL_FORMAT_NV12) {
DLOG(ERROR) << "Unsupported pixel format supported, got " DLOG(ERROR) << "Unsupported pixel format supported, got "
<< VideoPixelFormatToString(format); << VideoPixelFormatToString(format);
return nullptr; return nullptr;
......
...@@ -137,6 +137,7 @@ skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative( ...@@ -137,6 +137,7 @@ skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative(
VideoFrame* video_frame, VideoFrame* video_frame,
const Context3D& context_3d) { const Context3D& context_3d) {
DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
PIXEL_FORMAT_NV12 == video_frame->format() ||
PIXEL_FORMAT_UYVY == video_frame->format()); PIXEL_FORMAT_UYVY == video_frame->format());
const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "media/renderers/mock_gpu_video_accelerator_factories.h" #include "media/renderers/mock_gpu_video_accelerator_factories.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/gpu_memory_buffer.h"
namespace media { namespace media {
...@@ -13,16 +14,23 @@ namespace { ...@@ -13,16 +14,23 @@ namespace {
class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
public: public:
GpuMemoryBufferImpl(const gfx::Size& size, gfx::BufferFormat format) GpuMemoryBufferImpl(const gfx::Size& size, gfx::BufferFormat format)
: format_(format), size_(size) { : format_(format), size_(size),
num_planes_(gfx::NumberOfPlanesForBufferFormat(format)) {
DCHECK(gfx::BufferFormat::R_8 == format_ || DCHECK(gfx::BufferFormat::R_8 == format_ ||
gfx::BufferFormat::YUV_420_BIPLANAR == format_ ||
gfx::BufferFormat::UYVY_422 == format_); gfx::BufferFormat::UYVY_422 == format_);
bytes_.resize(size_.GetArea() * DCHECK(num_planes_ <= kMaxPlanes);
(format_ == gfx::BufferFormat::UYVY_422 ? 2 : 1)); for (int i = 0; i < static_cast<int>(num_planes_); ++i) {
bytes_[i].resize(
gfx::RowSizeForBufferFormat(size_.width(), format_, i) *
size_.height() / gfx::SubsamplingFactorForBufferFormat(format_, i));
}
} }
// Overridden from gfx::GpuMemoryBuffer: // Overridden from gfx::GpuMemoryBuffer:
bool Map(void** data) override { bool Map(void** data) override {
data[0] = &bytes_[0]; for (size_t plane = 0; plane < num_planes_; ++plane)
data[plane] = &bytes_[plane][0];
return true; return true;
} }
void Unmap() override{}; void Unmap() override{};
...@@ -31,12 +39,13 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { ...@@ -31,12 +39,13 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
return false; return false;
} }
gfx::BufferFormat GetFormat() const override { gfx::BufferFormat GetFormat() const override {
NOTREACHED(); return format_;
return gfx::BufferFormat::R_8;
} }
void GetStride(int* stride) const override { void GetStride(int* strides) const override {
stride[0] = for (int plane = 0; plane < static_cast<int>(num_planes_); ++plane) {
size_.width() * (format_ == gfx::BufferFormat::UYVY_422 ? 2 : 1); strides[plane] = static_cast<int>(
gfx::RowSizeForBufferFormat(size_.width(), format_, plane));
}
} }
gfx::GpuMemoryBufferId GetId() const override { gfx::GpuMemoryBufferId GetId() const override {
NOTREACHED(); NOTREACHED();
...@@ -51,9 +60,12 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { ...@@ -51,9 +60,12 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
} }
private: private:
static const size_t kMaxPlanes = 3;
gfx::BufferFormat format_; gfx::BufferFormat format_;
std::vector<unsigned char> bytes_;
const gfx::Size size_; const gfx::Size size_;
size_t num_planes_;
std::vector<uint8> bytes_[kMaxPlanes];
}; };
} // unnamed namespace } // unnamed namespace
......
...@@ -161,6 +161,9 @@ gfx::BufferFormat GpuMemoryBufferFormat(VideoPixelFormat format, size_t plane) { ...@@ -161,6 +161,9 @@ gfx::BufferFormat GpuMemoryBufferFormat(VideoPixelFormat format, size_t plane) {
case PIXEL_FORMAT_I420: case PIXEL_FORMAT_I420:
DCHECK_LE(plane, 2u); DCHECK_LE(plane, 2u);
return gfx::BufferFormat::R_8; return gfx::BufferFormat::R_8;
case PIXEL_FORMAT_NV12:
DCHECK_LE(plane, 1u);
return gfx::BufferFormat::YUV_420_BIPLANAR;
case PIXEL_FORMAT_UYVY: case PIXEL_FORMAT_UYVY:
DCHECK_EQ(0u, plane); DCHECK_EQ(0u, plane);
return gfx::BufferFormat::UYVY_422; return gfx::BufferFormat::UYVY_422;
...@@ -175,6 +178,10 @@ unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) { ...@@ -175,6 +178,10 @@ unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) {
case PIXEL_FORMAT_I420: case PIXEL_FORMAT_I420:
DCHECK_LE(plane, 2u); DCHECK_LE(plane, 2u);
return GL_R8_EXT; return GL_R8_EXT;
case PIXEL_FORMAT_NV12:
DCHECK_LE(plane, 1u);
DLOG(WARNING) << "NV12 format not supported yet";
return 0; // TODO(andresantoso): Implement extension for NV12.
case PIXEL_FORMAT_UYVY: case PIXEL_FORMAT_UYVY:
DCHECK_EQ(0u, plane); DCHECK_EQ(0u, plane);
return GL_RGB_YCBCR_422_CHROMIUM; return GL_RGB_YCBCR_422_CHROMIUM;
...@@ -184,6 +191,31 @@ unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) { ...@@ -184,6 +191,31 @@ unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) {
} }
} }
// The number of output planes to be copied in each iteration.
size_t PlanesPerCopy(VideoPixelFormat format) {
switch (format) {
case PIXEL_FORMAT_I420:
case PIXEL_FORMAT_UYVY:
return 1;
case PIXEL_FORMAT_NV12:
return 2;
default:
NOTREACHED();
return 0;
}
}
// The number of output rows to be copied in each iteration.
int RowsPerCopy(size_t plane, VideoPixelFormat format, int width) {
int bytes_per_row = VideoFrame::RowBytes(plane, format, width);
if (format == PIXEL_FORMAT_NV12) {
DCHECK_EQ(0u, plane);
bytes_per_row += VideoFrame::RowBytes(1, format, width);
}
// Copy an even number of lines, and at least one.
return std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1);
}
void CopyRowsToI420Buffer(int first_row, void CopyRowsToI420Buffer(int first_row,
int rows, int rows,
int bytes_per_row, int bytes_per_row,
...@@ -204,6 +236,38 @@ void CopyRowsToI420Buffer(int first_row, ...@@ -204,6 +236,38 @@ void CopyRowsToI420Buffer(int first_row,
done.Run(); done.Run();
} }
void CopyRowsToNV12Buffer(int first_row,
int rows,
int bytes_per_row,
const scoped_refptr<VideoFrame>& source_frame,
uint8* dest_y,
int dest_stride_y,
uint8* dest_uv,
int dest_stride_uv,
const base::Closure& done) {
TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "bytes_per_row", bytes_per_row,
"rows", rows);
DCHECK_NE(dest_stride_y, 0);
DCHECK_NE(dest_stride_uv, 0);
DCHECK_LE(bytes_per_row, std::abs(dest_stride_y));
DCHECK_LE(bytes_per_row, std::abs(dest_stride_uv));
DCHECK_EQ(0, first_row % 2);
libyuv::I420ToNV12(
source_frame->data(VideoFrame::kYPlane) +
first_row * source_frame->stride(VideoFrame::kYPlane),
source_frame->stride(VideoFrame::kYPlane),
source_frame->data(VideoFrame::kUPlane) +
first_row / 2 * source_frame->stride(VideoFrame::kUPlane),
source_frame->stride(VideoFrame::kUPlane),
source_frame->data(VideoFrame::kVPlane) +
first_row / 2 * source_frame->stride(VideoFrame::kVPlane),
source_frame->stride(VideoFrame::kVPlane),
dest_y + first_row * dest_stride_y, dest_stride_y,
dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv,
bytes_per_row, rows);
done.Run();
}
void CopyRowsToUYVYBuffer(int first_row, void CopyRowsToUYVYBuffer(int first_row,
int rows, int rows,
int width, int width,
...@@ -298,9 +362,9 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( ...@@ -298,9 +362,9 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone(
const scoped_refptr<VideoFrame>& video_frame, const scoped_refptr<VideoFrame>& video_frame,
FrameResources* frame_resources, FrameResources* frame_resources,
const FrameReadyCB& frame_ready_cb) { const FrameReadyCB& frame_ready_cb) {
const size_t planes = VideoFrame::NumPlanes(output_format_); for (const auto& plane_resource : frame_resources->plane_resources) {
for (size_t i = 0; i < planes; ++i) { if (plane_resource.gpu_memory_buffer)
frame_resources->plane_resources[i].gpu_memory_buffer->Unmap(); plane_resource.gpu_memory_buffer->Unmap();
} }
media_task_runner_->PostTask( media_task_runner_->PostTask(
...@@ -317,15 +381,13 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( ...@@ -317,15 +381,13 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
FrameResources* frame_resources, FrameResources* frame_resources,
const FrameReadyCB& frame_ready_cb) { const FrameReadyCB& frame_ready_cb) {
// Compute the number of tasks to post and create the barrier. // Compute the number of tasks to post and create the barrier.
const size_t dest_planes = VideoFrame::NumPlanes(output_format_); const size_t num_planes = VideoFrame::NumPlanes(output_format_);
const size_t planes_per_copy = PlanesPerCopy(output_format_);
gfx::Size size = video_frame->visible_rect().size(); gfx::Size size = video_frame->visible_rect().size();
size_t copies = 0; size_t copies = 0;
for (size_t i = 0; i < dest_planes; ++i) { for (size_t i = 0; i < num_planes; i += planes_per_copy) {
int rows = VideoFrame::Rows(i, output_format_, size.height()); const int rows = VideoFrame::Rows(i, output_format_, size.height());
int bytes_per_row = VideoFrame::RowBytes(i, output_format_, size.width()); const int rows_per_copy = RowsPerCopy(i, output_format_, size.width());
// Copy a even number of lines, and at least one.
int rows_per_copy =
std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1);
copies += rows / rows_per_copy; copies += rows / rows_per_copy;
if (rows % rows_per_copy) if (rows % rows_per_copy)
++copies; ++copies;
...@@ -334,40 +396,51 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( ...@@ -334,40 +396,51 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources,
frame_ready_cb); frame_ready_cb);
base::Closure barrier = base::BarrierClosure(copies, copies_done); base::Closure barrier = base::BarrierClosure(copies, copies_done);
// Post all the async tasks. // Post all the async tasks.
for (size_t i = 0; i < dest_planes; ++i) { for (size_t i = 0; i < num_planes; i += planes_per_copy) {
int rows = VideoFrame::Rows(i, output_format_, size.height()); gfx::GpuMemoryBuffer* buffer =
int bytes_per_row = VideoFrame::RowBytes(i, output_format_, size.width()); frame_resources->plane_resources[i].gpu_memory_buffer.get();
int rows_per_copy = DCHECK(buffer);
std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1); DCHECK_EQ(planes_per_copy,
gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat()));
void* data = nullptr; uint8* dest_buffers[VideoFrame::kMaxPlanes];
DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat( int dest_strides[VideoFrame::kMaxPlanes];
GpuMemoryBufferFormat(output_format_, i))); bool rv = buffer->Map(reinterpret_cast<void**>(dest_buffers));
bool rv = frame_resources->plane_resources[i].gpu_memory_buffer->Map(&data);
DCHECK(rv); DCHECK(rv);
uint8* mapped_buffer = static_cast<uint8*>(data); buffer->GetStride(dest_strides);
int dest_stride = 0; const int rows = VideoFrame::Rows(i, output_format_, size.height());
frame_resources->plane_resources[i].gpu_memory_buffer->GetStride( const int rows_per_copy = RowsPerCopy(i, output_format_, size.width());
&dest_stride);
for (int row = 0; row < rows; row += rows_per_copy) { for (int row = 0; row < rows; row += rows_per_copy) {
const int rows_to_copy = std::min(rows_per_copy, rows - row);
switch (output_format_) { switch (output_format_) {
case PIXEL_FORMAT_I420: case PIXEL_FORMAT_I420: {
const int bytes_per_row =
VideoFrame::RowBytes(i, output_format_, size.width());
worker_task_runner_->PostTask( worker_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&CopyRowsToI420Buffer, row, base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy,
std::min(rows_per_copy, rows - row), bytes_per_row, bytes_per_row, video_frame->data(i),
video_frame->data(i), video_frame->stride(i), video_frame->stride(i), dest_buffers[0],
mapped_buffer, dest_stride, barrier)); dest_strides[0], barrier));
break;
}
case PIXEL_FORMAT_NV12:
worker_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CopyRowsToNV12Buffer, row, rows_to_copy,
size.width(), video_frame, dest_buffers[0],
dest_strides[0], dest_buffers[1], dest_strides[1],
barrier));
break; break;
case PIXEL_FORMAT_UYVY: case PIXEL_FORMAT_UYVY:
worker_task_runner_->PostTask( worker_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&CopyRowsToUYVYBuffer, row, base::Bind(&CopyRowsToUYVYBuffer, row, rows_to_copy, size.width(),
std::min(rows_per_copy, rows - row), size.width(), video_frame, dest_buffers[0], dest_strides[0],
video_frame, mapped_buffer, dest_stride, barrier)); barrier));
break; break;
default: default:
NOTREACHED(); NOTREACHED();
...@@ -387,16 +460,18 @@ void GpuMemoryBufferVideoFramePool::PoolImpl:: ...@@ -387,16 +460,18 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
return; return;
} }
const size_t planes = VideoFrame::NumPlanes(output_format_); const size_t num_planes = VideoFrame::NumPlanes(output_format_);
const size_t planes_per_copy = PlanesPerCopy(output_format_);
const gfx::Size size = video_frame->visible_rect().size(); const gfx::Size size = video_frame->visible_rect().size();
gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
// Set up the planes creating the mailboxes needed to refer to the textures. // Set up the planes creating the mailboxes needed to refer to the textures.
for (size_t i = 0; i < planes; ++i) { for (size_t i = 0; i < num_planes; i += planes_per_copy) {
PlaneResource& plane_resource = frame_resources->plane_resources[i]; PlaneResource& plane_resource = frame_resources->plane_resources[i];
DCHECK(plane_resource.gpu_memory_buffer);
// Bind the texture and create or rebind the image. // Bind the texture and create or rebind the image.
gles2->BindTexture(texture_target_, plane_resource.texture_id); gles2->BindTexture(texture_target_, plane_resource.texture_id);
if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { if (!plane_resource.image_id) {
const size_t width = VideoFrame::Columns(i, output_format_, size.width()); const size_t width = VideoFrame::Columns(i, output_format_, size.width());
const size_t height = VideoFrame::Rows(i, output_format_, size.height()); const size_t height = VideoFrame::Rows(i, output_format_, size.height());
plane_resource.image_id = gles2->CreateImageCHROMIUM( plane_resource.image_id = gles2->CreateImageCHROMIUM(
...@@ -415,9 +490,8 @@ void GpuMemoryBufferVideoFramePool::PoolImpl:: ...@@ -415,9 +490,8 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
// mailboxes refer to will be used only after all the previous commands posted // mailboxes refer to will be used only after all the previous commands posted
// in the command buffer have been processed. // in the command buffer have been processed.
unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); unsigned sync_point = gles2->InsertSyncPointCHROMIUM();
for (size_t i = 0; i < planes; ++i) { for (size_t i = 0; i < num_planes; i += planes_per_copy)
mailbox_holders[i].sync_point = sync_point; mailbox_holders[i].sync_point = sync_point;
}
scoped_refptr<VideoFrame> frame; scoped_refptr<VideoFrame> frame;
// Create the VideoFrame backed by native textures. // Create the VideoFrame backed by native textures.
...@@ -433,9 +507,10 @@ void GpuMemoryBufferVideoFramePool::PoolImpl:: ...@@ -433,9 +507,10 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY))
frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
break; break;
case PIXEL_FORMAT_NV12:
case PIXEL_FORMAT_UYVY: case PIXEL_FORMAT_UYVY:
frame = VideoFrame::WrapNativeTexture( frame = VideoFrame::WrapNativeTexture(
PIXEL_FORMAT_UYVY, mailbox_holders[VideoFrame::kYPlane], output_format_, mailbox_holders[VideoFrame::kYPlane],
base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources),
size, video_frame->visible_rect(), video_frame->natural_size(), size, video_frame->visible_rect(), video_frame->natural_size(),
video_frame->timestamp()); video_frame->timestamp());
...@@ -488,17 +563,18 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( ...@@ -488,17 +563,18 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
if (!gles2) if (!gles2)
return nullptr; return nullptr;
gles2->ActiveTexture(GL_TEXTURE0); gles2->ActiveTexture(GL_TEXTURE0);
size_t planes = VideoFrame::NumPlanes(format); size_t num_planes = VideoFrame::NumPlanes(format);
FrameResources* frame_resources = new FrameResources(size); FrameResources* frame_resources = new FrameResources(size);
resources_pool_.push_back(frame_resources); resources_pool_.push_back(frame_resources);
for (size_t i = 0; i < planes; ++i) { for (size_t i = 0; i < num_planes; i += PlanesPerCopy(format)) {
PlaneResource& plane_resource = frame_resources->plane_resources[i]; PlaneResource& plane_resource = frame_resources->plane_resources[i];
const size_t width = VideoFrame::Columns(i, format, size.width()); const size_t width = VideoFrame::Columns(i, format, size.width());
const size_t height = VideoFrame::Rows(i, format, size.height()); const size_t height = VideoFrame::Rows(i, format, size.height());
const gfx::Size plane_size(width, height); const gfx::Size plane_size(width, height);
const gfx::BufferFormat buffer_format = GpuMemoryBufferFormat(format, i);
plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer(
plane_size, GpuMemoryBufferFormat(format, i), gfx::BufferUsage::MAP); plane_size, buffer_format, gfx::BufferUsage::MAP);
gles2->GenTextures(1, &plane_resource.texture_id); gles2->GenTextures(1, &plane_resource.texture_id);
gles2->BindTexture(texture_target_, plane_resource.texture_id); gles2->BindTexture(texture_target_, plane_resource.texture_id);
......
...@@ -231,4 +231,26 @@ TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareUYUVFrame) { ...@@ -231,4 +231,26 @@ TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareUYUVFrame) {
EXPECT_EQ(1u, gles2_->gen_textures); EXPECT_EQ(1u, gles2_->gen_textures);
} }
TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareNV12Frame) {
scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10);
scoped_refptr<MockGpuVideoAcceleratorFactories> mock_gpu_factories(
new MockGpuVideoAcceleratorFactories);
mock_gpu_factories->SetVideoFrameOutputFormat(PIXEL_FORMAT_NV12);
scoped_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool_ =
make_scoped_ptr(new GpuMemoryBufferVideoFramePool(
media_task_runner_, copy_task_runner_.get(), mock_gpu_factories));
EXPECT_CALL(*mock_gpu_factories.get(), GetGLES2Interface())
.WillRepeatedly(testing::Return(gles2_.get()));
scoped_refptr<VideoFrame> frame;
gpu_memory_buffer_pool_->MaybeCreateHardwareFrame(
software_frame, base::Bind(MaybeCreateHardwareFrameCallback, &frame));
RunUntilIdle();
EXPECT_NE(software_frame.get(), frame.get());
EXPECT_EQ(1u, gles2_->gen_textures);
}
} // namespace media } // namespace media
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