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
,
229 DCHECK_NE(dest_stride
, 0);
230 DCHECK_LE(bytes_per_row
, std::abs(dest_stride
));
231 DCHECK_LE(bytes_per_row
, source_stride
);
232 for (int row
= first_row
; row
< first_row
+ rows
; ++row
) {
233 memcpy(output
+ dest_stride
* row
, source
+ source_stride
* row
,
239 void CopyRowsToNV12Buffer(int first_row
,
242 const scoped_refptr
<VideoFrame
>& source_frame
,
247 const base::Closure
& done
) {
248 TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "bytes_per_row", bytes_per_row
,
250 DCHECK_NE(dest_stride_y
, 0);
251 DCHECK_NE(dest_stride_uv
, 0);
252 DCHECK_LE(bytes_per_row
, std::abs(dest_stride_y
));
253 DCHECK_LE(bytes_per_row
, std::abs(dest_stride_uv
));
254 DCHECK_EQ(0, first_row
% 2);
256 source_frame
->data(VideoFrame::kYPlane
) +
257 first_row
* source_frame
->stride(VideoFrame::kYPlane
),
258 source_frame
->stride(VideoFrame::kYPlane
),
259 source_frame
->data(VideoFrame::kUPlane
) +
260 first_row
/ 2 * source_frame
->stride(VideoFrame::kUPlane
),
261 source_frame
->stride(VideoFrame::kUPlane
),
262 source_frame
->data(VideoFrame::kVPlane
) +
263 first_row
/ 2 * source_frame
->stride(VideoFrame::kVPlane
),
264 source_frame
->stride(VideoFrame::kVPlane
),
265 dest_y
+ first_row
* dest_stride_y
, dest_stride_y
,
266 dest_uv
+ first_row
/ 2 * dest_stride_uv
, dest_stride_uv
,
267 bytes_per_row
, rows
);
271 void CopyRowsToUYVYBuffer(int first_row
,
274 const scoped_refptr
<VideoFrame
>& source_frame
,
277 const base::Closure
& done
) {
278 TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width
* 2,
280 DCHECK_NE(dest_stride
, 0);
281 DCHECK_LE(width
, std::abs(dest_stride
/ 2));
282 DCHECK_EQ(0, first_row
% 2);
284 source_frame
->data(VideoFrame::kYPlane
) +
285 first_row
* source_frame
->stride(VideoFrame::kYPlane
),
286 source_frame
->stride(VideoFrame::kYPlane
),
287 source_frame
->data(VideoFrame::kUPlane
) +
288 first_row
/ 2 * source_frame
->stride(VideoFrame::kUPlane
),
289 source_frame
->stride(VideoFrame::kUPlane
),
290 source_frame
->data(VideoFrame::kVPlane
) +
291 first_row
/ 2 * source_frame
->stride(VideoFrame::kVPlane
),
292 source_frame
->stride(VideoFrame::kVPlane
),
293 output
+ first_row
* dest_stride
, dest_stride
, width
, rows
);
297 } // unnamed namespace
299 // Creates a VideoFrame backed by native textures starting from a software
301 // The data contained in |video_frame| is copied into the VideoFrame passed to
303 // This has to be called on the thread where |media_task_runner_| is current.
304 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
305 const scoped_refptr
<VideoFrame
>& video_frame
,
306 const FrameReadyCB
& frame_ready_cb
) {
307 DCHECK(media_task_runner_
->BelongsToCurrentThread());
308 if (!gpu_factories_
) {
309 frame_ready_cb
.Run(video_frame
);
313 // Lazily initialize output_format_ since VideoFrameOutputFormat() has to be
314 // called on the media_thread while this object might be instantiated on any.
315 if (output_format_
== PIXEL_FORMAT_UNKNOWN
)
316 output_format_
= gpu_factories_
->VideoFrameOutputFormat();
318 if (output_format_
== PIXEL_FORMAT_UNKNOWN
) {
319 frame_ready_cb
.Run(video_frame
);
322 switch (video_frame
->format()) {
324 case PIXEL_FORMAT_YV12
:
325 case PIXEL_FORMAT_I420
:
327 // Unsupported cases.
328 case PIXEL_FORMAT_YV12A
:
329 case PIXEL_FORMAT_YV16
:
330 case PIXEL_FORMAT_YV24
:
331 case PIXEL_FORMAT_NV12
:
332 case PIXEL_FORMAT_NV21
:
333 case PIXEL_FORMAT_UYVY
:
334 case PIXEL_FORMAT_YUY2
:
335 case PIXEL_FORMAT_ARGB
:
336 case PIXEL_FORMAT_XRGB
:
337 case PIXEL_FORMAT_RGB24
:
338 case PIXEL_FORMAT_RGB32
:
339 case PIXEL_FORMAT_MJPEG
:
340 case PIXEL_FORMAT_UNKNOWN
:
341 frame_ready_cb
.Run(video_frame
);
345 DCHECK(video_frame
->visible_rect().origin().IsOrigin());
346 const gfx::Size size
= video_frame
->visible_rect().size();
348 // Acquire resources. Incompatible ones will be dropped from the pool.
349 FrameResources
* frame_resources
=
350 GetOrCreateFrameResources(size
, output_format_
);
351 if (!frame_resources
) {
352 frame_ready_cb
.Run(video_frame
);
356 worker_task_runner_
->PostTask(
357 FROM_HERE
, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers
, this,
358 video_frame
, frame_resources
, frame_ready_cb
));
361 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone(
362 const scoped_refptr
<VideoFrame
>& video_frame
,
363 FrameResources
* frame_resources
,
364 const FrameReadyCB
& frame_ready_cb
) {
365 for (const auto& plane_resource
: frame_resources
->plane_resources
) {
366 if (plane_resource
.gpu_memory_buffer
)
367 plane_resource
.gpu_memory_buffer
->Unmap();
370 media_task_runner_
->PostTask(
372 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources
, this,
373 video_frame
, frame_resources
, frame_ready_cb
));
376 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks
377 // that will be synchronized by a barrier.
378 // After the barrier is passed OnCopiesDone will be called.
379 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
380 const scoped_refptr
<VideoFrame
>& video_frame
,
381 FrameResources
* frame_resources
,
382 const FrameReadyCB
& frame_ready_cb
) {
383 // Compute the number of tasks to post and create the barrier.
384 const size_t num_planes
= VideoFrame::NumPlanes(output_format_
);
385 const size_t planes_per_copy
= PlanesPerCopy(output_format_
);
386 gfx::Size size
= video_frame
->visible_rect().size();
388 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
) {
389 const int rows
= VideoFrame::Rows(i
, output_format_
, size
.height());
390 const int rows_per_copy
= RowsPerCopy(i
, output_format_
, size
.width());
391 copies
+= rows
/ rows_per_copy
;
392 if (rows
% rows_per_copy
)
395 base::Closure copies_done
=
396 base::Bind(&PoolImpl::OnCopiesDone
, this, video_frame
, frame_resources
,
398 base::Closure barrier
= base::BarrierClosure(copies
, copies_done
);
400 // Post all the async tasks.
401 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
) {
402 gfx::GpuMemoryBuffer
* buffer
=
403 frame_resources
->plane_resources
[i
].gpu_memory_buffer
.get();
405 DCHECK_EQ(planes_per_copy
,
406 gfx::NumberOfPlanesForBufferFormat(buffer
->GetFormat()));
407 uint8
* dest_buffers
[VideoFrame::kMaxPlanes
];
408 int dest_strides
[VideoFrame::kMaxPlanes
];
409 bool rv
= buffer
->Map(reinterpret_cast<void**>(dest_buffers
));
411 buffer
->GetStride(dest_strides
);
413 const int rows
= VideoFrame::Rows(i
, output_format_
, size
.height());
414 const int rows_per_copy
= RowsPerCopy(i
, output_format_
, size
.width());
416 for (int row
= 0; row
< rows
; row
+= rows_per_copy
) {
417 const int rows_to_copy
= std::min(rows_per_copy
, rows
- row
);
418 switch (output_format_
) {
419 case PIXEL_FORMAT_I420
: {
420 const int bytes_per_row
=
421 VideoFrame::RowBytes(i
, output_format_
, size
.width());
422 worker_task_runner_
->PostTask(
424 base::Bind(&CopyRowsToI420Buffer
, row
, rows_to_copy
,
425 bytes_per_row
, video_frame
->data(i
),
426 video_frame
->stride(i
), dest_buffers
[0],
427 dest_strides
[0], barrier
));
430 case PIXEL_FORMAT_NV12
:
431 worker_task_runner_
->PostTask(
433 base::Bind(&CopyRowsToNV12Buffer
, row
, rows_to_copy
,
434 size
.width(), video_frame
, dest_buffers
[0],
435 dest_strides
[0], dest_buffers
[1], dest_strides
[1],
438 case PIXEL_FORMAT_UYVY
:
439 worker_task_runner_
->PostTask(
441 base::Bind(&CopyRowsToUYVYBuffer
, row
, rows_to_copy
, size
.width(),
442 video_frame
, dest_buffers
[0], dest_strides
[0],
452 void GpuMemoryBufferVideoFramePool::PoolImpl::
453 BindAndCreateMailboxesHardwareFrameResources(
454 const scoped_refptr
<VideoFrame
>& video_frame
,
455 FrameResources
* frame_resources
,
456 const FrameReadyCB
& frame_ready_cb
) {
457 gpu::gles2::GLES2Interface
* gles2
= gpu_factories_
->GetGLES2Interface();
459 frame_ready_cb
.Run(video_frame
);
463 const size_t num_planes
= VideoFrame::NumPlanes(output_format_
);
464 const size_t planes_per_copy
= PlanesPerCopy(output_format_
);
465 const gfx::Size size
= video_frame
->visible_rect().size();
466 gpu::MailboxHolder mailbox_holders
[VideoFrame::kMaxPlanes
];
467 // Set up the planes creating the mailboxes needed to refer to the textures.
468 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
) {
469 PlaneResource
& plane_resource
= frame_resources
->plane_resources
[i
];
470 DCHECK(plane_resource
.gpu_memory_buffer
);
471 // Bind the texture and create or rebind the image.
472 gles2
->BindTexture(texture_target_
, plane_resource
.texture_id
);
474 if (!plane_resource
.image_id
) {
475 const size_t width
= VideoFrame::Columns(i
, output_format_
, size
.width());
476 const size_t height
= VideoFrame::Rows(i
, output_format_
, size
.height());
477 plane_resource
.image_id
= gles2
->CreateImageCHROMIUM(
478 plane_resource
.gpu_memory_buffer
->AsClientBuffer(), width
, height
,
479 ImageInternalFormat(output_format_
, i
));
481 gles2
->ReleaseTexImage2DCHROMIUM(texture_target_
,
482 plane_resource
.image_id
);
484 gles2
->BindTexImage2DCHROMIUM(texture_target_
, plane_resource
.image_id
);
486 gpu::MailboxHolder(plane_resource
.mailbox
, texture_target_
, 0);
489 // Insert a sync_point, this is needed to make sure that the textures the
490 // mailboxes refer to will be used only after all the previous commands posted
491 // in the command buffer have been processed.
492 unsigned sync_point
= gles2
->InsertSyncPointCHROMIUM();
493 for (size_t i
= 0; i
< num_planes
; i
+= planes_per_copy
)
494 mailbox_holders
[i
].sync_point
= sync_point
;
496 scoped_refptr
<VideoFrame
> frame
;
497 // Create the VideoFrame backed by native textures.
498 switch (output_format_
) {
499 case PIXEL_FORMAT_I420
:
500 frame
= VideoFrame::WrapYUV420NativeTextures(
501 mailbox_holders
[VideoFrame::kYPlane
],
502 mailbox_holders
[VideoFrame::kUPlane
],
503 mailbox_holders
[VideoFrame::kVPlane
],
504 base::Bind(&PoolImpl::MailboxHoldersReleased
, this, frame_resources
),
505 size
, video_frame
->visible_rect(), video_frame
->natural_size(),
506 video_frame
->timestamp());
507 if (video_frame
->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY
))
508 frame
->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY
, true);
510 case PIXEL_FORMAT_NV12
:
511 case PIXEL_FORMAT_UYVY
:
512 frame
= VideoFrame::WrapNativeTexture(
513 output_format_
, mailbox_holders
[VideoFrame::kYPlane
],
514 base::Bind(&PoolImpl::MailboxHoldersReleased
, this, frame_resources
),
515 size
, video_frame
->visible_rect(), video_frame
->natural_size(),
516 video_frame
->timestamp());
517 frame
->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY
, true);
522 frame_ready_cb
.Run(frame
);
525 // Destroy all the resources posting one task per FrameResources
526 // to the |media_task_runner_|.
527 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() {
528 // Delete all the resources on the media thread.
529 while (!resources_pool_
.empty()) {
530 FrameResources
* frame_resources
= resources_pool_
.front();
531 resources_pool_
.pop_front();
532 media_task_runner_
->PostTask(
533 FROM_HERE
, base::Bind(&PoolImpl::DeleteFrameResources
, gpu_factories_
,
534 base::Owned(frame_resources
)));
538 // Tries to find the resources in the pool or create them.
539 // Incompatible resources will be dropped.
540 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources
*
541 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
542 const gfx::Size
& size
,
543 VideoPixelFormat format
) {
544 auto it
= resources_pool_
.begin();
545 while (it
!= resources_pool_
.end()) {
546 FrameResources
* frame_resources
= *it
;
547 if (!frame_resources
->in_use
) {
548 if (AreFrameResourcesCompatible(frame_resources
, size
)) {
549 frame_resources
->in_use
= true;
550 return frame_resources
;
552 resources_pool_
.erase(it
++);
553 DeleteFrameResources(gpu_factories_
, frame_resources
);
554 delete frame_resources
;
561 // Create the resources.
562 gpu::gles2::GLES2Interface
* gles2
= gpu_factories_
->GetGLES2Interface();
565 gles2
->ActiveTexture(GL_TEXTURE0
);
566 size_t num_planes
= VideoFrame::NumPlanes(format
);
567 FrameResources
* frame_resources
= new FrameResources(size
);
568 resources_pool_
.push_back(frame_resources
);
569 for (size_t i
= 0; i
< num_planes
; i
+= PlanesPerCopy(format
)) {
570 PlaneResource
& plane_resource
= frame_resources
->plane_resources
[i
];
571 const size_t width
= VideoFrame::Columns(i
, format
, size
.width());
572 const size_t height
= VideoFrame::Rows(i
, format
, size
.height());
573 const gfx::Size
plane_size(width
, height
);
575 const gfx::BufferFormat buffer_format
= GpuMemoryBufferFormat(format
, i
);
576 plane_resource
.gpu_memory_buffer
= gpu_factories_
->AllocateGpuMemoryBuffer(
577 plane_size
, buffer_format
, gfx::BufferUsage::MAP
);
579 gles2
->GenTextures(1, &plane_resource
.texture_id
);
580 gles2
->BindTexture(texture_target_
, plane_resource
.texture_id
);
581 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
582 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
583 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
584 gles2
->TexParameteri(texture_target_
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
585 gles2
->GenMailboxCHROMIUM(plane_resource
.mailbox
.name
);
586 gles2
->ProduceTextureCHROMIUM(texture_target_
, plane_resource
.mailbox
.name
);
588 return frame_resources
;
592 void GpuMemoryBufferVideoFramePool::PoolImpl::DeleteFrameResources(
593 const scoped_refptr
<GpuVideoAcceleratorFactories
>& gpu_factories
,
594 FrameResources
* frame_resources
) {
595 // TODO(dcastagna): As soon as the context lost is dealt with in media,
596 // make sure that we won't execute this callback (use a weak pointer to
598 gpu::gles2::GLES2Interface
* gles2
= gpu_factories
->GetGLES2Interface();
602 for (PlaneResource
& plane_resource
: frame_resources
->plane_resources
) {
603 if (plane_resource
.image_id
)
604 gles2
->DestroyImageCHROMIUM(plane_resource
.image_id
);
605 if (plane_resource
.texture_id
)
606 gles2
->DeleteTextures(1, &plane_resource
.texture_id
);
610 // Called when a VideoFrame is no longer references.
611 void GpuMemoryBufferVideoFramePool::PoolImpl::MailboxHoldersReleased(
612 FrameResources
* frame_resources
,
614 // Return the resource on the media thread.
615 media_task_runner_
->PostTask(
617 base::Bind(&PoolImpl::ReturnFrameResources
, this, frame_resources
));
620 // Put back the resoruces in the pool.
621 void GpuMemoryBufferVideoFramePool::PoolImpl::ReturnFrameResources(
622 FrameResources
* frame_resources
) {
624 auto it
= std::find(resources_pool_
.begin(), resources_pool_
.end(),
626 DCHECK(it
!= resources_pool_
.end());
627 // We want the pool to behave in a FIFO way.
628 // This minimizes the chances of locking the buffer that might be
629 // still needed for drawing.
630 std::swap(*it
, resources_pool_
.back());
631 frame_resources
->in_use
= false;
634 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool() {}
636 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool(
637 const scoped_refptr
<base::SingleThreadTaskRunner
>& media_task_runner
,
638 const scoped_refptr
<base::TaskRunner
>& worker_task_runner
,
639 const scoped_refptr
<GpuVideoAcceleratorFactories
>& gpu_factories
)
641 new PoolImpl(media_task_runner
, worker_task_runner
, gpu_factories
)) {}
643 GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() {
646 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame(
647 const scoped_refptr
<VideoFrame
>& video_frame
,
648 const FrameReadyCB
& frame_ready_cb
) {
650 pool_impl_
->CreateHardwareFrame(video_frame
, frame_ready_cb
);