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 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 |
| OLD | NEW |