| 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 DCHECK(buffer->held_by_producer); |
| 57 *memory = buffer->shared_memory.memory(); |
| 58 *size = buffer->shared_memory.mapped_size(); |
| 59 return true; |
| 60 } |
| 61 |
| 45 int VideoCaptureBufferPool::ReserveForProducer(size_t size, | 62 int VideoCaptureBufferPool::ReserveForProducer(size_t size, |
| 46 int* buffer_id_to_drop) { | 63 int* buffer_id_to_drop) { |
| 47 base::AutoLock lock(lock_); | 64 base::AutoLock lock(lock_); |
| 48 return ReserveForProducerInternal(size, buffer_id_to_drop); | 65 return ReserveForProducerInternal(size, buffer_id_to_drop); |
| 49 } | 66 } |
| 50 | 67 |
| 51 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { | 68 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { |
| 52 base::AutoLock lock(lock_); | 69 base::AutoLock lock(lock_); |
| 53 Buffer* buffer = GetBuffer(buffer_id); | 70 Buffer* buffer = GetBuffer(buffer_id); |
| 54 if (!buffer) { | 71 if (!buffer) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 83 Buffer* buffer = GetBuffer(buffer_id); | 100 Buffer* buffer = GetBuffer(buffer_id); |
| 84 if (!buffer) { | 101 if (!buffer) { |
| 85 NOTREACHED() << "Invalid buffer_id."; | 102 NOTREACHED() << "Invalid buffer_id."; |
| 86 return; | 103 return; |
| 87 } | 104 } |
| 88 DCHECK_GE(buffer->consumer_hold_count, num_clients); | 105 DCHECK_GE(buffer->consumer_hold_count, num_clients); |
| 89 | 106 |
| 90 buffer->consumer_hold_count -= num_clients; | 107 buffer->consumer_hold_count -= num_clients; |
| 91 } | 108 } |
| 92 | 109 |
| 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() | 110 VideoCaptureBufferPool::Buffer::Buffer() |
| 147 : rotation(0), | 111 : held_by_producer(false), consumer_hold_count(0) {} |
| 148 held_by_producer(false), | |
| 149 consumer_hold_count(0) {} | |
| 150 | 112 |
| 151 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, | 113 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, |
| 152 int* buffer_id_to_drop) { | 114 int* buffer_id_to_drop) { |
| 153 lock_.AssertAcquired(); | 115 lock_.AssertAcquired(); |
| 154 | 116 |
| 155 // Look for a buffer that's allocated, big enough, and not in use. | 117 // Look for a buffer that's allocated, big enough, and not in use. Track the |
| 118 // largest one that's not big enough, in case we have to reallocate a buffer. |
| 156 *buffer_id_to_drop = kInvalidId; | 119 *buffer_id_to_drop = kInvalidId; |
| 157 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { | 120 size_t realloc_size = 0; |
| 121 BufferMap::iterator realloc = buffers_.end(); |
| 122 for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); ++it) { |
| 158 Buffer* buffer = it->second; | 123 Buffer* buffer = it->second; |
| 159 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { | 124 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { |
| 160 if (buffer->shared_memory.requested_size() >= size) { | 125 if (buffer->shared_memory.requested_size() >= size) { |
| 161 // Existing buffer is big enough. Reuse it. | 126 // Existing buffer is big enough. Reuse it. |
| 162 buffer->held_by_producer = true; | 127 buffer->held_by_producer = true; |
| 163 return it->first; | 128 return it->first; |
| 164 } | 129 } |
| 130 if (buffer->shared_memory.requested_size() > realloc_size) { |
| 131 realloc_size = buffer->shared_memory.requested_size(); |
| 132 realloc = it; |
| 133 } |
| 165 } | 134 } |
| 166 } | 135 } |
| 167 | 136 |
| 168 // Look for a buffer that's not in use, that we can reallocate. | 137 // 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++) { | 138 // size, then reallocate by deleting an existing one instead. |
| 170 Buffer* buffer = it->second; | 139 if (buffers_.size() == static_cast<size_t>(count_)) { |
| 171 if (!buffer->consumer_hold_count && !buffer->held_by_producer) { | 140 if (realloc == buffers_.end()) { |
| 172 // Existing buffer is too small. Free it so we can allocate a new one | 141 // We're out of space, and can't find an unused buffer to reallocate. |
| 173 // after the loop. | 142 return kInvalidId; |
| 174 *buffer_id_to_drop = it->first; | |
| 175 buffers_.erase(it); | |
| 176 delete buffer; | |
| 177 break; | |
| 178 } | 143 } |
| 144 *buffer_id_to_drop = realloc->first; |
| 145 delete realloc->second; |
| 146 buffers_.erase(realloc); |
| 179 } | 147 } |
| 180 | 148 |
| 181 // If possible, grow the pool by creating a new buffer. | 149 // Create the new buffer. |
| 182 if (static_cast<int>(buffers_.size()) < count_) { | 150 int buffer_id = next_buffer_id_++; |
| 183 int buffer_id = next_buffer_id_++; | 151 scoped_ptr<Buffer> buffer(new Buffer()); |
| 184 scoped_ptr<Buffer> buffer(new Buffer()); | 152 if (size) { |
| 153 // |size| can be 0 for buffers that do not require memory backing. |
| 185 if (!buffer->shared_memory.CreateAndMapAnonymous(size)) | 154 if (!buffer->shared_memory.CreateAndMapAnonymous(size)) |
| 186 return kInvalidId; | 155 return kInvalidId; |
| 187 buffer->held_by_producer = true; | |
| 188 buffers_[buffer_id] = buffer.release(); | |
| 189 return buffer_id; | |
| 190 } | 156 } |
| 191 | 157 buffer->held_by_producer = true; |
| 192 // The pool is at its size limit, and all buffers are in use. | 158 buffers_[buffer_id] = buffer.release(); |
| 193 return kInvalidId; | 159 return buffer_id; |
| 194 } | 160 } |
| 195 | 161 |
| 196 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( | 162 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( |
| 197 int buffer_id) { | 163 int buffer_id) { |
| 198 BufferMap::iterator it = buffers_.find(buffer_id); | 164 BufferMap::iterator it = buffers_.find(buffer_id); |
| 199 if (it == buffers_.end()) | 165 if (it == buffers_.end()) |
| 200 return NULL; | 166 return NULL; |
| 201 return it->second; | 167 return it->second; |
| 202 } | 168 } |
| 203 | 169 |
| 204 } // namespace content | 170 } // namespace content |
| 205 | 171 |
| OLD | NEW |