summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordcastagna <dcastagna@chromium.org>2015-08-21 16:18:13 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-21 23:19:04 +0000
commitde00d08970e7ef2a95b231d605bb6a0c2c7716f4 (patch)
tree791b4dbd3c6c9897ec3f3eaf33b8385a704dd2b3
parentbaecdb8d6f9b35cbce977f92c94d5aed3008175b (diff)
downloadchromium_src-de00d08970e7ef2a95b231d605bb6a0c2c7716f4.zip
chromium_src-de00d08970e7ef2a95b231d605bb6a0c2c7716f4.tar.gz
chromium_src-de00d08970e7ef2a95b231d605bb6a0c2c7716f4.tar.bz2
media: Convert I420 VideoFrame to UYVY GpuMemoryBuffer.
This patch adds support for UYVY as a pixel format for the VideoFrame backed by GpuMemoryBuffer. If UYVY is set as format in GpuMemoryBufferVideoFramePool, the source VideoFrame will be converted during the copy to GMB. UYVY VideoFrames might get promoted to overlays on Mac. CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel BUG=485859,510252 Review URL: https://codereview.chromium.org/1306693002 Cr-Commit-Position: refs/heads/master@{#344899}
-rw-r--r--content/renderer/media/renderer_gpu_video_accelerator_factories.cc10
-rw-r--r--content/renderer/media/renderer_gpu_video_accelerator_factories.h8
-rw-r--r--content/renderer/render_thread_impl.cc7
-rw-r--r--media/base/video_frame.cc4
-rw-r--r--media/blink/skcanvas_video_renderer.cc3
-rw-r--r--media/renderers/gpu_video_accelerator_factories.h4
-rw-r--r--media/renderers/mock_gpu_video_accelerator_factories.cc19
-rw-r--r--media/renderers/mock_gpu_video_accelerator_factories.h11
-rw-r--r--media/video/gpu_memory_buffer_video_frame_pool.cc213
-rw-r--r--media/video/gpu_memory_buffer_video_frame_pool_unittest.cc22
10 files changed, 229 insertions, 72 deletions
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
index b5522b0..ff0be6a 100644
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -31,12 +31,13 @@ RendererGpuVideoAcceleratorFactories::Create(
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
bool enable_gpu_memory_buffer_video_frames,
unsigned image_texture_target,
+ media::VideoPixelFormat video_frame_output_format,
bool enable_video_accelerator) {
scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
new RendererGpuVideoAcceleratorFactories(
gpu_channel_host, task_runner, context_provider,
enable_gpu_memory_buffer_video_frames, image_texture_target,
- enable_video_accelerator);
+ video_frame_output_format, enable_video_accelerator);
// Post task from outside constructor, since AddRef()/Release() is unsafe from
// within.
task_runner->PostTask(
@@ -52,6 +53,7 @@ RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
bool enable_gpu_memory_buffer_video_frames,
unsigned image_texture_target,
+ media::VideoPixelFormat video_frame_output_format,
bool enable_video_accelerator)
: task_runner_(task_runner),
gpu_channel_host_(gpu_channel_host),
@@ -59,6 +61,7 @@ RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
enable_gpu_memory_buffer_video_frames_(
enable_gpu_memory_buffer_video_frames),
image_texture_target_(image_texture_target),
+ video_frame_output_format_(video_frame_output_format),
video_accelerator_enabled_(enable_video_accelerator),
gpu_memory_buffer_manager_(ChildThreadImpl::current()
->gpu_memory_buffer_manager()),
@@ -235,6 +238,11 @@ unsigned RendererGpuVideoAcceleratorFactories::ImageTextureTarget() {
return image_texture_target_;
}
+media::VideoPixelFormat
+RendererGpuVideoAcceleratorFactories::VideoFrameOutputFormat() {
+ return video_frame_output_format_;
+}
+
gpu::gles2::GLES2Interface*
RendererGpuVideoAcceleratorFactories::GetGLES2Interface() {
DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.h b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
index 981fc65..b1dfc5c 100644
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.h
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
@@ -49,6 +49,7 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
bool enable_gpu_memory_buffer_video_frames,
unsigned image_texture_target,
+ media::VideoPixelFormat video_frame_output_format,
bool enable_video_accelerator);
bool IsGpuVideoAcceleratorEnabled() override;
@@ -75,6 +76,7 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
bool IsTextureRGSupported() override;
bool ShouldUseGpuMemoryBuffersForVideoFrames() const override;
unsigned ImageTextureTarget() override;
+ media::VideoPixelFormat VideoFrameOutputFormat() override;
gpu::gles2::GLES2Interface* GetGLES2Interface() override;
scoped_ptr<base::SharedMemory> CreateSharedMemory(size_t size) override;
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override;
@@ -92,6 +94,7 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
bool enable_gpu_memory_buffer_video_frames,
unsigned image_texture_target,
+ media::VideoPixelFormat video_frame_output_format_,
bool enable_video_accelerator);
~RendererGpuVideoAcceleratorFactories() override;
@@ -109,9 +112,12 @@ class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
scoped_refptr<GpuChannelHost> gpu_channel_host_;
scoped_refptr<ContextProviderCommandBuffer> context_provider_;
- // Wheter gpu memory buffers should be used to hold video frames data.
+ // Whether gpu memory buffers should be used to hold video frames data.
bool enable_gpu_memory_buffer_video_frames_;
const unsigned image_texture_target_;
+ // Pixel format of the hardware video frames created when GpuMemoryBuffers
+ // video frames are enabled.
+ const media::VideoPixelFormat video_frame_output_format_;
// Whether video acceleration encoding/decoding should be enabled.
const bool video_accelerator_enabled_;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 585d5f1..0a146ea 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1365,10 +1365,15 @@ RenderThreadImpl::GetGpuFactories() {
"gpu_channel_. See crbug.com/495185.";
CHECK(gpu_channel_host.get()) << "Have gpu_va_context_provider but lost "
"gpu_channel_. See crbug.com/495185.";
+ media::VideoPixelFormat video_pixel_format = media::PIXEL_FORMAT_I420;
+#if defined(OS_MACOSX)
+ // TODO(dcastagna): Check that the extension is available.
+ video_pixel_format = media::PIXEL_FORMAT_UYVY;
+#endif
gpu_factories = RendererGpuVideoAcceleratorFactories::Create(
gpu_channel_host.get(), media_task_runner, gpu_va_context_provider_,
enable_gpu_memory_buffer_video_frames, image_texture_target,
- enable_video_accelerator);
+ video_pixel_format, enable_video_accelerator);
}
return gpu_factories;
}
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 892cbe3..662d6aa 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -223,8 +223,8 @@ scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
base::TimeDelta timestamp) {
- if (format != PIXEL_FORMAT_ARGB) {
- DLOG(ERROR) << "Only ARGB pixel format supported, got "
+ if (format != PIXEL_FORMAT_ARGB && format != PIXEL_FORMAT_UYVY) {
+ DLOG(ERROR) << "Unsupported pixel format supported, got "
<< VideoPixelFormatToString(format);
return nullptr;
}
diff --git a/media/blink/skcanvas_video_renderer.cc b/media/blink/skcanvas_video_renderer.cc
index a36a9ed..6aa863e 100644
--- a/media/blink/skcanvas_video_renderer.cc
+++ b/media/blink/skcanvas_video_renderer.cc
@@ -138,7 +138,8 @@ bool ShouldCacheVideoFrameSkImage(const VideoFrame* video_frame) {
skia::RefPtr<SkImage> NewSkImageFromVideoFrameNative(
VideoFrame* video_frame,
const Context3D& context_3d) {
- DCHECK_EQ(PIXEL_FORMAT_ARGB, video_frame->format());
+ DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
+ PIXEL_FORMAT_UYVY == video_frame->format());
const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
diff --git a/media/renderers/gpu_video_accelerator_factories.h b/media/renderers/gpu_video_accelerator_factories.h
index c6f728e..5a8ba0b 100644
--- a/media/renderers/gpu_video_accelerator_factories.h
+++ b/media/renderers/gpu_video_accelerator_factories.h
@@ -12,6 +12,7 @@
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/media_export.h"
+#include "media/base/video_types.h"
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/gfx/gpu_memory_buffer.h"
@@ -70,6 +71,9 @@ class MEDIA_EXPORT GpuVideoAcceleratorFactories
virtual bool ShouldUseGpuMemoryBuffersForVideoFrames() const = 0;
virtual unsigned ImageTextureTarget() = 0;
+ // Pixel format of the hardware video frames created when GpuMemoryBuffers
+ // video frames are enabled.
+ virtual VideoPixelFormat VideoFrameOutputFormat() = 0;
virtual bool IsTextureRGSupported() = 0;
virtual gpu::gles2::GLES2Interface* GetGLES2Interface() = 0;
diff --git a/media/renderers/mock_gpu_video_accelerator_factories.cc b/media/renderers/mock_gpu_video_accelerator_factories.cc
index 14e4d14..5230cdd 100644
--- a/media/renderers/mock_gpu_video_accelerator_factories.cc
+++ b/media/renderers/mock_gpu_video_accelerator_factories.cc
@@ -12,8 +12,12 @@ namespace {
class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
public:
- GpuMemoryBufferImpl(const gfx::Size& size) : size_(size) {
- bytes_.resize(size_.GetArea());
+ GpuMemoryBufferImpl(const gfx::Size& size, gfx::BufferFormat format)
+ : format_(format), size_(size) {
+ DCHECK(gfx::BufferFormat::R_8 == format_ ||
+ gfx::BufferFormat::UYVY_422 == format_);
+ bytes_.resize(size_.GetArea() *
+ (format_ == gfx::BufferFormat::UYVY_422 ? 2 : 1));
}
// Overridden from gfx::GpuMemoryBuffer:
@@ -27,9 +31,13 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
return false;
}
gfx::BufferFormat GetFormat() const override {
+ NOTREACHED();
return gfx::BufferFormat::R_8;
}
- void GetStride(int* stride) const override { stride[0] = size_.width(); }
+ void GetStride(int* stride) const override {
+ stride[0] =
+ size_.width() * (format_ == gfx::BufferFormat::UYVY_422 ? 2 : 1);
+ }
gfx::GpuMemoryBufferId GetId() const override {
NOTREACHED();
return gfx::GpuMemoryBufferId(0);
@@ -43,6 +51,7 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
}
private:
+ gfx::BufferFormat format_;
std::vector<unsigned char> bytes_;
const gfx::Size size_;
};
@@ -62,8 +71,8 @@ MockGpuVideoAcceleratorFactories::AllocateGpuMemoryBuffer(
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage) {
- DCHECK(gfx::BufferFormat::R_8 == format);
- return make_scoped_ptr<gfx::GpuMemoryBuffer>(new GpuMemoryBufferImpl(size));
+ return make_scoped_ptr<gfx::GpuMemoryBuffer>(
+ new GpuMemoryBufferImpl(size, format));
}
scoped_ptr<base::SharedMemory>
diff --git a/media/renderers/mock_gpu_video_accelerator_factories.h b/media/renderers/mock_gpu_video_accelerator_factories.h
index 19a509a..e78d824 100644
--- a/media/renderers/mock_gpu_video_accelerator_factories.h
+++ b/media/renderers/mock_gpu_video_accelerator_factories.h
@@ -52,6 +52,15 @@ class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories {
bool ShouldUseGpuMemoryBuffersForVideoFrames() const override;
unsigned ImageTextureTarget() override;
+ VideoPixelFormat VideoFrameOutputFormat() override {
+ return video_frame_output_format_;
+ };
+
+ void SetVideoFrameOutputFormat(
+ const VideoPixelFormat video_frame_output_format) {
+ video_frame_output_format_ = video_frame_output_format;
+ };
+
MOCK_METHOD0(IsTextureRGSupported, bool());
MOCK_METHOD0(GetGLES2Interface, gpu::gles2::GLES2Interface*());
@@ -65,6 +74,8 @@ class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories {
~MockGpuVideoAcceleratorFactories() override;
DISALLOW_COPY_AND_ASSIGN(MockGpuVideoAcceleratorFactories);
+
+ VideoPixelFormat video_frame_output_format_ = PIXEL_FORMAT_I420;
};
} // namespace media
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index a141be0..41de9d9 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));
+ DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(
+ GpuMemoryBufferFormat(output_format_, i)));
+ 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);
diff --git a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
index 3f16e07..2449548 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -216,4 +216,26 @@ TEST_F(GpuMemoryBufferVideoFramePoolTest, DropResourceWhenSizeIsDifferent) {
EXPECT_EQ(6u, gles2_->gen_textures);
}
+TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareUYUVFrame) {
+ scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10);
+ scoped_refptr<MockGpuVideoAcceleratorFactories> mock_gpu_factories(
+ new MockGpuVideoAcceleratorFactories);
+ mock_gpu_factories->SetVideoFrameOutputFormat(PIXEL_FORMAT_UYVY);
+ 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