• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "media/base/video_frame.h"
13 #include "media/base/video_util.h"
14 
15 namespace content {
16 
17 const int VideoCaptureBufferPool::kInvalidId = -1;
18 
VideoCaptureBufferPool(int count)19 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
20     : count_(count),
21       next_buffer_id_(0) {
22 }
23 
~VideoCaptureBufferPool()24 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
25   STLDeleteValues(&buffers_);
26 }
27 
ShareToProcess(int buffer_id,base::ProcessHandle process_handle,size_t * memory_size)28 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
29     int buffer_id,
30     base::ProcessHandle process_handle,
31     size_t* memory_size) {
32   base::AutoLock lock(lock_);
33 
34   Buffer* buffer = GetBuffer(buffer_id);
35   if (!buffer) {
36     NOTREACHED() << "Invalid buffer_id.";
37     return base::SharedMemory::NULLHandle();
38   }
39   base::SharedMemoryHandle remote_handle;
40   buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
41   *memory_size = buffer->shared_memory.requested_size();
42   return remote_handle;
43 }
44 
GetBufferInfo(int buffer_id,void ** memory,size_t * size)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 
ReserveForProducer(size_t size,int * buffer_id_to_drop)62 int VideoCaptureBufferPool::ReserveForProducer(size_t size,
63                                                int* buffer_id_to_drop) {
64   base::AutoLock lock(lock_);
65   return ReserveForProducerInternal(size, buffer_id_to_drop);
66 }
67 
RelinquishProducerReservation(int buffer_id)68 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
69   base::AutoLock lock(lock_);
70   Buffer* buffer = GetBuffer(buffer_id);
71   if (!buffer) {
72     NOTREACHED() << "Invalid buffer_id.";
73     return;
74   }
75   DCHECK(buffer->held_by_producer);
76   buffer->held_by_producer = false;
77 }
78 
HoldForConsumers(int buffer_id,int num_clients)79 void VideoCaptureBufferPool::HoldForConsumers(
80     int buffer_id,
81     int num_clients) {
82   base::AutoLock lock(lock_);
83   Buffer* buffer = GetBuffer(buffer_id);
84   if (!buffer) {
85     NOTREACHED() << "Invalid buffer_id.";
86     return;
87   }
88   DCHECK(buffer->held_by_producer);
89   DCHECK(!buffer->consumer_hold_count);
90 
91   buffer->consumer_hold_count = num_clients;
92   // Note: |held_by_producer| will stay true until
93   // RelinquishProducerReservation() (usually called by destructor of the object
94   // wrapping this buffer, e.g. a media::VideoFrame).
95 }
96 
RelinquishConsumerHold(int buffer_id,int num_clients)97 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
98                                                     int num_clients) {
99   base::AutoLock lock(lock_);
100   Buffer* buffer = GetBuffer(buffer_id);
101   if (!buffer) {
102     NOTREACHED() << "Invalid buffer_id.";
103     return;
104   }
105   DCHECK_GE(buffer->consumer_hold_count, num_clients);
106 
107   buffer->consumer_hold_count -= num_clients;
108 }
109 
Buffer()110 VideoCaptureBufferPool::Buffer::Buffer()
111     : held_by_producer(false), consumer_hold_count(0) {}
112 
ReserveForProducerInternal(size_t size,int * buffer_id_to_drop)113 int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size,
114                                                        int* buffer_id_to_drop) {
115   lock_.AssertAcquired();
116 
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.
119   *buffer_id_to_drop = kInvalidId;
120   size_t realloc_size = 0;
121   BufferMap::iterator realloc = buffers_.end();
122   for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); ++it) {
123     Buffer* buffer = it->second;
124     if (!buffer->consumer_hold_count && !buffer->held_by_producer) {
125       if (buffer->shared_memory.requested_size() >= size) {
126         // Existing buffer is big enough. Reuse it.
127         buffer->held_by_producer = true;
128         return it->first;
129       }
130       if (buffer->shared_memory.requested_size() > realloc_size) {
131         realloc_size = buffer->shared_memory.requested_size();
132         realloc = it;
133       }
134     }
135   }
136 
137   // Preferentially grow the pool by creating a new buffer. If we're at maximum
138   // size, then reallocate by deleting an existing one instead.
139   if (buffers_.size() == static_cast<size_t>(count_)) {
140     if (realloc == buffers_.end()) {
141       // We're out of space, and can't find an unused buffer to reallocate.
142       return kInvalidId;
143     }
144     *buffer_id_to_drop = realloc->first;
145     delete realloc->second;
146     buffers_.erase(realloc);
147   }
148 
149   // Create the new buffer.
150   int buffer_id = next_buffer_id_++;
151   scoped_ptr<Buffer> buffer(new Buffer());
152   if (size) {
153     // |size| can be 0 for buffers that do not require memory backing.
154     if (!buffer->shared_memory.CreateAndMapAnonymous(size))
155       return kInvalidId;
156   }
157   buffer->held_by_producer = true;
158   buffers_[buffer_id] = buffer.release();
159   return buffer_id;
160 }
161 
GetBuffer(int buffer_id)162 VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer(
163     int buffer_id) {
164   BufferMap::iterator it = buffers_.find(buffer_id);
165   if (it == buffers_.end())
166     return NULL;
167   return it->second;
168 }
169 
170 }  // namespace content
171 
172