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