| 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 4b2f7a1b6b52f75453c0ed033dabe44ce23f0808..c00a8f63b641604845acc33a8293cb075a8412e7 100644
|
| --- a/media/video/gpu_memory_buffer_video_frame_pool.cc
|
| +++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
|
| @@ -86,11 +86,13 @@ class GpuMemoryBufferVideoFramePool::PoolImpl
|
|
|
| // All the resources needed to compose a frame.
|
| struct FrameResources {
|
| - explicit FrameResources(const gfx::Size& size) : size(size) {}
|
| + explicit FrameResources(const gfx::Size& size, VideoPixelFormat format)
|
| + : size(size), format(format) {}
|
| void SetIsInUse(bool in_use) { in_use_ = in_use; }
|
| bool IsInUse() const { return in_use_; }
|
|
|
| const gfx::Size size;
|
| + VideoPixelFormat format;
|
| PlaneResource plane_resources[VideoFrame::kMaxPlanes];
|
|
|
| private:
|
| @@ -121,8 +123,9 @@ 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) {
|
| - return size == resources->size;
|
| + const gfx::Size& size,
|
| + VideoPixelFormat format) {
|
| + return size == resources->size && format == resources->format;
|
| }
|
|
|
| // Get the resources needed for a frame out of the pool, or create them if
|
| @@ -155,8 +158,13 @@ class GpuMemoryBufferVideoFramePool::PoolImpl
|
|
|
| // TODO(dcastagna): change the following type from VideoPixelFormat to
|
| // BufferFormat.
|
| + // Pixel format of the hardware video frames for I420 and YV12 video.
|
| VideoPixelFormat output_format_;
|
|
|
| + // If texture_rg is supported, gpu memory buffers can be used for R8 and RG8.
|
| + bool texture_rg_available_ = false;
|
| + bool texture_rg_available_initialized_ = false;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(PoolImpl);
|
| };
|
|
|
| @@ -166,25 +174,6 @@ namespace {
|
| // output size is |kBytesPerCopyTarget| bytes and run in parallel.
|
| const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB
|
|
|
| -// 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_NV12:
|
| - DCHECK_LE(plane, 1u);
|
| - return gfx::BufferFormat::YUV_420_BIPLANAR;
|
| - 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:
|
| @@ -196,6 +185,9 @@ unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) {
|
| case PIXEL_FORMAT_UYVY:
|
| DCHECK_EQ(0u, plane);
|
| return GL_RGB_YCBCR_422_CHROMIUM;
|
| + case PIXEL_FORMAT_Y16:
|
| + DCHECK_EQ(0u, plane);
|
| + return GL_RG_EXT;
|
| default:
|
| NOTREACHED();
|
| return 0;
|
| @@ -207,6 +199,7 @@ size_t PlanesPerCopy(VideoPixelFormat format) {
|
| switch (format) {
|
| case PIXEL_FORMAT_I420:
|
| case PIXEL_FORMAT_UYVY:
|
| + case PIXEL_FORMAT_Y16:
|
| return 1;
|
| case PIXEL_FORMAT_NV12:
|
| return 2;
|
| @@ -312,6 +305,29 @@ void CopyRowsToUYVYBuffer(int first_row,
|
| done.Run();
|
| }
|
|
|
| +void CopyRowsToGPUBuffer(int first_row,
|
| + int rows,
|
| + int width,
|
| + const scoped_refptr<VideoFrame>& source_frame,
|
| + uint8_t* output,
|
| + int dest_stride,
|
| + const base::Closure& done) {
|
| + int row_bytes = VideoFrame::RowBytes(0, source_frame->format(), width);
|
| + TRACE_EVENT2("media", "CopyRowsToGPUBuffer", "bytes_per_row", row_bytes,
|
| + "rows", rows);
|
| + if (output) {
|
| + DCHECK_NE(dest_stride, 0);
|
| + DCHECK_LE(row_bytes, std::abs(dest_stride));
|
| + const int source_stride = source_frame->stride(0);
|
| + const uint8_t* source =
|
| + source_frame->visible_data(0) + first_row * source_stride;
|
| + uint8_t* dest = output + first_row * dest_stride;
|
| + for (int i = 0; i < rows; ++i)
|
| + memcpy(dest + i * dest_stride, source + i * source_stride, row_bytes);
|
| + }
|
| + done.Run();
|
| +}
|
| +
|
| gfx::Size CodedSize(const scoped_refptr<VideoFrame>& video_frame,
|
| VideoPixelFormat output_format) {
|
| DCHECK(gfx::Rect(video_frame->coded_size())
|
| @@ -329,6 +345,9 @@ gfx::Size CodedSize(const scoped_refptr<VideoFrame>& video_frame,
|
| output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1,
|
| video_frame->visible_rect().height());
|
| break;
|
| + case PIXEL_FORMAT_Y16:
|
| + output = video_frame->visible_rect().size();
|
| + break;
|
| default:
|
| NOTREACHED();
|
| }
|
| @@ -346,19 +365,30 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
|
| const scoped_refptr<VideoFrame>& video_frame,
|
| const FrameReadyCB& frame_ready_cb) {
|
| DCHECK(media_task_runner_->BelongsToCurrentThread());
|
| - // Lazily initialize output_format_ since VideoFrameOutputFormat() has to be
|
| - // called on the media_thread while this object might be instantiated on any.
|
| - if (output_format_ == PIXEL_FORMAT_UNKNOWN)
|
| - output_format_ = gpu_factories_->VideoFrameOutputFormat();
|
| -
|
| - if (output_format_ == PIXEL_FORMAT_UNKNOWN) {
|
| - frame_ready_cb.Run(video_frame);
|
| - return;
|
| - }
|
| + media::VideoPixelFormat output_format = PIXEL_FORMAT_UNKNOWN;
|
| switch (video_frame->format()) {
|
| // Supported cases.
|
| case PIXEL_FORMAT_YV12:
|
| - case PIXEL_FORMAT_I420:
|
| + case PIXEL_FORMAT_I420: {
|
| + // Lazily initialize output_format_ since VideoFrameOutputFormat() has to
|
| + // be called on the media_thread while this object might be instantiated
|
| + // on any.
|
| + if (output_format_ == PIXEL_FORMAT_UNKNOWN) {
|
| + output_format_ =
|
| + gpu_factories_->VideoFrameOutputFormat(PIXEL_FORMAT_I420);
|
| + }
|
| + output_format = output_format_;
|
| + break;
|
| + }
|
| + case PIXEL_FORMAT_Y16:
|
| + // Lazily initialize texture_rg_available_.
|
| + if (!texture_rg_available_initialized_) {
|
| + texture_rg_available_initialized_ = true;
|
| + texture_rg_available_ = gpu_factories_->VideoFrameOutputFormat(
|
| + PIXEL_FORMAT_Y16) == PIXEL_FORMAT_Y16;
|
| + }
|
| + output_format =
|
| + texture_rg_available_ ? video_frame->format() : PIXEL_FORMAT_UNKNOWN;
|
| break;
|
| // Unsupported cases.
|
| case PIXEL_FORMAT_YV12A:
|
| @@ -384,16 +414,18 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
|
| case PIXEL_FORMAT_YUV422P12:
|
| case PIXEL_FORMAT_YUV444P12:
|
| case PIXEL_FORMAT_Y8:
|
| - case PIXEL_FORMAT_Y16:
|
| case PIXEL_FORMAT_UNKNOWN:
|
| - frame_ready_cb.Run(video_frame);
|
| - return;
|
| + break;
|
| + }
|
| + if (output_format == PIXEL_FORMAT_UNKNOWN) {
|
| + frame_ready_cb.Run(video_frame);
|
| + return;
|
| }
|
|
|
| - const gfx::Size coded_size = CodedSize(video_frame, output_format_);
|
| + const gfx::Size coded_size = CodedSize(video_frame, output_format);
|
| // Acquire resources. Incompatible ones will be dropped from the pool.
|
| FrameResources* frame_resources =
|
| - GetOrCreateFrameResources(coded_size, output_format_);
|
| + GetOrCreateFrameResources(coded_size, output_format);
|
| if (!frame_resources) {
|
| frame_ready_cb.Run(video_frame);
|
| return;
|
| @@ -466,14 +498,15 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
|
| FrameResources* frame_resources,
|
| const FrameReadyCB& frame_ready_cb) {
|
| // Compute the number of tasks to post and create the barrier.
|
| - const size_t num_planes = VideoFrame::NumPlanes(output_format_);
|
| - const size_t planes_per_copy = PlanesPerCopy(output_format_);
|
| - const gfx::Size coded_size = CodedSize(video_frame, output_format_);
|
| + const size_t num_planes = VideoFrame::NumPlanes(frame_resources->format);
|
| + const size_t planes_per_copy = PlanesPerCopy(frame_resources->format);
|
| + const gfx::Size coded_size = CodedSize(video_frame, frame_resources->format);
|
| size_t copies = 0;
|
| for (size_t i = 0; i < num_planes; i += planes_per_copy) {
|
| - const int rows = VideoFrame::Rows(i, output_format_, coded_size.height());
|
| + const int rows =
|
| + VideoFrame::Rows(i, frame_resources->format, coded_size.height());
|
| const int rows_per_copy =
|
| - RowsPerCopy(i, output_format_, coded_size.width());
|
| + RowsPerCopy(i, frame_resources->format, coded_size.width());
|
| copies += rows / rows_per_copy;
|
| if (rows % rows_per_copy)
|
| ++copies;
|
| @@ -495,16 +528,17 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
|
| DCHECK_EQ(planes_per_copy,
|
| gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat()));
|
|
|
| - const int rows = VideoFrame::Rows(i, output_format_, coded_size.height());
|
| + const int rows =
|
| + VideoFrame::Rows(i, frame_resources->format, coded_size.height());
|
| const int rows_per_copy =
|
| - RowsPerCopy(i, output_format_, coded_size.width());
|
| + RowsPerCopy(i, frame_resources->format, coded_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_) {
|
| + switch (frame_resources->format) {
|
| case PIXEL_FORMAT_I420: {
|
| - const int bytes_per_row =
|
| - VideoFrame::RowBytes(i, output_format_, coded_size.width());
|
| + const int bytes_per_row = VideoFrame::RowBytes(
|
| + i, frame_resources->format, coded_size.width());
|
| worker_task_runner_->PostTask(
|
| FROM_HERE, base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy,
|
| bytes_per_row, video_frame->visible_data(i),
|
| @@ -529,6 +563,13 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
|
| static_cast<uint8_t*>(buffer->memory(0)),
|
| buffer->stride(0), barrier));
|
| break;
|
| + case PIXEL_FORMAT_Y16:
|
| + worker_task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(&CopyRowsToGPUBuffer, row, rows_to_copy,
|
| + coded_size.width(), video_frame,
|
| + static_cast<uint8_t*>(buffer->memory(0)),
|
| + buffer->stride(0), barrier));
|
| + break;
|
| default:
|
| NOTREACHED();
|
| }
|
| @@ -549,27 +590,27 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
|
| }
|
| gpu::gles2::GLES2Interface* gles2 = lock->ContextGL();
|
|
|
| - const size_t num_planes = VideoFrame::NumPlanes(output_format_);
|
| - const size_t planes_per_copy = PlanesPerCopy(output_format_);
|
| - const gfx::Size coded_size = CodedSize(video_frame, output_format_);
|
| + const size_t num_planes = VideoFrame::NumPlanes(frame_resources->format);
|
| + const size_t planes_per_copy = PlanesPerCopy(frame_resources->format);
|
| + const gfx::Size coded_size = CodedSize(video_frame, frame_resources->format);
|
| gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
|
| // Set up the planes creating the mailboxes needed to refer to the textures.
|
| for (size_t i = 0; i < num_planes; i += planes_per_copy) {
|
| PlaneResource& plane_resource = frame_resources->plane_resources[i];
|
| const gfx::BufferFormat buffer_format =
|
| - GpuMemoryBufferFormat(output_format_, i);
|
| + VideoFrame::BufferFormat(frame_resources->format);
|
| unsigned texture_target = gpu_factories_->ImageTextureTarget(buffer_format);
|
| // Bind the texture and create or rebind the image.
|
| 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, output_format_, coded_size.width());
|
| + VideoFrame::Columns(i, frame_resources->format, coded_size.width());
|
| const size_t height =
|
| - VideoFrame::Rows(i, output_format_, coded_size.height());
|
| + VideoFrame::Rows(i, frame_resources->format, coded_size.height());
|
| plane_resource.image_id = gles2->CreateImageCHROMIUM(
|
| plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height,
|
| - ImageInternalFormat(output_format_, i));
|
| + ImageInternalFormat(frame_resources->format, i));
|
| } else if (plane_resource.image_id) {
|
| gles2->ReleaseTexImage2DCHROMIUM(texture_target, plane_resource.image_id);
|
| }
|
| @@ -595,8 +636,9 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
|
| base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources));
|
|
|
| // Consumers should sample from NV12 textures as if they're XRGB.
|
| - VideoPixelFormat frame_format =
|
| - output_format_ == PIXEL_FORMAT_NV12 ? PIXEL_FORMAT_XRGB : output_format_;
|
| + VideoPixelFormat frame_format = (frame_resources->format == PIXEL_FORMAT_NV12)
|
| + ? PIXEL_FORMAT_XRGB
|
| + : frame_resources->format;
|
| DCHECK_EQ(VideoFrame::NumPlanes(frame_format) * planes_per_copy, num_planes);
|
|
|
| // Create the VideoFrame backed by native textures.
|
| @@ -615,13 +657,14 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
|
| frame->set_color_space(video_frame->ColorSpace());
|
|
|
| bool allow_overlay = false;
|
| - switch (output_format_) {
|
| + switch (frame_resources->format) {
|
| case PIXEL_FORMAT_I420:
|
| allow_overlay =
|
| video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY);
|
| break;
|
| case PIXEL_FORMAT_NV12:
|
| case PIXEL_FORMAT_UYVY:
|
| + case PIXEL_FORMAT_Y16:
|
| allow_overlay = true;
|
| break;
|
| default:
|
| @@ -666,7 +709,7 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
|
| while (it != resources_pool_.end()) {
|
| FrameResources* frame_resources = *it;
|
| if (!frame_resources->IsInUse()) {
|
| - if (AreFrameResourcesCompatible(frame_resources, size)) {
|
| + if (AreFrameResourcesCompatible(frame_resources, size, format)) {
|
| frame_resources->SetIsInUse(true);
|
| return frame_resources;
|
| } else {
|
| @@ -688,7 +731,7 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
|
| gpu::gles2::GLES2Interface* gles2 = lock->ContextGL();
|
| gles2->ActiveTexture(GL_TEXTURE0);
|
| size_t num_planes = VideoFrame::NumPlanes(format);
|
| - FrameResources* frame_resources = new FrameResources(size);
|
| + FrameResources* frame_resources = new FrameResources(size, format);
|
| resources_pool_.push_back(frame_resources);
|
| for (size_t i = 0; i < num_planes; i += PlanesPerCopy(format)) {
|
| PlaneResource& plane_resource = frame_resources->plane_resources[i];
|
| @@ -696,7 +739,7 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
|
| const size_t height = VideoFrame::Rows(i, format, size.height());
|
| plane_resource.size = gfx::Size(width, height);
|
|
|
| - const gfx::BufferFormat buffer_format = GpuMemoryBufferFormat(format, i);
|
| + const gfx::BufferFormat buffer_format = VideoFrame::BufferFormat(format);
|
| plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer(
|
| plane_resource.size, buffer_format,
|
| gfx::BufferUsage::GPU_READ_CPU_READ_WRITE);
|
| @@ -704,8 +747,13 @@ GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
|
| unsigned texture_target = gpu_factories_->ImageTextureTarget(buffer_format);
|
| gles2->GenTextures(1, &plane_resource.texture_id);
|
| gles2->BindTexture(texture_target, plane_resource.texture_id);
|
| - gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
| - gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
| + if (format == PIXEL_FORMAT_Y16) {
|
| + gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
| + gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
| + } else {
|
| + gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
| + gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
| + }
|
| gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
| gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
| gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name);
|
|
|