1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
8 #include <GLES2/gl2ext.h>
14 #include "base/barrier_closure.h"
15 #include "base/bind.h"
16 #include "base/containers/stack_container.h"
17 #include "base/location.h"
18 #include "base/memory/linked_ptr.h"
19 #include "base/trace_event/trace_event.h"
20 #include "gpu/GLES2/gl2extchromium.h"
21 #include "gpu/command_buffer/client/gles2_interface.h"
22 #include "media/renderers/gpu_video_accelerator_factories.h"
23 #include "third_party/libyuv/include/libyuv.h"
24 #include "ui/gfx/buffer_format_util.h"
28 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames.
29 class GpuMemoryBufferVideoFramePool::PoolImpl
30 : public base::RefCountedThreadSafe
<
31 GpuMemoryBufferVideoFramePool::PoolImpl
> {
33 // |media_task_runner| is the media task runner associated with the
34 // GL context provided by |gpu_factories|
35 // |worker_task_runner| is a task runner used to asynchronously copy
36 // video frame's planes.
37 // |gpu_factories| is an interface to GPU related operation and can be
38 // null if a GL context is not available.
39 PoolImpl(const scoped_refptr
<base::SingleThreadTaskRunner
>& media_task_runner
,
40 const scoped_refptr
<base::TaskRunner
>& worker_task_runner
,
41 const scoped_refptr
<GpuVideoAcceleratorFactories
>& gpu_factories
)
42 : media_task_runner_(media_task_runner
),
43 worker_task_runner_(worker_task_runner
),
44 gpu_factories_(gpu_factories
),
45 texture_target_(gpu_factories
? gpu_factories
->ImageTextureTarget()
47 output_format_(PIXEL_FORMAT_UNKNOWN
) {
48 DCHECK(media_task_runner_
);
49 DCHECK(worker_task_runner_
);
52 // Takes a software VideoFrame and calls |frame_ready_cb| with a VideoFrame
53 // backed by native textures if possible.
54 // The data contained in video_frame is copied into the returned frame
55 // asynchronously posting tasks to |worker_task_runner_|, while
56 // |frame_ready_cb| will be called on |media_task_runner_| once all the data
58 void CreateHardwareFrame(const scoped_refptr
<VideoFrame
>& video_frame
,
59 const FrameReadyCB
& cb
);
62 friend class base::RefCountedThreadSafe
<
63 GpuMemoryBufferVideoFramePool::PoolImpl
>;
66 // Resource to represent a plane.
67 struct PlaneResource
{
69 scoped_ptr
<gfx::GpuMemoryBuffer
> gpu_memory_buffer
;
70 unsigned texture_id
= 0u;
71 unsigned image_id
= 0u;
75 // All the resources needed to compose a frame.
76 struct FrameResources
{
77 explicit FrameResources(const gfx::Size
& size
) : size(size
) {}
80 PlaneResource plane_resources
[VideoFrame::kMaxPlanes
];
83 // Copy |video_frame| data into |frame_resouces|
84 // and calls |done| when done.
85 void CopyVideoFrameToGpuMemoryBuffers(
86 const scoped_refptr
<VideoFrame
>& video_frame
,
87 FrameResources
* frame_resources
,
88 const FrameReadyCB
& frame_ready_cb
);
90 // Called when all the data has been copied.
91 void OnCopiesDone(const scoped_refptr
<VideoFrame
>& video_frame
,
92 FrameResources
* frame_resources
,
93 const FrameReadyCB
& frame_ready_cb
);
95 // Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new
97 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also
99 void BindAndCreateMailboxesHardwareFrameResources(
100 const scoped_refptr
<VideoFrame
>& video_frame
,
101 FrameResources
* frame_resources
,
102 const FrameReadyCB
& frame_ready_cb
);
104 // Return true if |resources| can be used to represent a frame for
105 // specific |format| and |size|.
106 static bool AreFrameResourcesCompatible(const FrameResources
* resources
,
107 const gfx::Size
& size
) {
108 return size
== resources
->size
;
111 // Get the resources needed for a frame out of the pool, or create them if
113 // This also drops the LRU resources that can't be reuse for this frame.
114 FrameResources
* GetOrCreateFrameResources(const gfx::Size
& size
,
115 VideoPixelFormat format
);
117 // Callback called when a VideoFrame generated with GetFrameResources is no
118 // longer referenced.
119 // This could be called by any thread.
120 void MailboxHoldersReleased(FrameResources
* frame_resources
,
123 // Return frame resources to the pool. This has to be called on the thread
124 // where |media_task_runner_| is current.
125 void ReturnFrameResources(FrameResources
* frame_resources
);
127 // Delete resources. This has to be called on the thread where |task_runner|
129 static void DeleteFrameResources(
130 const scoped_refptr
<GpuVideoAcceleratorFactories
>& gpu_factories
,
131 FrameResources
* frame_resources
);
133 // Task runner associated to the GL context provided by |gpu_factories_|.
134 scoped_refptr
<base::SingleThreadTaskRunner
> media_task_runner_
;
135 // Task runner used to asynchronously copy planes.
136 scoped_refptr
<base::TaskRunner
> worker_task_runner_
;
138 // Interface to GPU related operations.
139 scoped_refptr
<GpuVideoAcceleratorFactories
> gpu_factories_
;
141 // Pool of resources.
142 std::list
<FrameResources
*> resources_pool_
;
144 const unsigned texture_target_
;
145 // TODO(dcastagna): change the following type from VideoPixelFormat to
147 VideoPixelFormat output_format_
;
148 DISALLOW_COPY_AND_ASSIGN(PoolImpl
);
153 // VideoFrame copies to GpuMemoryBuffers will be split in copies where the
154 // output size is |kBytesPerCopyTarget| bytes and run in parallel.
155 const size_t kBytesPerCopyTarget
= 1024 * 1024; // 1MB
157 // Return the GpuMemoryBuffer format to use for a specific VideoPixelFormat
159 gfx::BufferFormat
GpuMemoryBufferFormat(VideoPixelFormat format
, size_t plane
) {
161 case PIXEL_FORMAT_I420
:
162 DCHECK_LE(plane
, 2u);
163 return gfx::BufferFormat::R_8
;
164 case PIXEL_FORMAT_NV12
:
165 DCHECK_LE(plane
, 1u);
166 return gfx::BufferFormat::YUV_420_BIPLANAR
;
167 case PIXEL_FORMAT_UYVY
:
168 DCHECK_EQ(0u, plane
);
169 return gfx::BufferFormat::UYVY_422
;
172 return gfx::BufferFormat::BGRA_8888
;
176 unsigned ImageInternalFormat(VideoPixelFormat format
, size_t plane
) {
178 case PIXEL_FORMAT_I420
:
179 DCHECK_LE(plane
, 2u);
181 case PIXEL_FORMAT_NV12
:
182 DCHECK_LE(plane
, 1u);
183 DLOG(WARNING
) << "NV12 format not supported yet";
184 return 0; // TODO(andresantoso): Implement extension for NV12.
185 case PIXEL_FORMAT_UYVY
:
186 DCHECK_EQ(0u, plane
);
187 return GL_RGB_YCBCR_422_CHROMIUM
;
194 // The number of output planes to be copied in each iteration.
195 size_t PlanesPerCopy(VideoPixelFormat format
) {
197 case PIXEL_FORMAT_I420
:
198 case PIXEL_FORMAT_UYVY
:
200 case PIXEL_FORMAT_NV12
:
208 // The number of output rows to be copied in each iteration.
209 int RowsPerCopy(size_t plane
, VideoPixelFormat format
, int width
) {
210 int bytes_per_row
= VideoFrame::RowBytes(plane
, format
, width
);
211 if (format
== PIXEL_FORMAT_NV12
) {
212 DCHECK_EQ(0u, plane
);
213 bytes_per_row
+= VideoFrame::RowBytes(1, format
, width
);
215 // Copy an even number of lines, and at least one.
216 return std::max
<size_t>((kBytesPerCopyTarget
/ bytes_per_row
) & ~1, 1);
219 void CopyRowsToI420Buffer(int first_row
,
226 const base::Closure
& done
) {
227 TRACE_EVENT2("media", "CopyRowsToI420Buffer", "bytes_per_row", bytes_per_row
,
230 DCHECK_NE(dest_stride
, 0);
231 DCHECK_LE(bytes_per_row
, std::abs(dest_stride
));
232 DCHECK_LE(bytes_per_row
, source_stride
);
233 for (int row
= first_row
; row
< first_row
+ rows
; ++row
) {
234 memcpy(output
+ dest_stride
* row
, source
+ source_stride
* row
,
241 void CopyRowsToNV12Buffer(int first_row
,
244 const scoped_refptr
<VideoFrame
>& source_frame
,
249 const base::Closure
& done
) {
250 TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "bytes_per_row", bytes_per_row
,
252 if (dest_y
&& dest_uv
) {
253 DCHECK_NE(dest_stride_y
, 0);
254 DCHECK_NE(dest_stride_uv
, 0);
255 DCHECK_LE(bytes_per_row
, std::abs(dest_stride_y
));
256 DCHECK_LE(bytes_per_row
, std::abs(dest_stride_uv
));
257 DCHECK_EQ(0, first_row
% 2);
260 source_frame
->data(VideoFrame::kYPlane
) +
261 first_row
* source_frame
->stride(VideoFrame::kYPlane
),
262 source_frame
->stride(VideoFrame::kYPlane
),
263 source_frame
->data(VideoFrame::kUPlane
) +
264 first_row
/ 2 * source_frame
->stride(VideoFrame::kUPlane
),
265 source_frame
->stride(VideoFrame::kUPlane
),
266 source_frame
->data(VideoFrame::kVPlane
) +
267 first_row
/ 2 * source_frame
->stride(VideoFrame::kVPlane
),
268 source_frame
->stride(VideoFrame::kVPlane
),
269 dest_y
+ first_row
* dest_stride_y
, dest_stride_y
,
270 dest_uv
+ first_row
/ 2 * dest_stride_uv
, dest_stride_uv
, bytes_per_row
,
276 void CopyRowsToUYVYBuffer(int first_row
,
279 const scoped_refptr
<VideoFrame
>& source_frame
,
282 const base::Closure
& done
) {
283 TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width
* 2,
286 DCHECK_NE(dest_stride
, 0);
287 DCHECK_LE(width
, std::abs(dest_stride
/ 2));
288 DCHECK_EQ(0, first_row
% 2);
290 source_frame
->data(VideoFrame::kYPlane
) +
291 first_row
* source_frame
->stride(VideoFrame::kYPlane
),
292 source_frame
->stride(VideoFrame::kYPlane
),
293 source_frame
->data(VideoFrame::kUPlane
) +
294 first_row
/ 2 * source_frame
->stride(VideoFrame::kUPlane
),
295 source_frame
->stride(VideoFrame::kUPlane
),
296 source_frame
->data(VideoFrame::kVPlane
) +
297 first_row
/ 2 * source_frame
->stride(VideoFrame::kVPlane
),
298 source_frame
->stride(VideoFrame::kVPlane
),
299 output
+ first_row
* dest_stride
, dest_stride
, width
, rows
);
304 } // unnamed namespace
306 // Creates a VideoFrame backed by native textures starting from a software
308 // The data contained in |video_frame| is copied into the VideoFrame passed to
310 // This has to be called on the thread where |media_task_runner_| is current.
311 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
312 const scoped_refptr
<VideoFrame
>& video_frame
,
313 const FrameReadyCB
& frame_ready_cb
) {
314 DCHECK(media_task_runner_
->BelongsToCurrentThread());
315 if (!gpu_factories_
) {
316 frame_ready_cb
.Run(video_frame
);
320 // Lazily initialize output_format_ since VideoFrameOutputFormat() has to be
321 // called on the media_thread while this object might be instantiated on any.
322 if (output_format_
== PIXEL_FORMAT_UNKNOWN
)
323 output_format_
= gpu_factories_
->VideoFrameOutputFormat();
325 if (output_format_
== PIXEL_FORMAT_UNKNOWN
) {
326 frame_ready_cb
.Run(video_frame
);
329 switch (video_frame
->format()) {
331 case PIXEL_FORMAT_YV12
:
332 case PIXEL_FORMAT_I420
:
334 // Unsupported cases.
335 case PIXEL_FORMAT_YV12A
:
336 case PIXEL_FORMAT_YV16
:
337 case PIXEL_FORMAT_YV24
:
338 case PIXEL_FORMAT_NV12
:
339 case PIXEL_FORMAT_NV21
:
340 case PIXEL_FORMAT_UYVY
:
341 case PIXEL_FORMAT_YUY2
:
342 case PIXEL_FORMAT_ARGB
:
343 case PIXEL_FORMAT_XRGB
:
344 case PIXEL_FORMAT_RGB24
:
345 case PIXEL_FORMAT_RGB32
:
346 case PIXEL_FORMAT_MJPEG
:
347 case PIXEL_FORMAT_MT21
:
348 case PIXEL_FORMAT_UNKNOWN
:
349 frame_ready_cb
.Run(video_frame
);
353 DCHECK(video_frame
->visible_rect().origin().IsOrigin());
354 const gfx::Size size
= video_frame
->visible_rect().size();
356 // Acquire resources. Incompatible ones will be dropped from the pool.
357 FrameResources
* frame_resources
=
358 GetOrCreateFrameResources(size
, output_format_
);
359 if (!frame_resources
) {
360 frame_ready_cb
.Run(video_frame
);
364 worker_task_runner_
->PostTask(
365 FROM_HERE
, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers
, this,
366 video_frame
, frame_resources
, frame_ready_cb
));
369 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone(
370 const scoped_refptr
<VideoFrame
>& video_frame
,
371 FrameResources
* frame_resources
,
372 const FrameReadyCB
& frame_ready_cb
) {
373 for (const auto& plane_resource
: frame_resources
->plane_resources
) {
374 if (plane_resource
.gpu_memory_buffer
)
375 plane_resource
.gpu_memory_buffer
->Unmap();
378 media_task_runner_
->PostTask(
380 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources
, this,
381 video_frame
, frame_resources
, frame_ready_cb
));
384 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks
385 // that will be synchronized by a barrier.
386 // After the barrier is passed OnCopiesDone will be called.
387 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
388 const scoped_refptr
<VideoFrame
>& video_frame
,
389 FrameResources
* frame_resources
,
390 const FrameReadyCB
& frame_ready_cb
) {
391 // Compute the number of tasks to post and create the barrier.
392 const size_t num_planes
= VideoFrame::NumPlanes(output_format_
);
393 const size_t planes_per_copy
= PlanesPerCopy(output_format_
);
394 gfx::Size size
= video_frame
->visible_rect().size();
396 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
) {
397 const int rows
= VideoFrame::Rows(i
, output_format_
, size
.height());
398 const int rows_per_copy
= RowsPerCopy(i
, output_format_
, size
.width());
399 copies
+= rows
/ rows_per_copy
;
400 if (rows
% rows_per_copy
)
403 base::Closure copies_done
=
404 base::Bind(&PoolImpl::OnCopiesDone
, this, video_frame
, frame_resources
,
406 base::Closure barrier
= base::BarrierClosure(copies
, copies_done
);
408 // Post all the async tasks.
409 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
) {
410 gfx::GpuMemoryBuffer
* buffer
=
411 frame_resources
->plane_resources
[i
].gpu_memory_buffer
.get();
412 uint8
* dest_buffers
[VideoFrame::kMaxPlanes
] = {0};
413 int dest_strides
[VideoFrame::kMaxPlanes
] = {0};
415 DCHECK_EQ(planes_per_copy
,
416 gfx::NumberOfPlanesForBufferFormat(buffer
->GetFormat()));
417 bool rv
= buffer
->Map(reinterpret_cast<void**>(dest_buffers
));
419 buffer
->GetStride(dest_strides
);
422 const int rows
= VideoFrame::Rows(i
, output_format_
, size
.height());
423 const int rows_per_copy
= RowsPerCopy(i
, output_format_
, size
.width());
425 for (int row
= 0; row
< rows
; row
+= rows_per_copy
) {
426 const int rows_to_copy
= std::min(rows_per_copy
, rows
- row
);
427 switch (output_format_
) {
428 case PIXEL_FORMAT_I420
: {
429 const int bytes_per_row
=
430 VideoFrame::RowBytes(i
, output_format_
, size
.width());
431 worker_task_runner_
->PostTask(
433 base::Bind(&CopyRowsToI420Buffer
, row
, rows_to_copy
,
434 bytes_per_row
, video_frame
->data(i
),
435 video_frame
->stride(i
), dest_buffers
[0],
436 dest_strides
[0], barrier
));
439 case PIXEL_FORMAT_NV12
:
440 worker_task_runner_
->PostTask(
442 base::Bind(&CopyRowsToNV12Buffer
, row
, rows_to_copy
,
443 size
.width(), video_frame
, dest_buffers
[0],
444 dest_strides
[0], dest_buffers
[1], dest_strides
[1],
447 case PIXEL_FORMAT_UYVY
:
448 worker_task_runner_
->PostTask(
450 base::Bind(&CopyRowsToUYVYBuffer
, row
, rows_to_copy
, size
.width(),
451 video_frame
, dest_buffers
[0], dest_strides
[0],
461 void GpuMemoryBufferVideoFramePool::PoolImpl::
462 BindAndCreateMailboxesHardwareFrameResources(
463 const scoped_refptr
<VideoFrame
>& video_frame
,
464 FrameResources
* frame_resources
,
465 const FrameReadyCB
& frame_ready_cb
) {
466 gpu::gles2::GLES2Interface
* gles2
= gpu_factories_
->GetGLES2Interface();
468 frame_ready_cb
.Run(video_frame
);
472 const size_t num_planes
= VideoFrame::NumPlanes(output_format_
);
473 const size_t planes_per_copy
= PlanesPerCopy(output_format_
);
474 const gfx::Size size
= video_frame
->visible_rect().size();
475 gpu::MailboxHolder mailbox_holders
[VideoFrame::kMaxPlanes
];
476 // Set up the planes creating the mailboxes needed to refer to the textures.
477 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
) {
478 PlaneResource
& plane_resource
= frame_resources
->plane_resources
[i
];
479 // Bind the texture and create or rebind the image.
480 gles2
->BindTexture(texture_target_
, plane_resource
.texture_id
);
482 if (plane_resource
.gpu_memory_buffer
&& !plane_resource
.image_id
) {
483 const size_t width
= VideoFrame::Columns(i
, output_format_
, size
.width());
484 const size_t height
= VideoFrame::Rows(i
, output_format_
, size
.height());
485 plane_resource
.image_id
= gles2
->CreateImageCHROMIUM(
486 plane_resource
.gpu_memory_buffer
->AsClientBuffer(), width
, height
,
487 ImageInternalFormat(output_format_
, i
));
488 } else if (plane_resource
.image_id
) {
489 gles2
->ReleaseTexImage2DCHROMIUM(texture_target_
,
490 plane_resource
.image_id
);
492 if (plane_resource
.image_id
)
493 gles2
->BindTexImage2DCHROMIUM(texture_target_
, plane_resource
.image_id
);
495 gpu::MailboxHolder(plane_resource
.mailbox
, texture_target_
, 0);
498 // Insert a sync_point, this is needed to make sure that the textures the
499 // mailboxes refer to will be used only after all the previous commands posted
500 // in the command buffer have been processed.
501 unsigned sync_point
= gles2
->InsertSyncPointCHROMIUM();
502 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
)
503 mailbox_holders
[i
].sync_point
= sync_point
;
505 scoped_refptr
<VideoFrame
> frame
;
506 // Create the VideoFrame backed by native textures.
507 switch (output_format_
) {
508 case PIXEL_FORMAT_I420
:
509 frame
= VideoFrame::WrapYUV420NativeTextures(
510 mailbox_holders
[VideoFrame::kYPlane
],
511 mailbox_holders
[VideoFrame::kUPlane
],
512 mailbox_holders
[VideoFrame::kVPlane
],
513 base::Bind(&PoolImpl::MailboxHoldersReleased
, this, frame_resources
),
514 size
, video_frame
->visible_rect(), video_frame
->natural_size(),
515 video_frame
->timestamp());
516 if (video_frame
->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY
))
517 frame
->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY
, true);
519 case PIXEL_FORMAT_NV12
:
520 case PIXEL_FORMAT_UYVY
:
521 frame
= VideoFrame::WrapNativeTexture(
522 output_format_
, mailbox_holders
[VideoFrame::kYPlane
],
523 base::Bind(&PoolImpl::MailboxHoldersReleased
, this, frame_resources
),
524 size
, video_frame
->visible_rect(), video_frame
->natural_size(),
525 video_frame
->timestamp());
526 frame
->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY
, true);
531 frame_ready_cb
.Run(frame
);
534 // Destroy all the resources posting one task per FrameResources
535 // to the |media_task_runner_|.
536 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() {
537 // Delete all the resources on the media thread.
538 while (!resources_pool_
.empty()) {
539 FrameResources
* frame_resources
= resources_pool_
.front();
540 resources_pool_
.pop_front();
541 media_task_runner_
->PostTask(
542 FROM_HERE
, base::Bind(&PoolImpl::DeleteFrameResources
, gpu_factories_
,
543 base::Owned(frame_resources
)));
547 // Tries to find the resources in the pool or create them.
548 // Incompatible resources will be dropped.
549 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources
*
550 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
551 const gfx::Size
& size
,
552 VideoPixelFormat format
) {
553 auto it
= resources_pool_
.begin();
554 while (it
!= resources_pool_
.end()) {
555 FrameResources
* frame_resources
= *it
;
556 if (!frame_resources
->in_use
) {
557 if (AreFrameResourcesCompatible(frame_resources
, size
)) {
558 frame_resources
->in_use
= true;
559 return frame_resources
;
561 resources_pool_
.erase(it
++);
562 DeleteFrameResources(gpu_factories_
, frame_resources
);
563 delete frame_resources
;
570 // Create the resources.
571 gpu::gles2::GLES2Interface
* gles2
= gpu_factories_
->GetGLES2Interface();
574 gles2
->ActiveTexture(GL_TEXTURE0
);
575 size_t num_planes
= VideoFrame::NumPlanes(format
);
576 FrameResources
* frame_resources
= new FrameResources(size
);
577 resources_pool_
.push_back(frame_resources
);
578 for (size_t i
= 0; i
< num_planes
; i
+= PlanesPerCopy(format
)) {
579 PlaneResource
& plane_resource
= frame_resources
->plane_resources
[i
];
580 const size_t width
= VideoFrame::Columns(i
, format
, size
.width());
581 const size_t height
= VideoFrame::Rows(i
, format
, size
.height());
582 const gfx::Size
plane_size(width
, height
);
584 const gfx::BufferFormat buffer_format
= GpuMemoryBufferFormat(format
, i
);
585 plane_resource
.gpu_memory_buffer
= gpu_factories_
->AllocateGpuMemoryBuffer(
586 plane_size
, buffer_format
, gfx::BufferUsage::MAP
);
588 gles2
->GenTextures(1, &plane_resource
.texture_id
);
589 gles2
->BindTexture(texture_target_
, plane_resource
.texture_id
);
590 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
591 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
592 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
593 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
594 gles2
->GenMailboxCHROMIUM(plane_resource
.mailbox
.name
);
595 gles2
->ProduceTextureCHROMIUM(texture_target_
, plane_resource
.mailbox
.name
);
597 return frame_resources
;
601 void GpuMemoryBufferVideoFramePool::PoolImpl::DeleteFrameResources(
602 const scoped_refptr
<GpuVideoAcceleratorFactories
>& gpu_factories
,
603 FrameResources
* frame_resources
) {
604 // TODO(dcastagna): As soon as the context lost is dealt with in media,
605 // make sure that we won't execute this callback (use a weak pointer to
607 gpu::gles2::GLES2Interface
* gles2
= gpu_factories
->GetGLES2Interface();
611 for (PlaneResource
& plane_resource
: frame_resources
->plane_resources
) {
612 if (plane_resource
.image_id
)
613 gles2
->DestroyImageCHROMIUM(plane_resource
.image_id
);
614 if (plane_resource
.texture_id
)
615 gles2
->DeleteTextures(1, &plane_resource
.texture_id
);
619 // Called when a VideoFrame is no longer references.
620 void GpuMemoryBufferVideoFramePool::PoolImpl::MailboxHoldersReleased(
621 FrameResources
* frame_resources
,
623 // Return the resource on the media thread.
624 media_task_runner_
->PostTask(
626 base::Bind(&PoolImpl::ReturnFrameResources
, this, frame_resources
));
629 // Put back the resoruces in the pool.
630 void GpuMemoryBufferVideoFramePool::PoolImpl::ReturnFrameResources(
631 FrameResources
* frame_resources
) {
633 auto it
= std::find(resources_pool_
.begin(), resources_pool_
.end(),
635 DCHECK(it
!= resources_pool_
.end());
636 // We want the pool to behave in a FIFO way.
637 // This minimizes the chances of locking the buffer that might be
638 // still needed for drawing.
639 std::swap(*it
, resources_pool_
.back());
640 frame_resources
->in_use
= false;
643 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool() {}
645 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool(
646 const scoped_refptr
<base::SingleThreadTaskRunner
>& media_task_runner
,
647 const scoped_refptr
<base::TaskRunner
>& worker_task_runner
,
648 const scoped_refptr
<GpuVideoAcceleratorFactories
>& gpu_factories
)
650 new PoolImpl(media_task_runner
, worker_task_runner
, gpu_factories
)) {}
652 GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() {
655 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame(
656 const scoped_refptr
<VideoFrame
>& video_frame
,
657 const FrameReadyCB
& frame_ready_cb
) {
659 pool_impl_
->CreateHardwareFrame(video_frame
, frame_ready_cb
);