Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Unified Diff: media/video/gpu_memory_buffer_video_frame_pool.cc

Issue 1306693002: media: Convert I420 VideoFrame to UYVY GpuMemoryBuffer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address reviewers' comments. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/video/gpu_memory_buffer_video_frame_pool.cc
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index a141be0d56d4e81f5bd630f477650071902a5fb5..dc58ce68f635d76f17bdd1fc4bffd8f7fcfda259 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -19,6 +19,8 @@
#include "base/trace_event/trace_event.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "media/renderers/gpu_video_accelerator_factories.h"
+#include "third_party/libyuv/include/libyuv.h"
+#include "ui/gfx/buffer_format_util.h"
namespace media {
@@ -40,7 +42,9 @@ class GpuMemoryBufferVideoFramePool::PoolImpl
worker_task_runner_(worker_task_runner),
gpu_factories_(gpu_factories),
texture_target_(gpu_factories ? gpu_factories->ImageTextureTarget()
- : GL_TEXTURE_2D) {
+ : GL_TEXTURE_2D),
+ output_format_(gpu_factories ? gpu_factories->VideoFrameOutputFormat()
+ : PIXEL_FORMAT_I420) {
DCHECK(media_task_runner_);
DCHECK(worker_task_runner_);
}
@@ -70,10 +74,8 @@ class GpuMemoryBufferVideoFramePool::PoolImpl
// All the resources needed to compose a frame.
struct FrameResources {
- FrameResources(VideoPixelFormat format, const gfx::Size& size)
- : format(format), size(size) {}
+ explicit FrameResources(const gfx::Size& size) : size(size) {}
bool in_use = true;
- VideoPixelFormat format;
gfx::Size size;
PlaneResource plane_resources[VideoFrame::kMaxPlanes];
};
@@ -102,9 +104,8 @@ class GpuMemoryBufferVideoFramePool::PoolImpl
// Return true if |resources| can be used to represent a frame for
// specific |format| and |size|.
static bool AreFrameResourcesCompatible(const FrameResources* resources,
- const gfx::Size& size,
- VideoPixelFormat format) {
- return size == resources->size && format == resources->format;
+ const gfx::Size& size) {
+ return size == resources->size;
}
// Get the resources needed for a frame out of the pool, or create them if
@@ -141,24 +142,56 @@ class GpuMemoryBufferVideoFramePool::PoolImpl
std::list<FrameResources*> resources_pool_;
const unsigned texture_target_;
+ const VideoPixelFormat output_format_;
+
DISALLOW_COPY_AND_ASSIGN(PoolImpl);
};
namespace {
-// VideoFrame copies to GpuMemoryBuffers will be split in |kBytesPerCopyTarget|
-// bytes copies and run in parallel.
+// VideoFrame copies to GpuMemoryBuffers will be split in copies where the
+// output size is |kBytesPerCopyTarget| bytes and run in parallel.
const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB
-void CopyRowsToBuffer(int first_row,
- int rows,
- int bytes_per_row,
- const uint8* source,
- int source_stride,
- uint8* output,
- int dest_stride,
- const base::Closure& done) {
- TRACE_EVENT2("media", "CopyRowsToBuffer", "bytes_per_row", bytes_per_row,
+// Return the GpuMemoryBuffer format to use for a specific VideoPixelFormat
+// and plane.
+gfx::BufferFormat GpuMemoryBufferFormat(VideoPixelFormat format, size_t plane) {
+ switch (format) {
+ case PIXEL_FORMAT_I420:
+ DCHECK_LE(plane, 2u);
+ return gfx::BufferFormat::R_8;
+ case PIXEL_FORMAT_UYVY:
+ DCHECK_EQ(0u, plane);
+ return gfx::BufferFormat::UYVY_422;
+ default:
+ NOTREACHED();
+ return gfx::BufferFormat::BGRA_8888;
+ }
+}
+
+unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) {
+ switch (format) {
+ case PIXEL_FORMAT_I420:
+ DCHECK_LE(plane, 2u);
+ return GL_R8_EXT;
+ case PIXEL_FORMAT_UYVY:
+ DCHECK_EQ(0u, plane);
+ return GL_RGB;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+void CopyRowsToI420Buffer(int first_row,
+ int rows,
+ int bytes_per_row,
+ const uint8* source,
+ int source_stride,
+ uint8* output,
+ int dest_stride,
+ const base::Closure& done) {
+ TRACE_EVENT2("media", "CopyRowsToI420Buffer", "bytes_per_row", bytes_per_row,
"rows", rows);
DCHECK_NE(dest_stride, 0);
DCHECK_LE(bytes_per_row, std::abs(dest_stride));
@@ -170,6 +203,32 @@ void CopyRowsToBuffer(int first_row,
done.Run();
}
+void CopyRowsToUYVYBuffer(int first_row,
+ int rows,
+ int width,
+ const scoped_refptr<VideoFrame>& source_frame,
+ uint8* output,
+ int dest_stride,
+ const base::Closure& done) {
+ TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width * 2,
+ "rows", rows);
+ DCHECK_NE(dest_stride, 0);
+ DCHECK_LE(width, std::abs(dest_stride / 2));
+ DCHECK_EQ(0, first_row % 2);
+ libyuv::I420ToUYVY(
+ 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),
+ output + first_row * dest_stride, dest_stride, width, rows);
+ done.Run();
+}
+
} // unnamed namespace
// Creates a VideoFrame backed by native textures starting from a software
@@ -181,7 +240,8 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
const scoped_refptr<VideoFrame>& video_frame,
const FrameReadyCB& frame_ready_cb) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
- if (!gpu_factories_ || !gpu_factories_->IsTextureRGSupported()) {
+ if (!gpu_factories_ || (output_format_ == PIXEL_FORMAT_I420 &&
+ !gpu_factories_->IsTextureRGSupported())) {
frame_ready_cb.Run(video_frame);
return;
}
@@ -203,12 +263,12 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
return;
}
- VideoPixelFormat format = video_frame->format();
DCHECK(video_frame->visible_rect().origin().IsOrigin());
const gfx::Size size = video_frame->visible_rect().size();
// Acquire resources. Incompatible ones will be dropped from the pool.
- FrameResources* frame_resources = GetOrCreateFrameResources(size, format);
+ FrameResources* frame_resources =
+ GetOrCreateFrameResources(size, output_format_);
if (!frame_resources) {
frame_ready_cb.Run(video_frame);
return;
@@ -223,8 +283,7 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone(
const scoped_refptr<VideoFrame>& video_frame,
FrameResources* frame_resources,
const FrameReadyCB& frame_ready_cb) {
- const VideoPixelFormat format = video_frame->format();
- const size_t planes = VideoFrame::NumPlanes(format);
+ const size_t planes = VideoFrame::NumPlanes(output_format_);
for (size_t i = 0; i < planes; ++i) {
frame_resources->plane_resources[i].gpu_memory_buffer->Unmap();
}
@@ -242,45 +301,62 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
const scoped_refptr<VideoFrame>& video_frame,
FrameResources* frame_resources,
const FrameReadyCB& frame_ready_cb) {
- const VideoPixelFormat format = video_frame->format();
- const size_t planes = VideoFrame::NumPlanes(format);
+ // Compute the number of tasks to post and create the barrier.
+ const size_t dest_planes = VideoFrame::NumPlanes(output_format_);
gfx::Size size = video_frame->visible_rect().size();
size_t copies = 0;
- for (size_t i = 0; i < planes; ++i) {
- int rows = VideoFrame::Rows(i, format, size.height());
- int bytes_per_row = VideoFrame::RowBytes(i, format, size.width());
+ for (size_t i = 0; i < dest_planes; ++i) {
+ int rows = VideoFrame::Rows(i, output_format_, size.height());
+ int bytes_per_row = VideoFrame::RowBytes(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);
+ std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1);
copies += rows / rows_per_copy;
if (rows % rows_per_copy)
++copies;
}
-
base::Closure copies_done =
base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources,
frame_ready_cb);
base::Closure barrier = base::BarrierClosure(copies, copies_done);
-
- for (size_t i = 0; i < planes; ++i) {
- int rows = VideoFrame::Rows(i, format, size.height());
- int bytes_per_row = VideoFrame::RowBytes(i, format, size.width());
+ // Post all the async tasks.
+ for (size_t i = 0; i < dest_planes; ++i) {
+ int rows = VideoFrame::Rows(i, output_format_, size.height());
+ int bytes_per_row = VideoFrame::RowBytes(i, output_format_, size.width());
int rows_per_copy =
- std::max<size_t>(kBytesPerCopyTarget / bytes_per_row, 1);
+ std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1);
- PlaneResource& plane_resource = frame_resources->plane_resources[i];
void* data = nullptr;
- CHECK(plane_resource.gpu_memory_buffer->Map(&data));
+ CHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(
+ GpuMemoryBufferFormat(output_format_, i)));
Avi (use Gerrit) 2015/08/21 21:32:03 DCHECK here too
Daniele Castagna 2015/08/21 21:37:08 Done.
+ bool rv = frame_resources->plane_resources[i].gpu_memory_buffer->Map(&data);
+ DCHECK(rv);
uint8* mapped_buffer = static_cast<uint8*>(data);
+
int dest_stride = 0;
- plane_resource.gpu_memory_buffer->GetStride(&dest_stride);
+ frame_resources->plane_resources[i].gpu_memory_buffer->GetStride(
+ &dest_stride);
for (int row = 0; row < rows; row += rows_per_copy) {
- worker_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&CopyRowsToBuffer, row,
- std::min(rows_per_copy, rows - row), bytes_per_row,
- video_frame->data(i), video_frame->stride(i),
- mapped_buffer, dest_stride, barrier));
+ switch (output_format_) {
+ case PIXEL_FORMAT_I420:
+ worker_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&CopyRowsToI420Buffer, row,
+ std::min(rows_per_copy, rows - row), bytes_per_row,
+ video_frame->data(i), video_frame->stride(i),
+ mapped_buffer, dest_stride, barrier));
+ break;
+ case PIXEL_FORMAT_UYVY:
+ worker_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&CopyRowsToUYVYBuffer, row,
+ std::min(rows_per_copy, rows - row), size.width(),
+ video_frame, mapped_buffer, dest_stride, barrier));
+ break;
+ default:
+ NOTREACHED();
+ }
}
}
}
@@ -296,8 +372,7 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
return;
}
- const VideoPixelFormat format = video_frame->format();
- const size_t planes = VideoFrame::NumPlanes(format);
+ const size_t planes = VideoFrame::NumPlanes(output_format_);
const gfx::Size size = video_frame->visible_rect().size();
gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
// Set up the planes creating the mailboxes needed to refer to the textures.
@@ -307,11 +382,11 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
gles2->BindTexture(texture_target_, plane_resource.texture_id);
if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) {
- const size_t width = VideoFrame::Columns(i, format, size.width());
- const size_t height = VideoFrame::Rows(i, format, size.height());
+ const size_t width = VideoFrame::Columns(i, output_format_, size.width());
+ const size_t height = VideoFrame::Rows(i, output_format_, size.height());
plane_resource.image_id = gles2->CreateImageCHROMIUM(
plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height,
- GL_R8_EXT);
+ ImageInternalFormat(output_format_, i));
} else {
gles2->ReleaseTexImage2DCHROMIUM(texture_target_,
plane_resource.image_id);
@@ -329,16 +404,31 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
mailbox_holders[i].sync_point = sync_point;
}
+ scoped_refptr<VideoFrame> frame;
// Create the VideoFrame backed by native textures.
- scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures(
- mailbox_holders[VideoFrame::kYPlane],
- mailbox_holders[VideoFrame::kUPlane],
- mailbox_holders[VideoFrame::kVPlane],
- base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources),
- size, video_frame->visible_rect(), video_frame->natural_size(),
- video_frame->timestamp());
- if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY))
- frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
+ switch (output_format_) {
+ case PIXEL_FORMAT_I420:
+ frame = VideoFrame::WrapYUV420NativeTextures(
+ mailbox_holders[VideoFrame::kYPlane],
+ mailbox_holders[VideoFrame::kUPlane],
+ mailbox_holders[VideoFrame::kVPlane],
+ base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources),
+ size, video_frame->visible_rect(), video_frame->natural_size(),
+ video_frame->timestamp());
+ if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY))
+ frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
+ break;
+ case PIXEL_FORMAT_UYVY:
+ frame = VideoFrame::WrapNativeTexture(
+ PIXEL_FORMAT_UYVY, mailbox_holders[VideoFrame::kYPlane],
+ base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources),
+ size, video_frame->visible_rect(), video_frame->natural_size(),
+ video_frame->timestamp());
+ frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
+ break;
+ default:
+ NOTREACHED();
+ }
frame_ready_cb.Run(frame);
}
@@ -365,7 +455,7 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
while (it != resources_pool_.end()) {
FrameResources* frame_resources = *it;
if (!frame_resources->in_use) {
- if (AreFrameResourcesCompatible(frame_resources, size, format)) {
+ if (AreFrameResourcesCompatible(frame_resources, size)) {
frame_resources->in_use = true;
return frame_resources;
} else {
@@ -384,15 +474,16 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
return nullptr;
gles2->ActiveTexture(GL_TEXTURE0);
size_t planes = VideoFrame::NumPlanes(format);
- FrameResources* frame_resources = new FrameResources(format, size);
+ FrameResources* frame_resources = new FrameResources(size);
resources_pool_.push_back(frame_resources);
for (size_t i = 0; i < planes; ++i) {
PlaneResource& plane_resource = frame_resources->plane_resources[i];
const size_t width = VideoFrame::Columns(i, format, size.width());
const size_t height = VideoFrame::Rows(i, format, size.height());
const gfx::Size plane_size(width, height);
+
plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer(
- plane_size, gfx::BufferFormat::R_8, gfx::BufferUsage::MAP);
+ plane_size, GpuMemoryBufferFormat(format, i), gfx::BufferUsage::MAP);
gles2->GenTextures(1, &plane_resource.texture_id);
gles2->BindTexture(texture_target_, plane_resource.texture_id);
« no previous file with comments | « media/renderers/mock_gpu_video_accelerator_factories.cc ('k') | media/video/gpu_memory_buffer_video_frame_pool_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698