video_capture_buffer_pool.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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 3// found in the LICENSE file. 4 5#include "content/browser/renderer_host/media/video_capture_buffer_pool.h" 6 7#include "base/bind.h" 8#include "base/callback.h" 9#include "base/logging.h" 10#include "media/base/video_frame.h" 11#include "media/base/video_util.h" 12 13namespace content { 14 15VideoCaptureBufferPool::VideoCaptureBufferPool(size_t size, int count) 16 : size_(size), 17 count_(count) { 18} 19 20VideoCaptureBufferPool::~VideoCaptureBufferPool() { 21} 22 23bool 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} 35 36base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess( 37 int buffer_id, 38 base::ProcessHandle process_handle) { 39 base::AutoLock lock(lock_); 40 DCHECK(IsAllocated()); 41 DCHECK(buffer_id >= 0); 42 DCHECK(buffer_id < count_); 43 Buffer* buffer = buffers_[buffer_id]; 44 base::SharedMemoryHandle remote_handle; 45 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle); 46 return remote_handle; 47} 48 49base::SharedMemoryHandle VideoCaptureBufferPool::GetHandle(int buffer_id) { 50 base::AutoLock lock(lock_); 51 DCHECK(IsAllocated()); 52 DCHECK(buffer_id >= 0); 53 DCHECK(buffer_id < count_); 54 return buffers_[buffer_id]->shared_memory.handle(); 55} 56 57void* 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 65int VideoCaptureBufferPool::ReserveForProducer() { 66 base::AutoLock lock(lock_); 67 return ReserveForProducerInternal(); 68} 69 70void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { 71 base::AutoLock lock(lock_); 72 DCHECK(buffer_id >= 0); 73 DCHECK(buffer_id < count()); 74 Buffer* buffer = buffers_[buffer_id]; 75 DCHECK(buffer->held_by_producer); 76 buffer->held_by_producer = false; 77} 78 79void VideoCaptureBufferPool::HoldForConsumers( 80 int buffer_id, 81 int num_clients) { 82 base::AutoLock lock(lock_); 83 DCHECK(buffer_id >= 0); 84 DCHECK(buffer_id < count()); 85 DCHECK(IsAllocated()); 86 Buffer* buffer = buffers_[buffer_id]; 87 DCHECK(buffer->held_by_producer); 88 DCHECK(!buffer->consumer_hold_count); 89 90 buffer->consumer_hold_count = num_clients; 91 // Note: |held_by_producer| will stay true until 92 // RelinquishProducerReservation() (usually called by destructor of the object 93 // wrapping this buffer, e.g. a media::VideoFrame 94} 95 96void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id, 97 int num_clients) { 98 base::AutoLock lock(lock_); 99 DCHECK(buffer_id >= 0); 100 DCHECK(buffer_id < count()); 101 DCHECK_GT(num_clients, 0); 102 DCHECK(IsAllocated()); 103 Buffer* buffer = buffers_[buffer_id]; 104 DCHECK_GE(buffer->consumer_hold_count, num_clients); 105 106 buffer->consumer_hold_count -= num_clients; 107} 108 109// State query functions. 110size_t VideoCaptureBufferPool::GetMemorySize() const { 111 // No need to take |lock_| currently. 112 return size_; 113} 114 115int VideoCaptureBufferPool::RecognizeReservedBuffer( 116 base::SharedMemoryHandle maybe_belongs_to_pool) { 117 base::AutoLock lock(lock_); 118 for (int buffer_id = 0; buffer_id < count(); ++buffer_id) { 119 Buffer* buffer = buffers_[buffer_id]; 120 if (buffer->shared_memory.handle() == maybe_belongs_to_pool) { 121 DCHECK(buffer->held_by_producer); 122 return buffer_id; 123 } 124 } 125 return -1; // Buffer is not from our pool. 126} 127 128scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( 129 const gfx::Size& size, 130 int rotation) { 131 if (GetMemorySize() != 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_); 139 140 int buffer_id = ReserveForProducerInternal(); 141 if (buffer_id < 0) 142 return NULL; 143 144 base::Closure disposal_handler = base::Bind( 145 &VideoCaptureBufferPool::RelinquishProducerReservation, 146 this, 147 buffer_id); 148 149 Buffer* buffer = buffers_[buffer_id]; 150 // Wrap the buffer in a VideoFrame container. 151 scoped_refptr<media::VideoFrame> frame = 152 media::VideoFrame::WrapExternalSharedMemory( 153 media::VideoFrame::I420, 154 size, 155 gfx::Rect(size), 156 size, 157 static_cast<uint8*>(buffer->shared_memory.memory()), 158 GetMemorySize(), 159 buffer->shared_memory.handle(), 160 base::TimeDelta(), 161 disposal_handler); 162 163 if (buffer->rotation != rotation) { 164 // TODO(nick): Generalize the |rotation| mechanism. 165 media::FillYUV(frame.get(), 0, 128, 128); 166 buffer->rotation = rotation; 167 } 168 169 return frame; 170} 171 172bool 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 182VideoCaptureBufferPool::Buffer::Buffer() 183 : rotation(0), 184 held_by_producer(false), 185 consumer_hold_count(0) {} 186 187int VideoCaptureBufferPool::ReserveForProducerInternal() { 188 lock_.AssertAcquired(); 189 DCHECK(IsAllocated()); 190 191 int buffer_id = -1; 192 for (int candidate_id = 0; candidate_id < count(); ++candidate_id) { 193 Buffer* candidate = buffers_[candidate_id]; 194 if (!candidate->consumer_hold_count && !candidate->held_by_producer) { 195 buffer_id = candidate_id; 196 break; 197 } 198 } 199 if (buffer_id == -1) 200 return -1; 201 202 Buffer* buffer = buffers_[buffer_id]; 203 CHECK_GE(buffer->shared_memory.requested_size(), size_); 204 buffer->held_by_producer = true; 205 return buffer_id; 206} 207 208bool VideoCaptureBufferPool::IsAllocated() const { 209 lock_.AssertAcquired(); 210 return !buffers_.empty(); 211} 212 213} // namespace content 214 215