Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool.cc
blobc5298c1d6cae8dd8cf9315fbf3ad164124281505
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"
13 #include "media/base/video_frame.h"
15 using media::VideoFrame;
17 namespace content {
19 const int VideoCaptureBufferPool::kInvalidId = -1;
21 VideoFrame::Format VideoPixelFormatToVideoFrameFormat(
22 media::VideoPixelFormat pixel_format) {
23 static struct {
24 media::VideoPixelFormat pixel_format;
25 VideoFrame::Format frame_format;
26 } const kVideoPixelFormatToVideoFrameFormat[] = {
27 {media::PIXEL_FORMAT_I420, VideoFrame::I420},
28 {media::PIXEL_FORMAT_TEXTURE, VideoFrame::NATIVE_TEXTURE},
29 {media::PIXEL_FORMAT_GPUMEMORYBUFFER, VideoFrame::NATIVE_TEXTURE},
32 for (const auto& format_pair : kVideoPixelFormatToVideoFrameFormat) {
33 if (format_pair.pixel_format == pixel_format)
34 return format_pair.frame_format;
36 LOG(ERROR) << "Unsupported VideoPixelFormat "
37 << media::VideoCaptureFormat::PixelFormatToString(pixel_format);
38 return VideoFrame::UNKNOWN;
41 // A simple holder of a memory-backed buffer and accesors to it.
42 class SimpleBufferHandle final : public VideoCaptureBufferPool::BufferHandle {
43 public:
44 SimpleBufferHandle(void* data, size_t size) : data_(data), size_(size) {}
45 ~SimpleBufferHandle() override {}
47 size_t size() const override { return size_; }
48 void* data() override { return data_; }
49 ClientBuffer AsClientBuffer() override { return nullptr; }
51 private:
52 void* const data_;
53 const size_t size_;
56 // A holder of a GpuMemoryBuffer-backed buffer, Map()ed on ctor and Unmap()ed on
57 // dtor. Holds a weak reference to its GpuMemoryBuffer.
58 // TODO(mcasas) Map()ed on ctor, or on first use?
59 class GpuMemoryBufferBufferHandle
60 final : public VideoCaptureBufferPool::BufferHandle {
61 public:
62 GpuMemoryBufferBufferHandle(gfx::GpuMemoryBuffer* gmb, size_t size)
63 : gmb_(gmb),
64 data_(new void* [GpuMemoryBufferImpl::
65 NumberOfPlanesForGpuMemoryBufferFormat(
66 gmb_->GetFormat())]),
67 size_(size) {
68 DCHECK(gmb && !gmb_->IsMapped());
69 gmb_->Map(data_.get());
71 ~GpuMemoryBufferBufferHandle() override { gmb_->Unmap(); }
73 size_t size() const override { return size_; }
74 void* data() override { return data_[0]; }
75 ClientBuffer AsClientBuffer() override { return gmb_->AsClientBuffer(); }
77 private:
78 gfx::GpuMemoryBuffer* const gmb_;
79 scoped_ptr<void*[]> data_;
80 const size_t size_;
83 // Tracker specifics for SharedMemory.
84 class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
85 public:
86 SharedMemTracker();
87 bool Init(VideoFrame::Format format, const gfx::Size& dimensions) override;
89 size_t mapped_size() const override { return shared_memory_.mapped_size(); }
91 scoped_ptr<BufferHandle> GetBufferHandle() override {
92 return make_scoped_ptr(
93 new SimpleBufferHandle(shared_memory_.memory(), mapped_size()));
96 bool ShareToProcess(base::ProcessHandle process_handle,
97 base::SharedMemoryHandle* new_handle) override {
98 return shared_memory_.ShareToProcess(process_handle, new_handle);
101 private:
102 // The memory created to be shared with renderer processes.
103 base::SharedMemory shared_memory_;
106 // Tracker specifics for GpuMemoryBuffer. Owns one GpuMemoryBuffer and its
107 // associated pixel dimensions.
108 class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker {
109 public:
110 GpuMemoryBufferTracker();
111 bool Init(VideoFrame::Format format, const gfx::Size& dimensions) override;
112 ~GpuMemoryBufferTracker() override;
114 size_t mapped_size() const override { return packed_size_; }
115 scoped_ptr<BufferHandle> GetBufferHandle() override {
116 return make_scoped_ptr(new GpuMemoryBufferBufferHandle(
117 gpu_memory_buffer_.get(), packed_size_));
120 bool ShareToProcess(base::ProcessHandle process_handle,
121 base::SharedMemoryHandle* new_handle) override {
122 return true;
125 private:
126 size_t packed_size_;
127 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
130 VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() {
133 bool VideoCaptureBufferPool::SharedMemTracker::Init(
134 VideoFrame::Format format,
135 const gfx::Size& dimensions) {
136 DVLOG(2) << "allocating ShMem of " << dimensions.ToString();
137 // Input |dimensions| can be 0x0 for trackers that do not require memory
138 // backing. The allocated size is calculated using VideoFrame methods since
139 // this will be the abstraction used to wrap the underlying data.
140 set_pixel_count(dimensions.GetArea());
141 const size_t byte_count = VideoFrame::AllocationSize(format, dimensions);
142 if (!byte_count)
143 return true;
144 return shared_memory_.CreateAndMapAnonymous(byte_count);
147 VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker()
148 : Tracker(), gpu_memory_buffer_(nullptr) {}
150 VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
151 if (gpu_memory_buffer_->IsMapped())
152 gpu_memory_buffer_->Unmap();
155 bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init(
156 VideoFrame::Format format,
157 const gfx::Size& dimensions) {
158 DVLOG(2) << "allocating GMB for " << dimensions.ToString();
159 // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread.
160 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
161 DCHECK(BrowserGpuMemoryBufferManager::current());
162 set_pixel_count(dimensions.GetArea());
163 gpu_memory_buffer_ =
164 BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer(
165 dimensions,
166 gfx::GpuMemoryBuffer::BGRA_8888,
167 gfx::GpuMemoryBuffer::MAP);
168 DLOG_IF(ERROR, !gpu_memory_buffer_.get()) << "Allocating GpuMemoryBuffer";
169 if (!gpu_memory_buffer_.get())
170 return false;
171 int plane_sizes;
172 gpu_memory_buffer_->GetStride(&plane_sizes);
173 packed_size_ = plane_sizes * dimensions.height();
174 return true;
177 //static
178 scoped_ptr<VideoCaptureBufferPool::Tracker>
179 VideoCaptureBufferPool::Tracker::CreateTracker(bool use_gmb) {
180 if (!use_gmb)
181 return make_scoped_ptr(new SharedMemTracker());
182 else
183 return make_scoped_ptr(new GpuMemoryBufferTracker());
186 VideoCaptureBufferPool::Tracker::~Tracker() {}
188 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
189 : count_(count),
190 next_buffer_id_(0) {
191 DCHECK_GT(count, 0);
194 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
195 STLDeleteValues(&trackers_);
198 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
199 int buffer_id,
200 base::ProcessHandle process_handle,
201 size_t* memory_size) {
202 base::AutoLock lock(lock_);
204 Tracker* tracker = GetTracker(buffer_id);
205 if (!tracker) {
206 NOTREACHED() << "Invalid buffer_id.";
207 return base::SharedMemory::NULLHandle();
209 base::SharedMemoryHandle remote_handle;
210 if (tracker->ShareToProcess(process_handle, &remote_handle)) {
211 *memory_size = tracker->mapped_size();
212 return remote_handle;
214 DPLOG(ERROR) << "Error mapping Shared Memory";
215 return base::SharedMemoryHandle();
218 scoped_ptr<VideoCaptureBufferPool::BufferHandle>
219 VideoCaptureBufferPool::GetBufferHandle(int buffer_id) {
220 base::AutoLock lock(lock_);
222 Tracker* tracker = GetTracker(buffer_id);
223 if (!tracker) {
224 NOTREACHED() << "Invalid buffer_id.";
225 return scoped_ptr<BufferHandle>();
228 DCHECK(tracker->held_by_producer());
229 return tracker->GetBufferHandle();
232 int VideoCaptureBufferPool::ReserveForProducer(media::VideoPixelFormat format,
233 const gfx::Size& dimensions,
234 int* buffer_id_to_drop) {
235 base::AutoLock lock(lock_);
236 return ReserveForProducerInternal(format, dimensions, buffer_id_to_drop);
239 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
240 base::AutoLock lock(lock_);
241 Tracker* tracker = GetTracker(buffer_id);
242 if (!tracker) {
243 NOTREACHED() << "Invalid buffer_id.";
244 return;
246 DCHECK(tracker->held_by_producer());
247 tracker->set_held_by_producer(false);
250 void VideoCaptureBufferPool::HoldForConsumers(
251 int buffer_id,
252 int num_clients) {
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 DCHECK(!tracker->consumer_hold_count());
262 tracker->set_consumer_hold_count(num_clients);
263 // Note: |held_by_producer()| will stay true until
264 // RelinquishProducerReservation() (usually called by destructor of the object
265 // wrapping this tracker, e.g. a media::VideoFrame).
268 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
269 int num_clients) {
270 base::AutoLock lock(lock_);
271 Tracker* tracker = GetTracker(buffer_id);
272 if (!tracker) {
273 NOTREACHED() << "Invalid buffer_id.";
274 return;
276 DCHECK_GE(tracker->consumer_hold_count(), num_clients);
278 tracker->set_consumer_hold_count(tracker->consumer_hold_count() -
279 num_clients);
282 int VideoCaptureBufferPool::ReserveForProducerInternal(
283 media::VideoPixelFormat format,
284 const gfx::Size& dimensions,
285 int* buffer_id_to_drop) {
286 DCHECK(format == media::PIXEL_FORMAT_I420 ||
287 format == media::PIXEL_FORMAT_TEXTURE ||
288 format == media::PIXEL_FORMAT_GPUMEMORYBUFFER );
289 lock_.AssertAcquired();
290 *buffer_id_to_drop = kInvalidId;
292 const size_t size_in_pixels = dimensions.GetArea();
293 // Look for a tracker that's allocated, big enough, and not in use. Track the
294 // largest one that's not big enough, in case we have to reallocate a tracker.
295 *buffer_id_to_drop = kInvalidId;
296 size_t largest_size_in_pixels = 0;
297 TrackerMap::iterator tracker_to_drop = trackers_.end();
298 for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end();
299 ++it) {
300 Tracker* const tracker = it->second;
301 if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) {
302 if (tracker->pixel_count() >= size_in_pixels) {
303 // Existing tracker is big enough. Reuse it.
304 tracker->set_held_by_producer(true);
305 return it->first;
307 if (tracker->pixel_count() > largest_size_in_pixels) {
308 largest_size_in_pixels = tracker->pixel_count();
309 tracker_to_drop = it;
314 // Preferably grow the pool by creating a new tracker. If we're at maximum
315 // size, then reallocate by deleting an existing one instead.
316 if (trackers_.size() == static_cast<size_t>(count_)) {
317 if (tracker_to_drop == trackers_.end()) {
318 // We're out of space, and can't find an unused tracker to reallocate.
319 return kInvalidId;
321 *buffer_id_to_drop = tracker_to_drop->first;
322 delete tracker_to_drop->second;
323 trackers_.erase(tracker_to_drop);
326 // Create the new tracker.
327 const int buffer_id = next_buffer_id_++;
329 scoped_ptr<Tracker> tracker =
330 Tracker::CreateTracker(format == media::PIXEL_FORMAT_GPUMEMORYBUFFER);
331 if (!tracker->Init(VideoPixelFormatToVideoFrameFormat(format), dimensions)) {
332 DLOG(ERROR) << "Error initializing Tracker";
333 return kInvalidId;
335 tracker->set_held_by_producer(true);
336 trackers_[buffer_id] = tracker.release();
338 return buffer_id;
341 VideoCaptureBufferPool::Tracker* VideoCaptureBufferPool::GetTracker(
342 int buffer_id) {
343 TrackerMap::const_iterator it = trackers_.find(buffer_id);
344 return (it == trackers_.end()) ? NULL : it->second;
347 } // namespace content