Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool.cc
blob65c94975bd5fa4c97064972720a2d2264a865c12
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/bind.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "media/base/video_util.h"
12 namespace content {
14 VideoCaptureBufferPool::VideoCaptureBufferPool(const gfx::Size& size, int count)
15 : size_(size),
16 count_(count) {
19 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
22 bool VideoCaptureBufferPool::Allocate() {
23 base::AutoLock lock(lock_);
24 DCHECK(!IsAllocated());
25 buffers_.resize(count_ + 1);
26 buffers_[0] = NULL;
27 for (int buffer_id = 1; 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;
34 return true;
37 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
38 int buffer_id,
39 base::ProcessHandle process_handle) {
40 base::AutoLock lock(lock_);
41 DCHECK(IsAllocated());
42 DCHECK(buffer_id >= 1);
43 DCHECK(buffer_id <= count_);
44 Buffer* buffer = buffers_[buffer_id];
45 base::SharedMemoryHandle remote_handle;
46 buffer->shared_memory.ShareToProcess(process_handle, &remote_handle);
47 return remote_handle;
50 scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveForProducer(
51 int rotation) {
52 base::AutoLock lock(lock_);
53 DCHECK(IsAllocated());
55 int buffer_id = 0;
56 for (int candidate_id = 1; candidate_id <= count(); ++candidate_id) {
57 Buffer* candidate = buffers_[candidate_id];
58 if (!candidate->consumer_hold_count && !candidate->held_by_producer) {
59 buffer_id = candidate_id;
60 break;
63 if (!buffer_id)
64 return NULL;
66 Buffer* buffer = buffers_[buffer_id];
68 CHECK_GE(buffer->shared_memory.requested_size(), GetMemorySize());
70 // Complete the reservation.
71 buffer->held_by_producer = true;
72 base::Closure disposal_handler = base::Bind(
73 &VideoCaptureBufferPool::OnVideoFrameDestroyed, this, buffer_id);
75 // Wrap the buffer in a VideoFrame container.
76 uint8* base_ptr = static_cast<uint8*>(buffer->shared_memory.memory());
77 size_t u_offset = size_.GetArea();
78 size_t v_offset = u_offset + u_offset / 4;
79 scoped_refptr<media::VideoFrame> frame =
80 media::VideoFrame::WrapExternalYuvData(
81 media::VideoFrame::YV12, // Actually it's I420, but equivalent here.
82 size_, gfx::Rect(size_), size_,
83 size_.width(), // y stride
84 size_.width() / 2, // u stride
85 size_.width() / 2, // v stride
86 base_ptr, // y address
87 base_ptr + u_offset, // u address
88 base_ptr + v_offset, // v address
89 base::TimeDelta(), // timestamp (unused).
90 disposal_handler);
92 if (buffer->rotation != rotation) {
93 // TODO(nick): Generalize the |rotation| mechanism.
94 media::FillYUV(frame.get(), 0, 128, 128);
95 buffer->rotation = rotation;
98 return frame;
101 void VideoCaptureBufferPool::HoldForConsumers(
102 const scoped_refptr<media::VideoFrame>& producer_held_buffer,
103 int buffer_id,
104 int num_clients) {
105 base::AutoLock lock(lock_);
106 DCHECK(buffer_id >= 1);
107 DCHECK(buffer_id <= count());
108 DCHECK(IsAllocated());
109 Buffer* buffer = buffers_[buffer_id];
110 DCHECK(buffer->held_by_producer);
111 DCHECK(!buffer->consumer_hold_count);
112 DCHECK(producer_held_buffer->data(media::VideoFrame::kYPlane) ==
113 buffer->shared_memory.memory());
115 buffer->consumer_hold_count = num_clients;
116 // Note: |held_by_producer| should stay true until ~VideoFrame occurs.
119 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
120 int num_clients) {
121 base::AutoLock lock(lock_);
122 DCHECK(buffer_id >= 1);
123 DCHECK(buffer_id <= count());
124 DCHECK_GT(num_clients, 0);
125 DCHECK(IsAllocated());
126 Buffer* buffer = buffers_[buffer_id];
127 DCHECK_GE(buffer->consumer_hold_count, num_clients);
129 buffer->consumer_hold_count -= num_clients;
132 // State query functions.
133 size_t VideoCaptureBufferPool::GetMemorySize() const {
134 // No need to take |lock_| currently.
135 return size_.GetArea() * 3 / 2;
138 int VideoCaptureBufferPool::RecognizeReservedBuffer(
139 const scoped_refptr<media::VideoFrame>& maybe_belongs_to_pool) {
140 base::AutoLock lock(lock_);
141 uint8* base_ptr = maybe_belongs_to_pool->data(media::VideoFrame::kYPlane);
142 for (int buffer_id = 1; buffer_id <= count(); ++buffer_id) {
143 Buffer* buffer = buffers_[buffer_id];
144 if (buffer->shared_memory.memory() == base_ptr) {
145 DCHECK(buffer->held_by_producer);
146 return buffer_id;
149 return 0; // VideoFrame is not from our pool.
152 bool VideoCaptureBufferPool::IsAnyBufferHeldForConsumers() {
153 base::AutoLock lock(lock_);
154 for (int buffer_id = 1; buffer_id <= count(); ++buffer_id) {
155 Buffer* buffer = buffers_[buffer_id];
156 if (buffer->consumer_hold_count > 0)
157 return true;
159 return false;
162 VideoCaptureBufferPool::Buffer::Buffer()
163 : rotation(0),
164 held_by_producer(false),
165 consumer_hold_count(0) {}
167 void VideoCaptureBufferPool::OnVideoFrameDestroyed(int buffer_id) {
168 base::AutoLock lock(lock_);
169 DCHECK(buffer_id);
170 Buffer* buffer = buffers_[buffer_id];
171 DCHECK(buffer->held_by_producer);
172 buffer->held_by_producer = false;
175 bool VideoCaptureBufferPool::IsAllocated() const {
176 lock_.AssertAcquired();
177 return !buffers_.empty();
180 } // namespace content