1 // Copyright (c) 2013 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 "content/browser/renderer_host/media/video_capture_buffer_pool.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "media/base/video_util.h"
14 VideoCaptureBufferPool::VideoCaptureBufferPool(const gfx::Size
& size
, int count
)
19 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
22 bool VideoCaptureBufferPool::Allocate() {
23 base::AutoLock
lock(lock_
);
24 DCHECK(!IsAllocated());
25 buffers_
.resize(count_
+ 1);
27 for (int buffer_id
= 1; buffer_id
<= count(); ++buffer_id
) {
28 Buffer
* buffer
= new Buffer();
29 buffers_
[buffer_id
] = buffer
;
30 if (!buffer
->shared_memory
.CreateAndMapAnonymous(GetMemorySize())) {
37 base::SharedMemoryHandle
VideoCaptureBufferPool::ShareToProcess(
39 base::ProcessHandle process_handle
) {
40 base::AutoLock
lock(lock_
);
41 DCHECK(IsAllocated());
42 DCHECK(buffer_id
>= 1);
43 DCHECK(buffer_id
<= count_
);
44 Buffer
* buffer
= buffers_
[buffer_id
];
45 base::SharedMemoryHandle remote_handle
;
46 buffer
->shared_memory
.ShareToProcess(process_handle
, &remote_handle
);
50 scoped_refptr
<media::VideoFrame
> VideoCaptureBufferPool::ReserveForProducer(
52 base::AutoLock
lock(lock_
);
53 DCHECK(IsAllocated());
56 for (int candidate_id
= 1; candidate_id
<= count(); ++candidate_id
) {
57 Buffer
* candidate
= buffers_
[candidate_id
];
58 if (!candidate
->consumer_hold_count
&& !candidate
->held_by_producer
) {
59 buffer_id
= candidate_id
;
66 Buffer
* buffer
= buffers_
[buffer_id
];
68 CHECK_GE(buffer
->shared_memory
.requested_size(), GetMemorySize());
70 // Complete the reservation.
71 buffer
->held_by_producer
= true;
72 base::Closure disposal_handler
= base::Bind(
73 &VideoCaptureBufferPool::OnVideoFrameDestroyed
, this, buffer_id
);
75 // Wrap the buffer in a VideoFrame container.
76 uint8
* base_ptr
= static_cast<uint8
*>(buffer
->shared_memory
.memory());
77 size_t u_offset
= size_
.GetArea();
78 size_t v_offset
= u_offset
+ u_offset
/ 4;
79 scoped_refptr
<media::VideoFrame
> frame
=
80 media::VideoFrame::WrapExternalYuvData(
81 media::VideoFrame::YV12
, // Actually it's I420, but equivalent here.
82 size_
, gfx::Rect(size_
), size_
,
83 size_
.width(), // y stride
84 size_
.width() / 2, // u stride
85 size_
.width() / 2, // v stride
86 base_ptr
, // y address
87 base_ptr
+ u_offset
, // u address
88 base_ptr
+ v_offset
, // v address
89 base::TimeDelta(), // timestamp (unused).
92 if (buffer
->rotation
!= rotation
) {
93 // TODO(nick): Generalize the |rotation| mechanism.
94 media::FillYUV(frame
.get(), 0, 128, 128);
95 buffer
->rotation
= rotation
;
101 void VideoCaptureBufferPool::HoldForConsumers(
102 const scoped_refptr
<media::VideoFrame
>& producer_held_buffer
,
105 base::AutoLock
lock(lock_
);
106 DCHECK(buffer_id
>= 1);
107 DCHECK(buffer_id
<= count());
108 DCHECK(IsAllocated());
109 Buffer
* buffer
= buffers_
[buffer_id
];
110 DCHECK(buffer
->held_by_producer
);
111 DCHECK(!buffer
->consumer_hold_count
);
112 DCHECK(producer_held_buffer
->data(media::VideoFrame::kYPlane
) ==
113 buffer
->shared_memory
.memory());
115 buffer
->consumer_hold_count
= num_clients
;
116 // Note: |held_by_producer| should stay true until ~VideoFrame occurs.
119 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id
,
121 base::AutoLock
lock(lock_
);
122 DCHECK(buffer_id
>= 1);
123 DCHECK(buffer_id
<= count());
124 DCHECK_GT(num_clients
, 0);
125 DCHECK(IsAllocated());
126 Buffer
* buffer
= buffers_
[buffer_id
];
127 DCHECK_GE(buffer
->consumer_hold_count
, num_clients
);
129 buffer
->consumer_hold_count
-= num_clients
;
132 // State query functions.
133 size_t VideoCaptureBufferPool::GetMemorySize() const {
134 // No need to take |lock_| currently.
135 return size_
.GetArea() * 3 / 2;
138 int VideoCaptureBufferPool::RecognizeReservedBuffer(
139 const scoped_refptr
<media::VideoFrame
>& maybe_belongs_to_pool
) {
140 base::AutoLock
lock(lock_
);
141 uint8
* base_ptr
= maybe_belongs_to_pool
->data(media::VideoFrame::kYPlane
);
142 for (int buffer_id
= 1; buffer_id
<= count(); ++buffer_id
) {
143 Buffer
* buffer
= buffers_
[buffer_id
];
144 if (buffer
->shared_memory
.memory() == base_ptr
) {
145 DCHECK(buffer
->held_by_producer
);
149 return 0; // VideoFrame is not from our pool.
152 bool VideoCaptureBufferPool::IsAnyBufferHeldForConsumers() {
153 base::AutoLock
lock(lock_
);
154 for (int buffer_id
= 1; buffer_id
<= count(); ++buffer_id
) {
155 Buffer
* buffer
= buffers_
[buffer_id
];
156 if (buffer
->consumer_hold_count
> 0)
162 VideoCaptureBufferPool::Buffer::Buffer()
164 held_by_producer(false),
165 consumer_hold_count(0) {}
167 void VideoCaptureBufferPool::OnVideoFrameDestroyed(int buffer_id
) {
168 base::AutoLock
lock(lock_
);
170 Buffer
* buffer
= buffers_
[buffer_id
];
171 DCHECK(buffer
->held_by_producer
);
172 buffer
->held_by_producer
= false;
175 bool VideoCaptureBufferPool::IsAllocated() const {
176 lock_
.AssertAcquired();
177 return !buffers_
.empty();
180 } // namespace content