OLD | NEW |
---|---|
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/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 24 matching lines...) Expand all Loading... | |
35 if (!buffer) { | 35 if (!buffer) { |
36 NOTREACHED() << "Invalid buffer_id."; | 36 NOTREACHED() << "Invalid buffer_id."; |
37 return base::SharedMemory::NULLHandle(); | 37 return base::SharedMemory::NULLHandle(); |
38 } | 38 } |
39 base::SharedMemoryHandle remote_handle; | 39 base::SharedMemoryHandle remote_handle; |
40 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle); | 40 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle); |
41 *memory_size = buffer->shared_memory.requested_size(); | 41 *memory_size = buffer->shared_memory.requested_size(); |
42 return remote_handle; | 42 return remote_handle; |
43 } | 43 } |
44 | 44 |
45 bool VideoCaptureBufferPool::GetBufferInfo(int buffer_id, | |
46 void** memory, | |
47 size_t* size) { | |
48 base::AutoLock lock(lock_); | |
49 | |
50 Buffer* buffer = GetBuffer(buffer_id); | |
51 if (!buffer) { | |
52 NOTREACHED() << "Invalid buffer_id."; | |
53 return false; | |
54 } | |
55 | |
56 *memory = buffer->shared_memory.memory(); | |
57 *size = buffer->shared_memory.mapped_size(); | |
58 return true; | |
59 } | |
60 | |
45 int VideoCaptureBufferPool::ReserveForProducer(size_t size, | 61 int VideoCaptureBufferPool::ReserveForProducer(size_t size, |
46 int* buffer_id_to_drop) { | 62 int* buffer_id_to_drop) { |
47 base::AutoLock lock(lock_); | 63 base::AutoLock lock(lock_); |
48 return ReserveForProducerInternal(size, buffer_id_to_drop); | 64 return ReserveForProducerInternal(size, buffer_id_to_drop); |
49 } | 65 } |
50 | 66 |
51 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { | 67 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { |
52 base::AutoLock lock(lock_); | 68 base::AutoLock lock(lock_); |
53 Buffer* buffer = GetBuffer(buffer_id); | 69 Buffer* buffer = GetBuffer(buffer_id); |
54 if (!buffer) { | 70 if (!buffer) { |
(...skipping 29 matching lines...) Expand all Loading... | |
84 if (!buffer) { | 100 if (!buffer) { |
85 NOTREACHED() << "Invalid buffer_id."; | 101 NOTREACHED() << "Invalid buffer_id."; |
86 return; | 102 return; |
87 } | 103 } |
88 DCHECK_GE(buffer->consumer_hold_count, num_clients); | 104 DCHECK_GE(buffer->consumer_hold_count, num_clients); |
89 | 105 |
90 buffer->consumer_hold_count -= num_clients; | 106 buffer->consumer_hold_count -= num_clients; |
91 } | 107 } |
92 | 108 |
93 int VideoCaptureBufferPool::RecognizeReservedBuffer( | 109 int VideoCaptureBufferPool::RecognizeReservedBuffer( |
94 base::SharedMemoryHandle maybe_belongs_to_pool) { | 110 const void* maybe_belongs_to_pool) { |
95 base::AutoLock lock(lock_); | 111 base::AutoLock lock(lock_); |
96 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { | 112 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
97 if (it->second->shared_memory.handle() == maybe_belongs_to_pool) { | 113 if (it->second->shared_memory.memory() == maybe_belongs_to_pool) { |
98 DCHECK(it->second->held_by_producer); | 114 DCHECK(it->second->held_by_producer); |
99 return it->first; | 115 return it->first; |
100 } | 116 } |
101 } | 117 } |
102 return kInvalidId; // Buffer is not from our pool. | 118 return kInvalidId; // Buffer is not from our pool. |
103 } | 119 } |
104 | 120 |
105 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( | |
106 const gfx::Size& size, | |
107 int rotation, | |
108 int* buffer_id_to_drop) { | |
109 base::AutoLock lock(lock_); | |
110 | |
111 size_t frame_bytes = | |
112 media::VideoFrame::AllocationSize(media::VideoFrame::I420, size); | |
113 | |
114 int buffer_id = ReserveForProducerInternal(frame_bytes, buffer_id_to_drop); | |
115 if (buffer_id == kInvalidId) | |
116 return NULL; | |
117 | |
118 base::Closure disposal_handler = base::Bind( | |
119 &VideoCaptureBufferPool::RelinquishProducerReservation, | |
120 this, | |
121 buffer_id); | |
122 | |
123 Buffer* buffer = GetBuffer(buffer_id); | |
124 // Wrap the buffer in a VideoFrame container. | |
125 scoped_refptr<media::VideoFrame> frame = | |
126 media::VideoFrame::WrapExternalSharedMemory( | |
127 media::VideoFrame::I420, | |
128 size, | |
129 gfx::Rect(size), | |
130 size, | |
131 static_cast<uint8*>(buffer->shared_memory.memory()), | |
132 frame_bytes, | |
133 buffer->shared_memory.handle(), | |
134 base::TimeDelta(), | |
135 disposal_handler); | |
136 | |
137 if (buffer->rotation != rotation) { | |
138 // TODO(jiayl): Generalize the |rotation| mechanism. | |
139 media::FillYUV(frame.get(), 0, 128, 128); | |
140 buffer->rotation = rotation; | |
141 } | |
142 | |
143 return frame; | |
144 } | |
145 | |
146 VideoCaptureBufferPool::Buffer::Buffer() | 121 VideoCaptureBufferPool::Buffer::Buffer() |
147 : rotation(0), | 122 : held_by_producer(false), consumer_hold_count(0) {} |
148 held_by_producer(false), | |
149 consumer_hold_count(0) {} | |
150 | 123 |
151 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, | 124 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, |
152 int* buffer_id_to_drop) { | 125 int* buffer_id_to_drop) { |
153 lock_.AssertAcquired(); | 126 lock_.AssertAcquired(); |
154 | 127 |
155 // Look for a buffer that's allocated, big enough, and not in use. | 128 // Even zero-sized placeholder buffers need some memory allocation, so that |
129 // RecognizeReservedBuffer() can have some pointer to recognize. | |
ncarter (slow)
2013/11/09 01:26:38
Is there an alternative to creating a dummy shared
sheu
2013/11/11 22:37:44
I was hesitant about exporting buffer_id, but I've
| |
130 if (!size) | |
131 size = 1; | |
132 | |
133 // Look for a buffer that's allocated, big enough, and not in use. Track the | |
134 // largest one that's not big enough, in case we have to reallocate a buffer. | |
jiayl
2013/11/08 22:16:46
Why is the largest one preferred for reallocation?
sheu
2013/11/09 00:59:30
I'd like reallocations of large buffer first so we
| |
156 *buffer_id_to_drop = kInvalidId; | 135 *buffer_id_to_drop = kInvalidId; |
136 size_t realloc_size = 0; | |
137 BufferMap::iterator realloc = buffers_.end(); | |
157 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { | 138 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
158 Buffer* buffer = it->second; | 139 Buffer* buffer = it->second; |
159 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { | 140 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { |
160 if (buffer->shared_memory.requested_size() >= size) { | 141 if (buffer->shared_memory.requested_size() >= size) { |
161 // Existing buffer is big enough. Reuse it. | 142 // Existing buffer is big enough. Reuse it. |
162 buffer->held_by_producer = true; | 143 buffer->held_by_producer = true; |
163 return it->first; | 144 return it->first; |
164 } | 145 } |
146 if (buffer->shared_memory.requested_size() > realloc_size) { | |
147 realloc_size = buffer->shared_memory.requested_size(); | |
148 realloc = it; | |
149 } | |
165 } | 150 } |
166 } | 151 } |
167 | 152 |
168 // Look for a buffer that's not in use, that we can reallocate. | 153 // Preferentially grow the pool by creating a new buffer. If we're at maximum |
169 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { | 154 // size, then reallocate by deleting an existing one instead. |
170 Buffer* buffer = it->second; | 155 if (buffers_.size() == static_cast<size_t>(count_)) { |
171 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { | 156 if (realloc == buffers_.end()) { |
172 // Existing buffer is too small. Free it so we can allocate a new one | 157 // We're out of space, and can't find an unused buffer to reallocate. |
173 // after the loop. | 158 return kInvalidId; |
174 *buffer_id_to_drop = it->first; | |
175 buffers_.erase(it); | |
176 delete buffer; | |
177 break; | |
178 } | 159 } |
160 *buffer_id_to_drop = realloc->first; | |
161 delete realloc->second; | |
162 buffers_.erase(realloc); | |
179 } | 163 } |
180 | 164 |
181 // If possible, grow the pool by creating a new buffer. | 165 // Create the new buffer. |
182 if (static_cast<int>(buffers_.size()) < count_) { | 166 int buffer_id = next_buffer_id_++; |
183 int buffer_id = next_buffer_id_++; | 167 scoped_ptr<Buffer> buffer(new Buffer()); |
184 scoped_ptr<Buffer> buffer(new Buffer()); | 168 if (!buffer->shared_memory.CreateAndMapAnonymous(size)) |
185 if (!buffer->shared_memory.CreateAndMapAnonymous(size)) | 169 return kInvalidId; |
186 return kInvalidId; | 170 buffer->held_by_producer = true; |
187 buffer->held_by_producer = true; | 171 buffers_[buffer_id] = buffer.release(); |
188 buffers_[buffer_id] = buffer.release(); | 172 return buffer_id; |
189 return buffer_id; | |
190 } | |
191 | |
192 // The pool is at its size limit, and all buffers are in use. | |
193 return kInvalidId; | |
194 } | 173 } |
195 | 174 |
196 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( | 175 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( |
197 int buffer_id) { | 176 int buffer_id) { |
198 BufferMap::iterator it = buffers_.find(buffer_id); | 177 BufferMap::iterator it = buffers_.find(buffer_id); |
199 if (it == buffers_.end()) | 178 if (it == buffers_.end()) |
200 return NULL; | 179 return NULL; |
201 return it->second; | 180 return it->second; |
202 } | 181 } |
203 | 182 |
204 } // namespace content | 183 } // namespace content |
205 | 184 |
OLD | NEW |