Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool.cc
blob92523756eff74e7dc3b7b6a3ca1076ae47017f0e
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"
7 #include "base/bind.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"
15 namespace content {
17 const int VideoCaptureBufferPool::kInvalidId = -1;
19 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
20 : count_(count),
21 next_buffer_id_(0) {
24 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
25 STLDeleteValues(&buffers_);
28 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
29 int buffer_id,
30 base::ProcessHandle process_handle,
31 size_t* memory_size) {
32 base::AutoLock lock(lock_);
34 Buffer* buffer = GetBuffer(buffer_id);
35 if (!buffer) {
36 NOTREACHED() << "Invalid buffer_id.";
37 return base::SharedMemory::NULLHandle();
39 base::SharedMemoryHandle remote_handle;
40 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
41 *memory_size = buffer->shared_memory.requested_size();
42 return remote_handle;
45 bool VideoCaptureBufferPool::GetBufferInfo(int buffer_id,
46 void** memory,
47 size_t* size) {
48 base::AutoLock lock(lock_);
50 Buffer* buffer = GetBuffer(buffer_id);
51 if (!buffer) {
52 NOTREACHED() << "Invalid buffer_id.";
53 return false;
56 DCHECK(buffer->held_by_producer);
57 *memory = buffer->shared_memory.memory();
58 *size = buffer->shared_memory.mapped_size();
59 return true;
62 int VideoCaptureBufferPool::ReserveForProducer(size_t size,
63 int* buffer_id_to_drop) {
64 base::AutoLock lock(lock_);
65 return ReserveForProducerInternal(size, buffer_id_to_drop);
68 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
69 base::AutoLock lock(lock_);
70 Buffer* buffer = GetBuffer(buffer_id);
71 if (!buffer) {
72 NOTREACHED() << "Invalid buffer_id.";
73 return;
75 DCHECK(buffer->held_by_producer);
76 buffer->held_by_producer = false;
79 void VideoCaptureBufferPool::HoldForConsumers(
80 int buffer_id,
81 int num_clients) {
82 base::AutoLock lock(lock_);
83 Buffer* buffer = GetBuffer(buffer_id);
84 if (!buffer) {
85 NOTREACHED() << "Invalid buffer_id.";
86 return;
88 DCHECK(buffer->held_by_producer);
89 DCHECK(!buffer->consumer_hold_count);
91 buffer->consumer_hold_count = num_clients;
92 // Note: |held_by_producer| will stay true until
93 // RelinquishProducerReservation() (usually called by destructor of the object
94 // wrapping this buffer, e.g. a media::VideoFrame).
97 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
98 int num_clients) {
99 base::AutoLock lock(lock_);
100 Buffer* buffer = GetBuffer(buffer_id);
101 if (!buffer) {
102 NOTREACHED() << "Invalid buffer_id.";
103 return;
105 DCHECK_GE(buffer->consumer_hold_count, num_clients);
107 buffer->consumer_hold_count -= num_clients;
110 VideoCaptureBufferPool::Buffer::Buffer()
111 : held_by_producer(false), consumer_hold_count(0) {}
113 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size,
114 int* buffer_id_to_drop) {
115 lock_.AssertAcquired();
117 // Look for a buffer that's allocated, big enough, and not in use. Track the
118 // largest one that's not big enough, in case we have to reallocate a buffer.
119 *buffer_id_to_drop = kInvalidId;
120 size_t realloc_size = 0;
121 BufferMap::iterator realloc = buffers_.end();
122 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); ++it) {
123 Buffer* buffer = it->second;
124 if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
125 if (buffer->shared_memory.requested_size() >= size) {
126 // Existing buffer is big enough. Reuse it.
127 buffer->held_by_producer = true;
128 return it->first;
130 if (buffer->shared_memory.requested_size() > realloc_size) {
131 realloc_size = buffer->shared_memory.requested_size();
132 realloc = it;
137 // Preferentially grow the pool by creating a new buffer. If we're at maximum
138 // size, then reallocate by deleting an existing one instead.
139 if (buffers_.size() == static_cast<size_t>(count_)) {
140 if (realloc == buffers_.end()) {
141 // We're out of space, and can't find an unused buffer to reallocate.
142 return kInvalidId;
144 *buffer_id_to_drop = realloc->first;
145 delete realloc->second;
146 buffers_.erase(realloc);
149 // Create the new buffer.
150 int buffer_id = next_buffer_id_++;
151 scoped_ptr<Buffer> buffer(new Buffer());
152 if (size) {
153 // |size| can be 0 for buffers that do not require memory backing.
154 if (!buffer->shared_memory.CreateAndMapAnonymous(size))
155 return kInvalidId;
157 buffer->held_by_producer = true;
158 buffers_[buffer_id] = buffer.release();
159 return buffer_id;
162 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer(
163 int buffer_id) {
164 BufferMap::iterator it = buffers_.find(buffer_id);
165 if (it == buffers_.end())
166 return NULL;
167 return it->second;
170 } // namespace content