DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool.cc
blobf9f83907120d73bf66e931af2d473dd110113b51
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), size_(size), handle_(handle) {}
23 ~SimpleBufferHandle() override {}
25 size_t size() const override { return size_; }
26 void* data() override { return data_; }
27 ClientBuffer AsClientBuffer() override { return nullptr; }
28 #if defined(OS_POSIX)
29 base::FileDescriptor AsPlatformFile() override {
30 #if defined(OS_MACOSX)
31 return handle_.GetFileDescriptor();
32 #else
33 return handle_;
34 #endif // defined(OS_MACOSX)
36 #endif
38 private:
39 void* const data_;
40 const size_t size_;
41 const base::SharedMemoryHandle handle_;
44 // A holder of a GpuMemoryBuffer-backed buffer, Map()ed on ctor and Unmap()ed on
45 // dtor. Holds a weak reference to its GpuMemoryBuffer.
46 // TODO(mcasas) Map()ed on ctor, or on first use?
47 class GpuMemoryBufferBufferHandle
48 final : public VideoCaptureBufferPool::BufferHandle {
49 public:
50 GpuMemoryBufferBufferHandle(gfx::GpuMemoryBuffer* gmb, size_t size)
51 : gmb_(gmb),
52 data_(new void* [GpuMemoryBufferImpl::
53 NumberOfPlanesForGpuMemoryBufferFormat(
54 gmb_->GetFormat())]),
55 size_(size) {
56 DCHECK(gmb && !gmb_->IsMapped());
57 gmb_->Map(data_.get());
59 ~GpuMemoryBufferBufferHandle() override { gmb_->Unmap(); }
61 size_t size() const override { return size_; }
62 void* data() override { return data_[0]; }
63 ClientBuffer AsClientBuffer() override { return gmb_->AsClientBuffer(); }
64 #if defined(OS_POSIX)
65 base::FileDescriptor AsPlatformFile() override {
66 #if defined(OS_MACOSX)
67 return gmb_->GetHandle().handle.GetFileDescriptor();
68 #else
69 return gmb_->GetHandle().handle;
70 #endif // defined(OS_MACOSX)
72 #endif
74 private:
75 gfx::GpuMemoryBuffer* const gmb_;
76 scoped_ptr<void*[]> data_;
77 const size_t size_;
80 // Tracker specifics for SharedMemory.
81 class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
82 public:
83 SharedMemTracker();
84 bool Init(media::VideoPixelFormat format,
85 media::VideoPixelStorage storage_type,
86 const gfx::Size& dimensions) override;
88 size_t mapped_size() const override { return shared_memory_.mapped_size(); }
90 scoped_ptr<BufferHandle> GetBufferHandle() override {
91 return make_scoped_ptr(new SimpleBufferHandle(
92 shared_memory_.memory(), mapped_size(), shared_memory_.handle()));
95 bool ShareToProcess(base::ProcessHandle process_handle,
96 base::SharedMemoryHandle* new_handle) override {
97 return shared_memory_.ShareToProcess(process_handle, new_handle);
100 private:
101 // The memory created to be shared with renderer processes.
102 base::SharedMemory shared_memory_;
105 // Tracker specifics for GpuMemoryBuffer. Owns one GpuMemoryBuffer and its
106 // associated pixel dimensions.
107 class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker {
108 public:
109 GpuMemoryBufferTracker();
110 bool Init(media::VideoPixelFormat format,
111 media::VideoPixelStorage storage_type,
112 const gfx::Size& dimensions) override;
113 ~GpuMemoryBufferTracker() override;
115 size_t mapped_size() const override { return packed_size_; }
116 scoped_ptr<BufferHandle> GetBufferHandle() override {
117 return make_scoped_ptr(new GpuMemoryBufferBufferHandle(
118 gpu_memory_buffer_.get(), packed_size_));
121 bool ShareToProcess(base::ProcessHandle process_handle,
122 base::SharedMemoryHandle* new_handle) override {
123 return true;
126 private:
127 size_t packed_size_;
128 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
131 VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() {
134 bool VideoCaptureBufferPool::SharedMemTracker::Init(
135 media::VideoPixelFormat format,
136 media::VideoPixelStorage storage_type,
137 const gfx::Size& dimensions) {
138 DVLOG(2) << "allocating ShMem of " << dimensions.ToString();
139 set_pixel_format(format);
140 set_storage_type(storage_type);
141 // |dimensions| can be 0x0 for trackers that do not require memory backing.
142 set_pixel_count(dimensions.GetArea());
143 const size_t byte_count =
144 media::VideoCaptureFormat(dimensions, 0.0f, format, storage_type)
145 .ImageAllocationSize();
146 if (!byte_count)
147 return true;
148 return shared_memory_.CreateAndMapAnonymous(byte_count);
151 VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker()
152 : Tracker(), packed_size_(0u), gpu_memory_buffer_(nullptr) {
155 VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
156 if (gpu_memory_buffer_->IsMapped())
157 gpu_memory_buffer_->Unmap();
160 bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init(
161 media::VideoPixelFormat format,
162 media::VideoPixelStorage storage_type,
163 const gfx::Size& dimensions) {
164 DVLOG(2) << "allocating GMB for " << dimensions.ToString();
165 // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread.
166 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
167 DCHECK(BrowserGpuMemoryBufferManager::current());
168 set_pixel_format(format);
169 set_storage_type(storage_type);
170 set_pixel_count(dimensions.GetArea());
171 // |dimensions| can be 0x0 for trackers that do not require memory backing.
172 if (dimensions.GetArea() == 0u)
173 return true;
174 gpu_memory_buffer_ =
175 BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer(
176 dimensions,
177 gfx::GpuMemoryBuffer::BGRA_8888,
178 gfx::GpuMemoryBuffer::MAP);
179 DLOG_IF(ERROR, !gpu_memory_buffer_.get()) << "Allocating GpuMemoryBuffer";
180 if (!gpu_memory_buffer_.get())
181 return false;
182 int plane_sizes;
183 gpu_memory_buffer_->GetStride(&plane_sizes);
184 packed_size_ = plane_sizes * dimensions.height();
185 return true;
188 //static
189 scoped_ptr<VideoCaptureBufferPool::Tracker>
190 VideoCaptureBufferPool::Tracker::CreateTracker(bool use_gmb) {
191 if (!use_gmb)
192 return make_scoped_ptr(new SharedMemTracker());
193 else
194 return make_scoped_ptr(new GpuMemoryBufferTracker());
197 VideoCaptureBufferPool::Tracker::~Tracker() {}
199 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
200 : count_(count),
201 next_buffer_id_(0) {
202 DCHECK_GT(count, 0);
205 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
206 STLDeleteValues(&trackers_);
209 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
210 int buffer_id,
211 base::ProcessHandle process_handle,
212 size_t* memory_size) {
213 base::AutoLock lock(lock_);
215 Tracker* tracker = GetTracker(buffer_id);
216 if (!tracker) {
217 NOTREACHED() << "Invalid buffer_id.";
218 return base::SharedMemory::NULLHandle();
220 base::SharedMemoryHandle remote_handle;
221 if (tracker->ShareToProcess(process_handle, &remote_handle)) {
222 *memory_size = tracker->mapped_size();
223 return remote_handle;
225 DPLOG(ERROR) << "Error mapping Shared Memory";
226 return base::SharedMemoryHandle();
229 scoped_ptr<VideoCaptureBufferPool::BufferHandle>
230 VideoCaptureBufferPool::GetBufferHandle(int buffer_id) {
231 base::AutoLock lock(lock_);
233 Tracker* tracker = GetTracker(buffer_id);
234 if (!tracker) {
235 NOTREACHED() << "Invalid buffer_id.";
236 return scoped_ptr<BufferHandle>();
239 DCHECK(tracker->held_by_producer());
240 return tracker->GetBufferHandle();
243 int VideoCaptureBufferPool::ReserveForProducer(media::VideoPixelFormat format,
244 media::VideoPixelStorage storage,
245 const gfx::Size& dimensions,
246 int* buffer_id_to_drop) {
247 base::AutoLock lock(lock_);
248 return ReserveForProducerInternal(format, storage, dimensions,
249 buffer_id_to_drop);
252 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
253 base::AutoLock lock(lock_);
254 Tracker* tracker = GetTracker(buffer_id);
255 if (!tracker) {
256 NOTREACHED() << "Invalid buffer_id.";
257 return;
259 DCHECK(tracker->held_by_producer());
260 tracker->set_held_by_producer(false);
263 void VideoCaptureBufferPool::HoldForConsumers(
264 int buffer_id,
265 int num_clients) {
266 base::AutoLock lock(lock_);
267 Tracker* tracker = GetTracker(buffer_id);
268 if (!tracker) {
269 NOTREACHED() << "Invalid buffer_id.";
270 return;
272 DCHECK(tracker->held_by_producer());
273 DCHECK(!tracker->consumer_hold_count());
275 tracker->set_consumer_hold_count(num_clients);
276 // Note: |held_by_producer()| will stay true until
277 // RelinquishProducerReservation() (usually called by destructor of the object
278 // wrapping this tracker, e.g. a media::VideoFrame).
281 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
282 int num_clients) {
283 base::AutoLock lock(lock_);
284 Tracker* tracker = GetTracker(buffer_id);
285 if (!tracker) {
286 NOTREACHED() << "Invalid buffer_id.";
287 return;
289 DCHECK_GE(tracker->consumer_hold_count(), num_clients);
291 tracker->set_consumer_hold_count(tracker->consumer_hold_count() -
292 num_clients);
295 double VideoCaptureBufferPool::GetBufferPoolUtilization() const {
296 base::AutoLock lock(lock_);
297 int num_buffers_held = 0;
298 for (const auto& entry : trackers_) {
299 Tracker* const tracker = entry.second;
300 if (tracker->held_by_producer() || tracker->consumer_hold_count() > 0)
301 ++num_buffers_held;
303 return static_cast<double>(num_buffers_held) / count_;
306 int VideoCaptureBufferPool::ReserveForProducerInternal(
307 media::VideoPixelFormat pixel_format,
308 media::VideoPixelStorage storage_type,
309 const gfx::Size& dimensions,
310 int* buffer_id_to_drop) {
311 lock_.AssertAcquired();
312 *buffer_id_to_drop = kInvalidId;
314 const size_t size_in_pixels = dimensions.GetArea();
315 // Look for a tracker that's allocated, big enough, and not in use. Track the
316 // largest one that's not big enough, in case we have to reallocate a tracker.
317 *buffer_id_to_drop = kInvalidId;
318 size_t largest_size_in_pixels = 0;
319 TrackerMap::iterator tracker_to_drop = trackers_.end();
320 for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end();
321 ++it) {
322 Tracker* const tracker = it->second;
323 if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) {
324 if (tracker->pixel_count() >= size_in_pixels &&
325 (tracker->pixel_format() == pixel_format) &&
326 (tracker->storage_type() == storage_type)) {
327 // Existing tracker is big enough and has correct format. Reuse it.
328 tracker->set_held_by_producer(true);
329 return it->first;
331 if (tracker->pixel_count() > largest_size_in_pixels) {
332 largest_size_in_pixels = tracker->pixel_count();
333 tracker_to_drop = it;
338 // Preferably grow the pool by creating a new tracker. If we're at maximum
339 // size, then reallocate by deleting an existing one instead.
340 if (trackers_.size() == static_cast<size_t>(count_)) {
341 if (tracker_to_drop == trackers_.end()) {
342 // We're out of space, and can't find an unused tracker to reallocate.
343 return kInvalidId;
345 *buffer_id_to_drop = tracker_to_drop->first;
346 delete tracker_to_drop->second;
347 trackers_.erase(tracker_to_drop);
350 // Create the new tracker.
351 const int buffer_id = next_buffer_id_++;
353 scoped_ptr<Tracker> tracker = Tracker::CreateTracker(
354 storage_type == media::PIXEL_STORAGE_GPUMEMORYBUFFER);
355 if (!tracker->Init(pixel_format, storage_type, dimensions)) {
356 DLOG(ERROR) << "Error initializing Tracker";
357 return kInvalidId;
359 tracker->set_held_by_producer(true);
360 trackers_[buffer_id] = tracker.release();
362 return buffer_id;
365 VideoCaptureBufferPool::Tracker* VideoCaptureBufferPool::GetTracker(
366 int buffer_id) {
367 TrackerMap::const_iterator it = trackers_.find(buffer_id);
368 return (it == trackers_.end()) ? NULL : it->second;
371 } // namespace content