Add ICU message format support
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool.cc
blob4d3e9a1ffa3d90b50e7b50e555dcf68662d69981
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.
5 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/stl_util.h"
10 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
11 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
12 #include "content/public/browser/browser_thread.h"
14 namespace content {
16 const int VideoCaptureBufferPool::kInvalidId = -1;
18 // A simple holder of a memory-backed buffer and accesors to it.
19 class SimpleBufferHandle final : public VideoCaptureBufferPool::BufferHandle {
20 public:
21 SimpleBufferHandle(void* data, size_t size, base::SharedMemoryHandle handle)
22 : data_(data),
23 size_(size)
24 #if defined(OS_POSIX)
25 , handle_(handle)
26 #endif
29 ~SimpleBufferHandle() override {}
31 size_t size() const override { return size_; }
32 void* data() override { return data_; }
33 ClientBuffer AsClientBuffer() override { return nullptr; }
34 #if defined(OS_POSIX)
35 base::FileDescriptor AsPlatformFile() override {
36 #if defined(OS_MACOSX)
37 return handle_.GetFileDescriptor();
38 #else
39 return handle_;
40 #endif // defined(OS_MACOSX)
42 #endif
44 private:
45 void* const data_;
46 const size_t size_;
47 #if defined(OS_POSIX)
48 const base::SharedMemoryHandle handle_;
49 #endif
52 // A holder of a GpuMemoryBuffer-backed buffer, Map()ed on ctor and Unmap()ed on
53 // dtor. Holds a weak reference to its GpuMemoryBuffer.
54 // TODO(mcasas) Map()ed on ctor, or on first use?
55 class GpuMemoryBufferBufferHandle
56 final : public VideoCaptureBufferPool::BufferHandle {
57 public:
58 GpuMemoryBufferBufferHandle(gfx::GpuMemoryBuffer* gmb, size_t size)
59 : gmb_(gmb),
60 data_(new void* [GpuMemoryBufferImpl::
61 NumberOfPlanesForGpuMemoryBufferFormat(
62 gmb_->GetFormat())]),
63 size_(size) {
64 DCHECK(gmb && !gmb_->IsMapped());
65 gmb_->Map(data_.get());
67 ~GpuMemoryBufferBufferHandle() override { gmb_->Unmap(); }
69 size_t size() const override { return size_; }
70 void* data() override { return data_[0]; }
71 ClientBuffer AsClientBuffer() override { return gmb_->AsClientBuffer(); }
72 #if defined(OS_POSIX)
73 base::FileDescriptor AsPlatformFile() override {
74 #if defined(OS_MACOSX)
75 return gmb_->GetHandle().handle.GetFileDescriptor();
76 #else
77 return gmb_->GetHandle().handle;
78 #endif // defined(OS_MACOSX)
80 #endif
82 private:
83 gfx::GpuMemoryBuffer* const gmb_;
84 scoped_ptr<void*[]> data_;
85 const size_t size_;
88 // Tracker specifics for SharedMemory.
89 class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
90 public:
91 SharedMemTracker();
92 bool Init(media::VideoCapturePixelFormat format,
93 media::VideoPixelStorage storage_type,
94 const gfx::Size& dimensions) override;
96 size_t mapped_size() const override { return shared_memory_.mapped_size(); }
98 scoped_ptr<BufferHandle> GetBufferHandle() override {
99 return make_scoped_ptr(new SimpleBufferHandle(
100 shared_memory_.memory(), mapped_size(), shared_memory_.handle()));
103 bool ShareToProcess(base::ProcessHandle process_handle,
104 base::SharedMemoryHandle* new_handle) override {
105 return shared_memory_.ShareToProcess(process_handle, new_handle);
108 private:
109 // The memory created to be shared with renderer processes.
110 base::SharedMemory shared_memory_;
113 // Tracker specifics for GpuMemoryBuffer. Owns one GpuMemoryBuffer and its
114 // associated pixel dimensions.
115 class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker {
116 public:
117 GpuMemoryBufferTracker();
118 bool Init(media::VideoCapturePixelFormat format,
119 media::VideoPixelStorage storage_type,
120 const gfx::Size& dimensions) override;
121 ~GpuMemoryBufferTracker() override;
123 size_t mapped_size() const override { return packed_size_; }
124 scoped_ptr<BufferHandle> GetBufferHandle() override {
125 return make_scoped_ptr(new GpuMemoryBufferBufferHandle(
126 gpu_memory_buffer_.get(), packed_size_));
129 bool ShareToProcess(base::ProcessHandle process_handle,
130 base::SharedMemoryHandle* new_handle) override {
131 return true;
134 private:
135 size_t packed_size_;
136 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
139 VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() {
142 bool VideoCaptureBufferPool::SharedMemTracker::Init(
143 media::VideoCapturePixelFormat format,
144 media::VideoPixelStorage storage_type,
145 const gfx::Size& dimensions) {
146 DVLOG(2) << "allocating ShMem of " << dimensions.ToString();
147 set_pixel_format(format);
148 set_storage_type(storage_type);
149 // |dimensions| can be 0x0 for trackers that do not require memory backing.
150 set_pixel_count(dimensions.GetArea());
151 const size_t byte_count =
152 media::VideoCaptureFormat(dimensions, 0.0f, format, storage_type)
153 .ImageAllocationSize();
154 if (!byte_count)
155 return true;
156 return shared_memory_.CreateAndMapAnonymous(byte_count);
159 VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker()
160 : Tracker(), packed_size_(0u), gpu_memory_buffer_(nullptr) {
163 VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
164 if (gpu_memory_buffer_->IsMapped())
165 gpu_memory_buffer_->Unmap();
168 bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init(
169 media::VideoCapturePixelFormat format,
170 media::VideoPixelStorage storage_type,
171 const gfx::Size& dimensions) {
172 DVLOG(2) << "allocating GMB for " << dimensions.ToString();
173 // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread.
174 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
175 DCHECK(BrowserGpuMemoryBufferManager::current());
176 set_pixel_format(format);
177 set_storage_type(storage_type);
178 set_pixel_count(dimensions.GetArea());
179 // |dimensions| can be 0x0 for trackers that do not require memory backing.
180 if (dimensions.GetArea() == 0u)
181 return true;
182 gpu_memory_buffer_ =
183 BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer(
184 dimensions, gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::MAP);
185 DLOG_IF(ERROR, !gpu_memory_buffer_.get()) << "Allocating GpuMemoryBuffer";
186 if (!gpu_memory_buffer_.get())
187 return false;
188 int plane_sizes;
189 gpu_memory_buffer_->GetStride(&plane_sizes);
190 packed_size_ = plane_sizes * dimensions.height();
191 return true;
194 // static
195 scoped_ptr<VideoCaptureBufferPool::Tracker>
196 VideoCaptureBufferPool::Tracker::CreateTracker(bool use_gmb) {
197 if (!use_gmb)
198 return make_scoped_ptr(new SharedMemTracker());
199 else
200 return make_scoped_ptr(new GpuMemoryBufferTracker());
203 VideoCaptureBufferPool::Tracker::~Tracker() {}
205 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
206 : count_(count),
207 next_buffer_id_(0) {
208 DCHECK_GT(count, 0);
211 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
212 STLDeleteValues(&trackers_);
215 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
216 int buffer_id,
217 base::ProcessHandle process_handle,
218 size_t* memory_size) {
219 base::AutoLock lock(lock_);
221 Tracker* tracker = GetTracker(buffer_id);
222 if (!tracker) {
223 NOTREACHED() << "Invalid buffer_id.";
224 return base::SharedMemory::NULLHandle();
226 base::SharedMemoryHandle remote_handle;
227 if (tracker->ShareToProcess(process_handle, &remote_handle)) {
228 *memory_size = tracker->mapped_size();
229 return remote_handle;
231 DPLOG(ERROR) << "Error mapping Shared Memory";
232 return base::SharedMemoryHandle();
235 scoped_ptr<VideoCaptureBufferPool::BufferHandle>
236 VideoCaptureBufferPool::GetBufferHandle(int buffer_id) {
237 base::AutoLock lock(lock_);
239 Tracker* tracker = GetTracker(buffer_id);
240 if (!tracker) {
241 NOTREACHED() << "Invalid buffer_id.";
242 return scoped_ptr<BufferHandle>();
245 DCHECK(tracker->held_by_producer());
246 return tracker->GetBufferHandle();
249 int VideoCaptureBufferPool::ReserveForProducer(
250 media::VideoCapturePixelFormat format,
251 media::VideoPixelStorage storage,
252 const gfx::Size& dimensions,
253 int* buffer_id_to_drop) {
254 base::AutoLock lock(lock_);
255 return ReserveForProducerInternal(format, storage, dimensions,
256 buffer_id_to_drop);
259 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
260 base::AutoLock lock(lock_);
261 Tracker* tracker = GetTracker(buffer_id);
262 if (!tracker) {
263 NOTREACHED() << "Invalid buffer_id.";
264 return;
266 DCHECK(tracker->held_by_producer());
267 tracker->set_held_by_producer(false);
270 void VideoCaptureBufferPool::HoldForConsumers(
271 int buffer_id,
272 int num_clients) {
273 base::AutoLock lock(lock_);
274 Tracker* tracker = GetTracker(buffer_id);
275 if (!tracker) {
276 NOTREACHED() << "Invalid buffer_id.";
277 return;
279 DCHECK(tracker->held_by_producer());
280 DCHECK(!tracker->consumer_hold_count());
282 tracker->set_consumer_hold_count(num_clients);
283 // Note: |held_by_producer()| will stay true until
284 // RelinquishProducerReservation() (usually called by destructor of the object
285 // wrapping this tracker, e.g. a media::VideoFrame).
288 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
289 int num_clients) {
290 base::AutoLock lock(lock_);
291 Tracker* tracker = GetTracker(buffer_id);
292 if (!tracker) {
293 NOTREACHED() << "Invalid buffer_id.";
294 return;
296 DCHECK_GE(tracker->consumer_hold_count(), num_clients);
298 tracker->set_consumer_hold_count(tracker->consumer_hold_count() -
299 num_clients);
302 double VideoCaptureBufferPool::GetBufferPoolUtilization() const {
303 base::AutoLock lock(lock_);
304 int num_buffers_held = 0;
305 for (const auto& entry : trackers_) {
306 Tracker* const tracker = entry.second;
307 if (tracker->held_by_producer() || tracker->consumer_hold_count() > 0)
308 ++num_buffers_held;
310 return static_cast<double>(num_buffers_held) / count_;
313 int VideoCaptureBufferPool::ReserveForProducerInternal(
314 media::VideoCapturePixelFormat pixel_format,
315 media::VideoPixelStorage storage_type,
316 const gfx::Size& dimensions,
317 int* buffer_id_to_drop) {
318 lock_.AssertAcquired();
319 *buffer_id_to_drop = kInvalidId;
321 const size_t size_in_pixels = dimensions.GetArea();
322 // Look for a tracker that's allocated, big enough, and not in use. Track the
323 // largest one that's not big enough, in case we have to reallocate a tracker.
324 *buffer_id_to_drop = kInvalidId;
325 size_t largest_size_in_pixels = 0;
326 TrackerMap::iterator tracker_to_drop = trackers_.end();
327 for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end();
328 ++it) {
329 Tracker* const tracker = it->second;
330 if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) {
331 if (tracker->pixel_count() >= size_in_pixels &&
332 (tracker->pixel_format() == pixel_format) &&
333 (tracker->storage_type() == storage_type)) {
334 // Existing tracker is big enough and has correct format. Reuse it.
335 tracker->set_held_by_producer(true);
336 return it->first;
338 if (tracker->pixel_count() > largest_size_in_pixels) {
339 largest_size_in_pixels = tracker->pixel_count();
340 tracker_to_drop = it;
345 // Preferably grow the pool by creating a new tracker. If we're at maximum
346 // size, then reallocate by deleting an existing one instead.
347 if (trackers_.size() == static_cast<size_t>(count_)) {
348 if (tracker_to_drop == trackers_.end()) {
349 // We're out of space, and can't find an unused tracker to reallocate.
350 return kInvalidId;
352 *buffer_id_to_drop = tracker_to_drop->first;
353 delete tracker_to_drop->second;
354 trackers_.erase(tracker_to_drop);
357 // Create the new tracker.
358 const int buffer_id = next_buffer_id_++;
360 scoped_ptr<Tracker> tracker = Tracker::CreateTracker(
361 storage_type == media::PIXEL_STORAGE_GPUMEMORYBUFFER);
362 if (!tracker->Init(pixel_format, storage_type, dimensions)) {
363 DLOG(ERROR) << "Error initializing Tracker";
364 return kInvalidId;
366 tracker->set_held_by_producer(true);
367 trackers_[buffer_id] = tracker.release();
369 return buffer_id;
372 VideoCaptureBufferPool::Tracker* VideoCaptureBufferPool::GetTracker(
373 int buffer_id) {
374 TrackerMap::const_iterator it = trackers_.find(buffer_id);
375 return (it == trackers_.end()) ? NULL : it->second;
378 } // namespace content