Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(520)

Side by Side Diff: content/browser/renderer_host/media/video_capture_buffer_pool.cc

Issue 23551011: From Video Capture, abolish OnFrameInfo and enable resolution changes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rework IPC serialization, VideoCaptureParams switch to composition, eliminate OnFrameInfo for PPAPI… Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" 5 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/stl_util.h"
10 #include "media/base/video_frame.h" 11 #include "media/base/video_frame.h"
11 #include "media/base/video_util.h" 12 #include "media/base/video_util.h"
12 13
13 namespace content { 14 namespace content {
14 15
15 VideoCaptureBufferPool::VideoCaptureBufferPool(size_t size, int count) 16 const int VideoCaptureBufferPool::kInvalidId = -1;
16 : size_(size), 17
17 count_(count) { 18 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
19 : count_(count),
20 next_buffer_id_(0) {
18 } 21 }
19 22
20 VideoCaptureBufferPool::~VideoCaptureBufferPool() { 23 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
21 } 24 STLDeleteValues(&buffers_);
22
23 bool VideoCaptureBufferPool::Allocate() {
24 base::AutoLock lock(lock_);
25 DCHECK(!IsAllocated());
26 buffers_.resize(count_);
27 for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
28 Buffer* buffer = new Buffer();
29 buffers_[buffer_id] = buffer;
30 if (!buffer->shared_memory.CreateAndMapAnonymous(GetMemorySize()))
31 return false;
32 }
33 return true;
34 } 25 }
35 26
36 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess( 27 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
37 int buffer_id, 28 int buffer_id,
38 base::ProcessHandle process_handle) { 29 base::ProcessHandle process_handle,
30 size_t* memory_size) {
39 base::AutoLock lock(lock_); 31 base::AutoLock lock(lock_);
40 DCHECK(IsAllocated()); 32
41 DCHECK(buffer_id >= 0); 33 Buffer* buffer = GetBuffer(buffer_id);
42 DCHECK(buffer_id < count_); 34 if (!buffer) {
43 Buffer* buffer = buffers_[buffer_id]; 35 NOTREACHED() << "Invalid buffer_id.";
36 return base::SharedMemory::NULLHandle();
37 }
44 base::SharedMemoryHandle remote_handle; 38 base::SharedMemoryHandle remote_handle;
45 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle); 39 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
40 *memory_size = buffer->shared_memory.requested_size();
46 return remote_handle; 41 return remote_handle;
47 } 42 }
48 43
49 base::SharedMemoryHandle VideoCaptureBufferPool::GetHandle(int buffer_id) { 44 int VideoCaptureBufferPool::ReserveForProducer(size_t size,
45 int* buffer_id_to_drop) {
50 base::AutoLock lock(lock_); 46 base::AutoLock lock(lock_);
51 DCHECK(IsAllocated()); 47 return ReserveForProducerInternal(size, buffer_id_to_drop);
52 DCHECK(buffer_id >= 0);
53 DCHECK(buffer_id < count_);
54 return buffers_[buffer_id]->shared_memory.handle();
55 }
56
57 void* VideoCaptureBufferPool::GetMemory(int buffer_id) {
58 base::AutoLock lock(lock_);
59 DCHECK(IsAllocated());
60 DCHECK(buffer_id >= 0);
61 DCHECK(buffer_id < count_);
62 return buffers_[buffer_id]->shared_memory.memory();
63 }
64
65 int VideoCaptureBufferPool::ReserveForProducer() {
66 base::AutoLock lock(lock_);
67 return ReserveForProducerInternal();
68 } 48 }
69 49
70 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { 50 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
71 base::AutoLock lock(lock_); 51 base::AutoLock lock(lock_);
72 DCHECK(buffer_id >= 0); 52 Buffer* buffer = GetBuffer(buffer_id);
73 DCHECK(buffer_id < count()); 53 if (!buffer) {
74 Buffer* buffer = buffers_[buffer_id]; 54 NOTREACHED() << "Invalid buffer_id.";
55 return;
56 }
75 DCHECK(buffer->held_by_producer); 57 DCHECK(buffer->held_by_producer);
76 buffer->held_by_producer = false; 58 buffer->held_by_producer = false;
77 } 59 }
78 60
79 void VideoCaptureBufferPool::HoldForConsumers( 61 void VideoCaptureBufferPool::HoldForConsumers(
80 int buffer_id, 62 int buffer_id,
81 int num_clients) { 63 int num_clients) {
82 base::AutoLock lock(lock_); 64 base::AutoLock lock(lock_);
83 DCHECK(buffer_id >= 0); 65 Buffer* buffer = GetBuffer(buffer_id);
84 DCHECK(buffer_id < count()); 66 if (!buffer) {
85 DCHECK(IsAllocated()); 67 NOTREACHED() << "Invalid buffer_id.";
86 Buffer* buffer = buffers_[buffer_id]; 68 return;
69 }
87 DCHECK(buffer->held_by_producer); 70 DCHECK(buffer->held_by_producer);
88 DCHECK(!buffer->consumer_hold_count); 71 DCHECK(!buffer->consumer_hold_count);
89 72
90 buffer->consumer_hold_count = num_clients; 73 buffer->consumer_hold_count = num_clients;
91 // Note: |held_by_producer| will stay true until 74 // Note: |held_by_producer| will stay true until
92 // RelinquishProducerReservation() (usually called by destructor of the object 75 // RelinquishProducerReservation() (usually called by destructor of the object
93 // wrapping this buffer, e.g. a media::VideoFrame 76 // wrapping this buffer, e.g. a media::VideoFrame).
94 } 77 }
95 78
96 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id, 79 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
97 int num_clients) { 80 int num_clients) {
98 base::AutoLock lock(lock_); 81 base::AutoLock lock(lock_);
99 DCHECK(buffer_id >= 0); 82 Buffer* buffer = GetBuffer(buffer_id);
100 DCHECK(buffer_id < count()); 83 if (!buffer) {
101 DCHECK_GT(num_clients, 0); 84 NOTREACHED() << "Invalid buffer_id.";
102 DCHECK(IsAllocated()); 85 return;
103 Buffer* buffer = buffers_[buffer_id]; 86 }
104 DCHECK_GE(buffer->consumer_hold_count, num_clients); 87 DCHECK_GE(buffer->consumer_hold_count, num_clients);
105 88
106 buffer->consumer_hold_count -= num_clients; 89 buffer->consumer_hold_count -= num_clients;
107 } 90 }
108 91
109 // State query functions.
110 size_t VideoCaptureBufferPool::GetMemorySize() const {
111 // No need to take |lock_| currently.
112 return size_;
113 }
114
115 int VideoCaptureBufferPool::RecognizeReservedBuffer( 92 int VideoCaptureBufferPool::RecognizeReservedBuffer(
116 base::SharedMemoryHandle maybe_belongs_to_pool) { 93 base::SharedMemoryHandle maybe_belongs_to_pool) {
117 base::AutoLock lock(lock_); 94 base::AutoLock lock(lock_);
118 for (int buffer_id = 0; buffer_id < count(); ++buffer_id) { 95 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) {
119 Buffer* buffer = buffers_[buffer_id]; 96 if (it->second->shared_memory.handle() == maybe_belongs_to_pool) {
120 if (buffer->shared_memory.handle() == maybe_belongs_to_pool) { 97 DCHECK(it->second->held_by_producer);
121 DCHECK(buffer->held_by_producer); 98 return it->first;
122 return buffer_id;
123 } 99 }
124 } 100 }
125 return -1; // Buffer is not from our pool. 101 return kInvalidId; // Buffer is not from our pool.
126 } 102 }
127 103
128 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( 104 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame(
129 const gfx::Size& size, 105 const gfx::Size& size,
130 int rotation) { 106 int rotation,
131 if (GetMemorySize() != 107 int* buffer_id_to_drop) {
132 media::VideoFrame::AllocationSize(media::VideoFrame::I420, size)) {
133 DCHECK_EQ(GetMemorySize(),
134 media::VideoFrame::AllocationSize(media::VideoFrame::I420, size));
135 return NULL;
136 }
137
138 base::AutoLock lock(lock_); 108 base::AutoLock lock(lock_);
139 109
140 int buffer_id = ReserveForProducerInternal(); 110 size_t frame_bytes =
141 if (buffer_id < 0) 111 media::VideoFrame::AllocationSize(media::VideoFrame::I420, size);
112
113 int buffer_id = ReserveForProducerInternal(frame_bytes, buffer_id_to_drop);
114 if (buffer_id == kInvalidId)
142 return NULL; 115 return NULL;
143 116
144 base::Closure disposal_handler = base::Bind( 117 base::Closure disposal_handler = base::Bind(
145 &VideoCaptureBufferPool::RelinquishProducerReservation, 118 &VideoCaptureBufferPool::RelinquishProducerReservation,
146 this, 119 this,
147 buffer_id); 120 buffer_id);
148 121
149 Buffer* buffer = buffers_[buffer_id]; 122 Buffer* buffer = GetBuffer(buffer_id);
150 // Wrap the buffer in a VideoFrame container. 123 // Wrap the buffer in a VideoFrame container.
151 scoped_refptr<media::VideoFrame> frame = 124 scoped_refptr<media::VideoFrame> frame =
152 media::VideoFrame::WrapExternalSharedMemory( 125 media::VideoFrame::WrapExternalSharedMemory(
153 media::VideoFrame::I420, 126 media::VideoFrame::I420,
154 size, 127 size,
155 gfx::Rect(size), 128 gfx::Rect(size),
156 size, 129 size,
157 static_cast<uint8*>(buffer->shared_memory.memory()), 130 static_cast<uint8*>(buffer->shared_memory.memory()),
158 GetMemorySize(), 131 frame_bytes,
159 buffer->shared_memory.handle(), 132 buffer->shared_memory.handle(),
160 base::TimeDelta(), 133 base::TimeDelta(),
161 disposal_handler); 134 disposal_handler);
162 135
163 if (buffer->rotation != rotation) { 136 if (buffer->rotation != rotation) {
164 // TODO(nick): Generalize the |rotation| mechanism. 137 // TODO(jiayl): Generalize the |rotation| mechanism.
165 media::FillYUV(frame.get(), 0, 128, 128); 138 media::FillYUV(frame.get(), 0, 128, 128);
166 buffer->rotation = rotation; 139 buffer->rotation = rotation;
167 } 140 }
168 141
169 return frame; 142 return frame;
170 } 143 }
171 144
172 bool VideoCaptureBufferPool::IsAnyBufferHeldForConsumers() {
173 base::AutoLock lock(lock_);
174 for (int buffer_id = 0; buffer_id < count(); ++buffer_id) {
175 Buffer* buffer = buffers_[buffer_id];
176 if (buffer->consumer_hold_count > 0)
177 return true;
178 }
179 return false;
180 }
181
182 VideoCaptureBufferPool::Buffer::Buffer() 145 VideoCaptureBufferPool::Buffer::Buffer()
183 : rotation(0), 146 : rotation(0),
184 held_by_producer(false), 147 held_by_producer(false),
185 consumer_hold_count(0) {} 148 consumer_hold_count(0) {}
186 149
187 int VideoCaptureBufferPool::ReserveForProducerInternal() { 150 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size,
151 int* buffer_id_to_drop) {
188 lock_.AssertAcquired(); 152 lock_.AssertAcquired();
189 DCHECK(IsAllocated());
190 153
191 int buffer_id = -1; 154 // Look for a buffer that's allocated, big enough, but not in use.
Ami GONE FROM CHROMIUM 2013/10/17 20:31:45 linguistic nit: s/but/and/
ncarter (slow) 2013/10/22 01:06:21 Done.
192 for (int candidate_id = 0; candidate_id < count(); ++candidate_id) { 155 *buffer_id_to_drop = kInvalidId;
193 Buffer* candidate = buffers_[candidate_id]; 156 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) {
194 if (!candidate->consumer_hold_count && !candidate->held_by_producer) { 157 Buffer* buffer = it->second;
195 buffer_id = candidate_id; 158 if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
159 if (buffer->shared_memory.requested_size() >= size) {
160 // Existing buffer is big enough. Reuse it.
161 buffer->held_by_producer = true;
162 return it->first;
163 }
164 }
165 }
166
167 // Look for a buffer that's not in use, that we can reallocate.
Ami GONE FROM CHROMIUM 2013/10/17 20:31:45 Is it important to only do this paragraph if buffe
ncarter (slow) 2013/10/22 01:06:21 if (buffers_.size() == count_) then it's required
168 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) {
169 Buffer* buffer = it->second;
170 if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
171 // Existing buffer is too small. Free it so we can allocate a new one
172 // after the loop.
173 *buffer_id_to_drop = it->first;
174 buffers_.erase(it);
175 delete buffer;
196 break; 176 break;
197 } 177 }
198 } 178 }
199 if (buffer_id == -1)
200 return -1;
201 179
202 Buffer* buffer = buffers_[buffer_id]; 180 // If possible, grow the pool by creating a new buffer.
203 CHECK_GE(buffer->shared_memory.requested_size(), size_); 181 if (static_cast<int>(buffers_.size()) < count_) {
Ami GONE FROM CHROMIUM 2013/10/17 20:31:45 optional: If count_ was of type size_t then the ct
ncarter (slow) 2013/10/22 01:06:21 count is 3. I am just not worried?
204 buffer->held_by_producer = true; 182 int buffer_id = next_buffer_id_++;
205 return buffer_id; 183 Buffer* buffer = new Buffer();
184 if (!buffer->shared_memory.CreateAndMapAnonymous(size))
185 return kInvalidId;
186 buffer->held_by_producer = true;
187 buffers_[buffer_id] = buffer;
188 return buffer_id;
189 }
190
191 // The pool is at its size limit, and all buffers are in use.
192 return kInvalidId;
206 } 193 }
207 194
208 bool VideoCaptureBufferPool::IsAllocated() const { 195 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer(
209 lock_.AssertAcquired(); 196 int buffer_id) {
210 return !buffers_.empty(); 197 BufferMap::iterator it = buffers_.find(buffer_id);
198 if (it == buffers_.end())
199 return NULL;
200 return it->second;
211 } 201 }
212 202
213 } // namespace content 203 } // namespace content
214 204
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698