Chromium Code Reviews| 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 41de9d97d262a47d226a43aae43da66cb9b63e6e..ae3f7a5277709d096bcd9feb183eeed2e1b868bd 100644 |
| --- a/media/video/gpu_memory_buffer_video_frame_pool.cc |
| +++ b/media/video/gpu_memory_buffer_video_frame_pool.cc |
| @@ -160,6 +160,9 @@ gfx::BufferFormat GpuMemoryBufferFormat(VideoPixelFormat format, size_t plane) { |
| case PIXEL_FORMAT_I420: |
| DCHECK_LE(plane, 2u); |
| return gfx::BufferFormat::R_8; |
| + case PIXEL_FORMAT_NV12: |
| + DCHECK_LE(plane, 1u); |
| + return gfx::BufferFormat::YUV_420_BIPLANAR; |
| case PIXEL_FORMAT_UYVY: |
| DCHECK_EQ(0u, plane); |
| return gfx::BufferFormat::UYVY_422; |
| @@ -174,6 +177,9 @@ unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) { |
| case PIXEL_FORMAT_I420: |
| DCHECK_LE(plane, 2u); |
| return GL_R8_EXT; |
| + case PIXEL_FORMAT_NV12: |
| + DCHECK_LE(plane, 1u); |
| + return GL_R8_EXT; |
|
Daniele Castagna
2015/08/31 16:28:14
Here we need the new internal format, it should be
Andre
2015/08/31 18:29:31
Great, thanks!
Andre
2015/09/08 20:20:45
dcastagna, I've changed this to NOTREACHED().
Shou
|
| case PIXEL_FORMAT_UYVY: |
| DCHECK_EQ(0u, plane); |
| return GL_RGB; |
| @@ -183,6 +189,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 a even number of lines, and at least one. |
|
Daniele Castagna
2015/08/31 16:28:14
nit: shouldn't it be "an even"
Andre
2015/08/31 18:29:31
Done.
|
| + return std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1); |
| +} |
| + |
| void CopyRowsToI420Buffer(int first_row, |
| int rows, |
| int bytes_per_row, |
| @@ -203,6 +234,38 @@ void CopyRowsToI420Buffer(int first_row, |
| 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, |
| int rows, |
| int width, |
| @@ -283,9 +346,9 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( |
| const scoped_refptr<VideoFrame>& video_frame, |
| FrameResources* frame_resources, |
| const FrameReadyCB& frame_ready_cb) { |
| - 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(); |
| + for (const auto& plane_resource : frame_resources->plane_resources) { |
| + if (plane_resource.gpu_memory_buffer) |
| + plane_resource.gpu_memory_buffer->Unmap(); |
| } |
| media_task_runner_->PostTask( |
| @@ -305,12 +368,9 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( |
| 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 < 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, 1); |
| + for (size_t i = 0; i < dest_planes; i += PlanesPerCopy(output_format_)) { |
| + const int rows = VideoFrame::Rows(i, output_format_, size.height()); |
| + const int rows_per_copy = RowsPerCopy(i, output_format_, size.width()); |
| copies += rows / rows_per_copy; |
| if (rows % rows_per_copy) |
| ++copies; |
| @@ -319,40 +379,55 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( |
| base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, |
| frame_ready_cb); |
| base::Closure barrier = base::BarrierClosure(copies, copies_done); |
| + |
| // 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, 1); |
| - |
| - void* data = nullptr; |
| - DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat( |
| - GpuMemoryBufferFormat(output_format_, i))); |
| - bool rv = frame_resources->plane_resources[i].gpu_memory_buffer->Map(&data); |
| + for (size_t i = 0; i < dest_planes; i += PlanesPerCopy(output_format_)) { |
| + gfx::GpuMemoryBuffer* buffer = |
| + frame_resources->plane_resources[i].gpu_memory_buffer.get(); |
| + DCHECK(buffer); |
| + const size_t buffer_planes = |
| + gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat()); |
| + DCHECK_LE(buffer_planes, VideoFrame::kMaxPlanes); |
| + uint8* dest_buffers[VideoFrame::kMaxPlanes]; |
| + int dest_strides[VideoFrame::kMaxPlanes]; |
| + bool rv = buffer->Map(reinterpret_cast<void**>(dest_buffers)); |
| DCHECK(rv); |
| - uint8* mapped_buffer = static_cast<uint8*>(data); |
| + buffer->GetStride(dest_strides); |
| - int dest_stride = 0; |
| - frame_resources->plane_resources[i].gpu_memory_buffer->GetStride( |
| - &dest_stride); |
| + const int rows = VideoFrame::Rows(i, output_format_, size.height()); |
| + const int rows_per_copy = RowsPerCopy(i, output_format_, size.width()); |
| 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_) { |
| - case PIXEL_FORMAT_I420: |
| + case PIXEL_FORMAT_I420: { |
| + DCHECK_EQ(1u, buffer_planes); |
| + const int bytes_per_row = |
| + VideoFrame::RowBytes(i, output_format_, size.width()); |
| 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)); |
| + base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy, |
| + bytes_per_row, video_frame->data(i), |
| + video_frame->stride(i), dest_buffers[0], |
| + dest_strides[0], barrier)); |
| + break; |
| + } |
| + case PIXEL_FORMAT_NV12: |
| + DCHECK_EQ(2u, buffer_planes); |
| + 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; |
| case PIXEL_FORMAT_UYVY: |
| + DCHECK_EQ(1u, buffer_planes); |
| 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)); |
| + base::Bind(&CopyRowsToUYVYBuffer, row, rows_to_copy, size.width(), |
| + video_frame, dest_buffers[0], dest_strides[0], |
| + barrier)); |
| break; |
| default: |
| NOTREACHED(); |
| @@ -418,9 +493,10 @@ void GpuMemoryBufferVideoFramePool::PoolImpl:: |
| if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) |
| frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); |
| break; |
| + case PIXEL_FORMAT_NV12: |
| case PIXEL_FORMAT_UYVY: |
| frame = VideoFrame::WrapNativeTexture( |
| - PIXEL_FORMAT_UYVY, mailbox_holders[VideoFrame::kYPlane], |
| + output_format_, mailbox_holders[VideoFrame::kYPlane], |
| base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), |
| size, video_frame->visible_rect(), video_frame->natural_size(), |
| video_frame->timestamp()); |
| @@ -482,8 +558,9 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( |
| const size_t height = VideoFrame::Rows(i, format, size.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_size, GpuMemoryBufferFormat(format, i), gfx::BufferUsage::MAP); |
| + plane_size, buffer_format, gfx::BufferUsage::MAP); |
| gles2->GenTextures(1, &plane_resource.texture_id); |
| gles2->BindTexture(texture_target_, plane_resource.texture_id); |
| @@ -493,6 +570,13 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( |
| gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name); |
| gles2->ProduceTextureCHROMIUM(texture_target_, plane_resource.mailbox.name); |
| + |
| + size_t buffer_planes = gfx::NumberOfPlanesForBufferFormat(buffer_format); |
| + if (buffer_planes > 1) { |
| + // Got a multi-planar buffer, assume all the planes fit in it. |
| + DCHECK_EQ(planes, buffer_planes); |
| + break; |
| + } |
| } |
| return frame_resources; |
| } |