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 "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "media/base/video_frame.h"
13 #include "media/base/video_util.h"
17 const int VideoCaptureBufferPool::kInvalidId
= -1;
19 VideoCaptureBufferPool::VideoCaptureBufferPool(int count
)
25 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
26 STLDeleteValues(&buffers_
);
29 base::SharedMemoryHandle
VideoCaptureBufferPool::ShareToProcess(
31 base::ProcessHandle process_handle
,
32 size_t* memory_size
) {
33 base::AutoLock
lock(lock_
);
35 Buffer
* buffer
= GetBuffer(buffer_id
);
37 NOTREACHED() << "Invalid buffer_id.";
38 return base::SharedMemory::NULLHandle();
40 base::SharedMemoryHandle remote_handle
;
41 buffer
->shared_memory
.ShareToProcess(process_handle
, &remote_handle
);
42 *memory_size
= buffer
->shared_memory
.requested_size();
46 bool VideoCaptureBufferPool::GetBufferInfo(int buffer_id
,
49 base::AutoLock
lock(lock_
);
51 Buffer
* buffer
= GetBuffer(buffer_id
);
53 NOTREACHED() << "Invalid buffer_id.";
57 DCHECK(buffer
->held_by_producer
);
58 *memory
= buffer
->shared_memory
.memory();
59 *size
= buffer
->shared_memory
.mapped_size();
63 int VideoCaptureBufferPool::ReserveForProducer(size_t size
,
64 int* buffer_id_to_drop
) {
65 base::AutoLock
lock(lock_
);
66 return ReserveForProducerInternal(size
, buffer_id_to_drop
);
69 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id
) {
70 base::AutoLock
lock(lock_
);
71 Buffer
* buffer
= GetBuffer(buffer_id
);
73 NOTREACHED() << "Invalid buffer_id.";
76 DCHECK(buffer
->held_by_producer
);
77 buffer
->held_by_producer
= false;
80 void VideoCaptureBufferPool::HoldForConsumers(
83 base::AutoLock
lock(lock_
);
84 Buffer
* buffer
= GetBuffer(buffer_id
);
86 NOTREACHED() << "Invalid buffer_id.";
89 DCHECK(buffer
->held_by_producer
);
90 DCHECK(!buffer
->consumer_hold_count
);
92 buffer
->consumer_hold_count
= num_clients
;
93 // Note: |held_by_producer| will stay true until
94 // RelinquishProducerReservation() (usually called by destructor of the object
95 // wrapping this buffer, e.g. a media::VideoFrame).
98 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id
,
100 base::AutoLock
lock(lock_
);
101 Buffer
* buffer
= GetBuffer(buffer_id
);
103 NOTREACHED() << "Invalid buffer_id.";
106 DCHECK_GE(buffer
->consumer_hold_count
, num_clients
);
108 buffer
->consumer_hold_count
-= num_clients
;
111 VideoCaptureBufferPool::Buffer::Buffer()
112 : held_by_producer(false), consumer_hold_count(0) {}
114 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size
,
115 int* buffer_id_to_drop
) {
116 lock_
.AssertAcquired();
118 // Look for a buffer that's allocated, big enough, and not in use. Track the
119 // largest one that's not big enough, in case we have to reallocate a buffer.
120 *buffer_id_to_drop
= kInvalidId
;
121 size_t realloc_size
= 0;
122 BufferMap::iterator realloc
= buffers_
.end();
123 for (BufferMap::iterator it
= buffers_
.begin(); it
!= buffers_
.end(); ++it
) {
124 Buffer
* buffer
= it
->second
;
125 if (!buffer
->consumer_hold_count
&& !buffer
->held_by_producer
) {
126 if (buffer
->shared_memory
.requested_size() >= size
) {
127 // Existing buffer is big enough. Reuse it.
128 buffer
->held_by_producer
= true;
131 if (buffer
->shared_memory
.requested_size() > realloc_size
) {
132 realloc_size
= buffer
->shared_memory
.requested_size();
138 // Preferentially grow the pool by creating a new buffer. If we're at maximum
139 // size, then reallocate by deleting an existing one instead.
140 if (buffers_
.size() == static_cast<size_t>(count_
)) {
141 if (realloc
== buffers_
.end()) {
142 // We're out of space, and can't find an unused buffer to reallocate.
145 *buffer_id_to_drop
= realloc
->first
;
146 delete realloc
->second
;
147 buffers_
.erase(realloc
);
150 // Create the new buffer.
151 int buffer_id
= next_buffer_id_
++;
152 scoped_ptr
<Buffer
> buffer(new Buffer());
154 // |size| can be 0 for buffers that do not require memory backing.
155 if (!buffer
->shared_memory
.CreateAndMapAnonymous(size
))
158 buffer
->held_by_producer
= true;
159 buffers_
[buffer_id
] = buffer
.release();
163 VideoCaptureBufferPool::Buffer
* VideoCaptureBufferPool::GetBuffer(
165 BufferMap::iterator it
= buffers_
.find(buffer_id
);
166 if (it
== buffers_
.end())
171 } // namespace content