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 } | |
ncarter (slow)
2013/11/12 21:14:22
Should probably add a DCHECK here that the buffer
sheu
2013/11/18 22:42:11
Done.
| |
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 28 matching lines...) Expand all Loading... | |
83 Buffer* buffer = GetBuffer(buffer_id); | 99 Buffer* buffer = GetBuffer(buffer_id); |
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( | |
94 base::SharedMemoryHandle maybe_belongs_to_pool) { | |
95 base::AutoLock lock(lock_); | |
96 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { | |
97 if (it->second->shared_memory.handle() == maybe_belongs_to_pool) { | |
98 DCHECK(it->second->held_by_producer); | |
99 return it->first; | |
100 } | |
101 } | |
102 return kInvalidId; // Buffer is not from our pool. | |
103 } | |
104 | |
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() | 109 VideoCaptureBufferPool::Buffer::Buffer() |
147 : rotation(0), | 110 : held_by_producer(false), consumer_hold_count(0) {} |
148 held_by_producer(false), | |
149 consumer_hold_count(0) {} | |
150 | 111 |
151 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, | 112 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, |
152 int* buffer_id_to_drop) { | 113 int* buffer_id_to_drop) { |
153 lock_.AssertAcquired(); | 114 lock_.AssertAcquired(); |
154 | 115 |
155 // Look for a buffer that's allocated, big enough, and not in use. | 116 // Look for a buffer that's allocated, big enough, and not in use. Track the |
117 // largest one that's not big enough, in case we have to reallocate a buffer. | |
156 *buffer_id_to_drop = kInvalidId; | 118 *buffer_id_to_drop = kInvalidId; |
119 size_t realloc_size = 0; | |
120 BufferMap::iterator realloc = buffers_.end(); | |
157 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { | 121 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
158 Buffer* buffer = it->second; | 122 Buffer* buffer = it->second; |
159 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { | 123 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { |
160 if (buffer->shared_memory.requested_size() >= size) { | 124 if (buffer->shared_memory.requested_size() >= size) { |
161 // Existing buffer is big enough. Reuse it. | 125 // Existing buffer is big enough. Reuse it. |
162 buffer->held_by_producer = true; | 126 buffer->held_by_producer = true; |
163 return it->first; | 127 return it->first; |
164 } | 128 } |
129 if (buffer->shared_memory.requested_size() > realloc_size) { | |
130 realloc_size = buffer->shared_memory.requested_size(); | |
131 realloc = it; | |
132 } | |
165 } | 133 } |
166 } | 134 } |
167 | 135 |
168 // Look for a buffer that's not in use, that we can reallocate. | 136 // 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++) { | 137 // size, then reallocate by deleting an existing one instead. |
170 Buffer* buffer = it->second; | 138 if (buffers_.size() == static_cast<size_t>(count_)) { |
171 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { | 139 if (realloc == buffers_.end()) { |
172 // Existing buffer is too small. Free it so we can allocate a new one | 140 // We're out of space, and can't find an unused buffer to reallocate. |
173 // after the loop. | 141 return kInvalidId; |
174 *buffer_id_to_drop = it->first; | |
175 buffers_.erase(it); | |
176 delete buffer; | |
177 break; | |
178 } | 142 } |
143 *buffer_id_to_drop = realloc->first; | |
144 delete realloc->second; | |
145 buffers_.erase(realloc); | |
179 } | 146 } |
180 | 147 |
181 // If possible, grow the pool by creating a new buffer. | 148 // Create the new buffer. |
182 if (static_cast<int>(buffers_.size()) < count_) { | 149 int buffer_id = next_buffer_id_++; |
183 int buffer_id = next_buffer_id_++; | 150 scoped_ptr<Buffer> buffer(new Buffer()); |
184 scoped_ptr<Buffer> buffer(new Buffer()); | 151 if (size) { |
152 // |size| can be 0 for buffers that do not require memory backing. | |
185 if (!buffer->shared_memory.CreateAndMapAnonymous(size)) | 153 if (!buffer->shared_memory.CreateAndMapAnonymous(size)) |
186 return kInvalidId; | 154 return kInvalidId; |
187 buffer->held_by_producer = true; | |
188 buffers_[buffer_id] = buffer.release(); | |
189 return buffer_id; | |
190 } | 155 } |
191 | 156 buffer->held_by_producer = true; |
192 // The pool is at its size limit, and all buffers are in use. | 157 buffers_[buffer_id] = buffer.release(); |
193 return kInvalidId; | 158 return buffer_id; |
194 } | 159 } |
195 | 160 |
196 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( | 161 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( |
197 int buffer_id) { | 162 int buffer_id) { |
198 BufferMap::iterator it = buffers_.find(buffer_id); | 163 BufferMap::iterator it = buffers_.find(buffer_id); |
199 if (it == buffers_.end()) | 164 if (it == buffers_.end()) |
200 return NULL; | 165 return NULL; |
201 return it->second; | 166 return it->second; |
202 } | 167 } |
203 | 168 |
204 } // namespace content | 169 } // namespace content |
205 | 170 |
OLD | NEW |