Chromium Code Reviews| 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/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 VideoCaptureBufferPool::VideoCaptureBufferPool(int count) |
| 16 : size_(size), | 17 : next_buffer_id_(0), |
| 17 count_(count) { | 18 count_(count) { |
| 18 } | 19 } |
| 19 | 20 |
| 20 VideoCaptureBufferPool::~VideoCaptureBufferPool() { | 21 VideoCaptureBufferPool::~VideoCaptureBufferPool() { |
| 21 } | 22 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 } | 23 } |
| 35 | 24 |
| 36 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess( | 25 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess( |
| 37 int buffer_id, | 26 int buffer_id, |
| 38 base::ProcessHandle process_handle) { | 27 base::ProcessHandle process_handle, |
| 28 size_t* memory_size) { | |
| 39 base::AutoLock lock(lock_); | 29 base::AutoLock lock(lock_); |
| 40 DCHECK(IsAllocated()); | 30 |
| 41 DCHECK(buffer_id >= 0); | 31 Buffer* buffer = GetBuffer(buffer_id); |
| 42 DCHECK(buffer_id < count_); | 32 if (!buffer) { |
| 43 Buffer* buffer = buffers_[buffer_id]; | 33 NOTREACHED() << "Invalid buffer_id."; |
| 34 return base::SharedMemory::NULLHandle(); | |
| 35 } | |
| 44 base::SharedMemoryHandle remote_handle; | 36 base::SharedMemoryHandle remote_handle; |
| 45 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle); | 37 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle); |
| 38 *memory_size = buffer->shared_memory.requested_size(); | |
| 46 return remote_handle; | 39 return remote_handle; |
| 47 } | 40 } |
| 48 | 41 |
| 49 base::SharedMemoryHandle VideoCaptureBufferPool::GetHandle(int buffer_id) { | 42 int VideoCaptureBufferPool::ReserveForProducer(size_t size, |
| 43 int* buffer_id_to_drop) { | |
| 50 base::AutoLock lock(lock_); | 44 base::AutoLock lock(lock_); |
| 51 DCHECK(IsAllocated()); | 45 return ReserveForProducerInternal(size, buffer_id_to_drop); |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
nit: s/Internal/_Locked/ ?
ncarter (slow)
2013/10/16 02:08:40
This name isn't introduced by this CL. I'm fine wi
| |
| 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 } | 46 } |
| 69 | 47 |
| 70 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { | 48 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { |
| 71 base::AutoLock lock(lock_); | 49 base::AutoLock lock(lock_); |
| 72 DCHECK(buffer_id >= 0); | 50 Buffer* buffer = GetBuffer(buffer_id); |
| 73 DCHECK(buffer_id < count()); | 51 if (!buffer) { |
| 74 Buffer* buffer = buffers_[buffer_id]; | 52 NOTREACHED() << "Invalid buffer_id."; |
| 53 return; | |
| 54 } | |
| 75 DCHECK(buffer->held_by_producer); | 55 DCHECK(buffer->held_by_producer); |
| 76 buffer->held_by_producer = false; | 56 buffer->held_by_producer = false; |
| 77 } | 57 } |
| 78 | 58 |
| 79 void VideoCaptureBufferPool::HoldForConsumers( | 59 void VideoCaptureBufferPool::HoldForConsumers( |
| 80 int buffer_id, | 60 int buffer_id, |
| 81 int num_clients) { | 61 int num_clients) { |
| 82 base::AutoLock lock(lock_); | 62 base::AutoLock lock(lock_); |
| 83 DCHECK(buffer_id >= 0); | 63 Buffer* buffer = GetBuffer(buffer_id); |
| 84 DCHECK(buffer_id < count()); | 64 if (!buffer) { |
| 85 DCHECK(IsAllocated()); | 65 NOTREACHED() << "Invalid buffer_id."; |
| 86 Buffer* buffer = buffers_[buffer_id]; | 66 return; |
| 67 } | |
| 87 DCHECK(buffer->held_by_producer); | 68 DCHECK(buffer->held_by_producer); |
| 88 DCHECK(!buffer->consumer_hold_count); | 69 DCHECK(!buffer->consumer_hold_count); |
| 89 | 70 |
| 90 buffer->consumer_hold_count = num_clients; | 71 buffer->consumer_hold_count = num_clients; |
| 91 // Note: |held_by_producer| will stay true until | 72 // Note: |held_by_producer| will stay true until |
| 92 // RelinquishProducerReservation() (usually called by destructor of the object | 73 // RelinquishProducerReservation() (usually called by destructor of the object |
| 93 // wrapping this buffer, e.g. a media::VideoFrame | 74 // wrapping this buffer, e.g. a media::VideoFrame). |
| 94 } | 75 } |
| 95 | 76 |
| 96 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id, | 77 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id, |
| 97 int num_clients) { | 78 int num_clients) { |
| 98 base::AutoLock lock(lock_); | 79 base::AutoLock lock(lock_); |
| 99 DCHECK(buffer_id >= 0); | 80 Buffer* buffer = GetBuffer(buffer_id); |
| 100 DCHECK(buffer_id < count()); | 81 if (!buffer) { |
| 101 DCHECK_GT(num_clients, 0); | 82 NOTREACHED() << "Invalid buffer_id."; |
| 102 DCHECK(IsAllocated()); | 83 return; |
| 103 Buffer* buffer = buffers_[buffer_id]; | 84 } |
| 104 DCHECK_GE(buffer->consumer_hold_count, num_clients); | 85 DCHECK_GE(buffer->consumer_hold_count, num_clients); |
| 105 | 86 |
| 106 buffer->consumer_hold_count -= num_clients; | 87 buffer->consumer_hold_count -= num_clients; |
| 107 } | 88 } |
| 108 | 89 |
| 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( | 90 int VideoCaptureBufferPool::RecognizeReservedBuffer( |
| 116 base::SharedMemoryHandle maybe_belongs_to_pool) { | 91 base::SharedMemoryHandle maybe_belongs_to_pool) { |
| 117 base::AutoLock lock(lock_); | 92 base::AutoLock lock(lock_); |
| 118 for (int buffer_id = 0; buffer_id < count(); ++buffer_id) { | 93 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
| 119 Buffer* buffer = buffers_[buffer_id]; | 94 if (it->second->shared_memory.handle() == maybe_belongs_to_pool) { |
| 120 if (buffer->shared_memory.handle() == maybe_belongs_to_pool) { | 95 DCHECK(it->second->held_by_producer); |
| 121 DCHECK(buffer->held_by_producer); | 96 return it->first; |
| 122 return buffer_id; | |
| 123 } | 97 } |
| 124 } | 98 } |
| 125 return -1; // Buffer is not from our pool. | 99 return kInvalidId; // Buffer is not from our pool. |
| 126 } | 100 } |
| 127 | 101 |
| 128 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( | 102 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( |
| 129 const gfx::Size& size, | 103 const gfx::Size& size, |
| 130 int rotation) { | 104 int rotation, |
| 131 if (GetMemorySize() != | 105 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_); | 106 base::AutoLock lock(lock_); |
| 139 | 107 |
| 140 int buffer_id = ReserveForProducerInternal(); | 108 size_t frame_bytes = |
| 141 if (buffer_id < 0) | 109 media::VideoFrame::AllocationSize(media::VideoFrame::I420, size); |
| 110 | |
| 111 int buffer_id = ReserveForProducerInternal(frame_bytes, buffer_id_to_drop); | |
| 112 if (buffer_id == kInvalidId) | |
| 142 return NULL; | 113 return NULL; |
| 143 | 114 |
| 144 base::Closure disposal_handler = base::Bind( | 115 base::Closure disposal_handler = base::Bind( |
| 145 &VideoCaptureBufferPool::RelinquishProducerReservation, | 116 &VideoCaptureBufferPool::RelinquishProducerReservation, |
| 146 this, | 117 this, |
| 147 buffer_id); | 118 buffer_id); |
| 148 | 119 |
| 149 Buffer* buffer = buffers_[buffer_id]; | 120 Buffer* buffer = GetBuffer(buffer_id); |
| 150 // Wrap the buffer in a VideoFrame container. | 121 // Wrap the buffer in a VideoFrame container. |
| 151 scoped_refptr<media::VideoFrame> frame = | 122 scoped_refptr<media::VideoFrame> frame = |
| 152 media::VideoFrame::WrapExternalSharedMemory( | 123 media::VideoFrame::WrapExternalSharedMemory( |
| 153 media::VideoFrame::I420, | 124 media::VideoFrame::I420, |
| 154 size, | 125 size, |
| 155 gfx::Rect(size), | 126 gfx::Rect(size), |
| 156 size, | 127 size, |
| 157 static_cast<uint8*>(buffer->shared_memory.memory()), | 128 static_cast<uint8*>(buffer->shared_memory.memory()), |
| 158 GetMemorySize(), | 129 frame_bytes, |
| 159 buffer->shared_memory.handle(), | 130 buffer->shared_memory.handle(), |
| 160 base::TimeDelta(), | 131 base::TimeDelta(), |
| 161 disposal_handler); | 132 disposal_handler); |
| 162 | 133 |
| 163 if (buffer->rotation != rotation) { | 134 if (buffer->rotation != rotation) { |
| 164 // TODO(nick): Generalize the |rotation| mechanism. | 135 // TODO(jiayl): Generalize the |rotation| mechanism. |
| 165 media::FillYUV(frame.get(), 0, 128, 128); | 136 media::FillYUV(frame.get(), 0, 128, 128); |
| 166 buffer->rotation = rotation; | 137 buffer->rotation = rotation; |
| 167 } | 138 } |
| 168 | 139 |
| 169 return frame; | 140 return frame; |
| 170 } | 141 } |
| 171 | 142 |
| 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() | 143 VideoCaptureBufferPool::Buffer::Buffer() |
| 183 : rotation(0), | 144 : rotation(0), |
| 184 held_by_producer(false), | 145 held_by_producer(false), |
| 185 consumer_hold_count(0) {} | 146 consumer_hold_count(0) {} |
| 186 | 147 |
| 187 int VideoCaptureBufferPool::ReserveForProducerInternal() { | 148 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, |
| 149 int* buffer_id_to_drop) { | |
| 188 lock_.AssertAcquired(); | 150 lock_.AssertAcquired(); |
| 189 DCHECK(IsAllocated()); | |
| 190 | 151 |
| 191 int buffer_id = -1; | 152 // Look for a buffer that's allocated but not in use. We'll reuse any buffer |
| 192 for (int candidate_id = 0; candidate_id < count(); ++candidate_id) { | 153 // that's big enough. |
| 193 Buffer* candidate = buffers_[candidate_id]; | 154 *buffer_id_to_drop = kInvalidId; |
| 194 if (!candidate->consumer_hold_count && !candidate->held_by_producer) { | 155 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
| 195 buffer_id = candidate_id; | 156 Buffer* buffer = it->second; |
| 196 break; | 157 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { |
| 158 if (buffer->shared_memory.requested_size() >= size) { | |
| 159 // Existing buffer is big enough. Reuse it. | |
| 160 buffer->held_by_producer = true; | |
| 161 return it->first; | |
| 162 } else { | |
| 163 // Existing buffer is too small. Free it so we can allocate a new one | |
| 164 // after the loop. | |
|
jiayl
2013/10/03 00:51:14
What if there is another free buffer that's big en
ncarter (slow)
2013/10/16 02:08:40
Done.
| |
| 165 *buffer_id_to_drop = it->first; | |
| 166 buffers_.erase(it); | |
| 167 delete buffer; | |
| 168 break; | |
| 169 } | |
| 197 } | 170 } |
| 198 } | 171 } |
| 199 if (buffer_id == -1) | |
| 200 return -1; | |
| 201 | 172 |
| 202 Buffer* buffer = buffers_[buffer_id]; | 173 if (static_cast<int>(buffers_.size()) < count_) { |
| 203 CHECK_GE(buffer->shared_memory.requested_size(), size_); | 174 // Grow the pool by creating a new buffer. |
| 204 buffer->held_by_producer = true; | 175 int buffer_id = next_buffer_id_++; |
| 205 return buffer_id; | 176 Buffer* buffer = new Buffer(); |
| 177 if (!buffer->shared_memory.CreateAndMapAnonymous(size)) | |
| 178 return kInvalidId; | |
| 179 buffer->held_by_producer = true; | |
| 180 buffers_[buffer_id] = buffer; | |
| 181 return buffer_id; | |
| 182 } | |
| 183 | |
| 184 // The pool is at its size limit, and all buffers are in use. | |
| 185 return kInvalidId; | |
| 206 } | 186 } |
| 207 | 187 |
| 208 bool VideoCaptureBufferPool::IsAllocated() const { | 188 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( |
| 209 lock_.AssertAcquired(); | 189 int buffer_id) { |
| 210 return !buffers_.empty(); | 190 BufferMap::iterator it = buffers_.find(buffer_id); |
| 191 if (it == buffers_.end()) | |
| 192 return NULL; | |
| 193 return it->second; | |
| 211 } | 194 } |
| 212 | 195 |
| 213 } // namespace content | 196 } // namespace content |
| 214 | 197 |
| OLD | NEW |