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/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 |