Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Side by Side Diff: content/renderer/media/video_capture_impl.cc

Issue 1267883002: Pass GpuMemoryBuffer backed VideoFrame from browser to renderer processes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gmbtracker-multiple
Patch Set: Rebase Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // Notes about usage of this object by VideoCaptureImplManager. 5 // Notes about usage of this object by VideoCaptureImplManager.
6 // 6 //
7 // VideoCaptureImplManager access this object by using a Unretained() 7 // VideoCaptureImplManager access this object by using a Unretained()
8 // binding and tasks on the IO thread. It is then important that 8 // binding and tasks on the IO thread. It is then important that
9 // VideoCaptureImpl never post task to itself. All operations must be 9 // VideoCaptureImpl never post task to itself. All operations must be
10 // synchronous. 10 // synchronous.
11 11
12 #include "content/renderer/media/video_capture_impl.h" 12 #include "content/renderer/media/video_capture_impl.h"
13 13
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "base/thread_task_runner_handle.h" 16 #include "base/thread_task_runner_handle.h"
17 #include "content/child/child_process.h" 17 #include "content/child/child_process.h"
18 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
18 #include "content/common/media/video_capture_messages.h" 19 #include "content/common/media/video_capture_messages.h"
19 #include "media/base/bind_to_current_loop.h" 20 #include "media/base/bind_to_current_loop.h"
20 #include "media/base/limits.h" 21 #include "media/base/limits.h"
21 #include "media/base/video_frame.h" 22 #include "media/base/video_frame.h"
22 23
23 namespace content { 24 namespace content {
24 25
25 namespace { 26 namespace {
26 27
27 const int kUndefinedDeviceId = 0; 28 const int kUndefinedDeviceId = 0;
28 29
29 // This is called on an unknown thread when the VideoFrame destructor executes. 30 // This is called on an unknown thread when the VideoFrame destructor executes.
30 // As of this writing, this callback mechanism is the only interface in 31 // As of this writing, this callback mechanism is the only interface in
31 // VideoFrame to provide the final value for |release_sync_point|. 32 // VideoFrame to provide the final value for |release_sync_point|.
32 // VideoCaptureImpl::DidFinishConsumingFrame() will read the value saved here, 33 // VideoCaptureImpl::DidFinishConsumingFrame() will read the value saved here,
33 // and pass it back to the IO thread to pass back to the host via the 34 // and pass it back to the IO thread to pass back to the host via the
34 // BufferReady IPC. 35 // BufferReady IPC.
35 void SaveReleaseSyncPoint(uint32* storage, uint32 release_sync_point) { 36 void SaveReleaseSyncPoint(uint32* storage, uint32 release_sync_point) {
36 *storage = release_sync_point; 37 *storage = release_sync_point;
37 } 38 }
38 39
39 } // namespace 40 } // namespace
40 41
42 // A holder of a memory-backed buffer and accessors to it.
41 class VideoCaptureImpl::ClientBuffer 43 class VideoCaptureImpl::ClientBuffer
42 : public base::RefCountedThreadSafe<ClientBuffer> { 44 : public base::RefCountedThreadSafe<ClientBuffer> {
43 public: 45 public:
44 ClientBuffer(scoped_ptr<base::SharedMemory> buffer, 46 ClientBuffer(scoped_ptr<base::SharedMemory> buffer, size_t buffer_size)
45 size_t buffer_size) 47 : buffer_(buffer.Pass()), buffer_size_(buffer_size) {}
46 : buffer(buffer.Pass()), 48
47 buffer_size(buffer_size) {} 49 base::SharedMemory* buffer() const { return buffer_.get(); }
48 const scoped_ptr<base::SharedMemory> buffer; 50 size_t buffer_size() const { return buffer_size_; }
49 const size_t buffer_size;
50 51
51 private: 52 private:
52 friend class base::RefCountedThreadSafe<ClientBuffer>; 53 friend class base::RefCountedThreadSafe<ClientBuffer>;
53 54
54 virtual ~ClientBuffer() {} 55 virtual ~ClientBuffer() {}
55 56
57 const scoped_ptr<base::SharedMemory> buffer_;
58 const size_t buffer_size_;
59
56 DISALLOW_COPY_AND_ASSIGN(ClientBuffer); 60 DISALLOW_COPY_AND_ASSIGN(ClientBuffer);
57 }; 61 };
58 62
63 // A holder of a GpuMemoryBuffer-backed buffer, Map()ed on ctor and Unmap()ed on
64 // dtor. Creates and owns GpuMemoryBuffer instances.
65 class VideoCaptureImpl::ClientBuffer2
66 : public base::RefCountedThreadSafe<ClientBuffer2> {
67 public:
68 ClientBuffer2(
69 const std::vector<gfx::GpuMemoryBufferHandle>& client_handles,
70 const gfx::Size& size)
71 : handles_(client_handles),
72 size_(size) {
73 const media::VideoPixelFormat format = media::PIXEL_FORMAT_I420;
74 for (size_t i = 0; i < handles_.size(); ++i) {
75 const size_t width = media::VideoFrame::Columns(i, format, size_.width());
76 const size_t height = media::VideoFrame::Rows(i, format, size_.height());
77 buffers_.push_back(GpuMemoryBufferImpl::CreateFromHandle(
78 handles_[i],
79 gfx::Size(width, height),
80 gfx::BufferFormat::R_8,
81 gfx::BufferUsage::MAP,
82 base::Bind(&ClientBuffer2::DestroyGpuMemoryBuffer,
83 base::Unretained(this))));
84 void* data_ptr = nullptr;
85 buffers_[i]->Map(&data_ptr);
86 data_[i] = reinterpret_cast<uint8*>(data_ptr);
87 strides_[i] = width;
88 }
89 }
90
91 uint8* data(int plane) const { return data_[plane]; }
92 int32 stride(int plane) const { return strides_[plane]; }
93 std::vector<gfx::GpuMemoryBufferHandle> gpu_memory_buffer_handles() {
94 return handles_;
95 }
96
97 private:
98 friend class base::RefCountedThreadSafe<ClientBuffer2>;
99
100 virtual ~ClientBuffer2() {
101 for (auto& buffer : buffers_)
102 buffer->Unmap();
103 }
104
105 void DestroyGpuMemoryBuffer(uint32 sync_point) {}
106
107 const std::vector<gfx::GpuMemoryBufferHandle> handles_;
108 const gfx::Size size_;
109 ScopedVector<gfx::GpuMemoryBuffer> buffers_;
110 uint8* data_[media::VideoFrame::kMaxPlanes];
111 int32 strides_[media::VideoFrame::kMaxPlanes];
112
113 DISALLOW_COPY_AND_ASSIGN(ClientBuffer2);
114 };
115
59 VideoCaptureImpl::VideoCaptureImpl( 116 VideoCaptureImpl::VideoCaptureImpl(
60 const media::VideoCaptureSessionId session_id, 117 const media::VideoCaptureSessionId session_id,
61 VideoCaptureMessageFilter* filter) 118 VideoCaptureMessageFilter* filter)
62 : message_filter_(filter), 119 : message_filter_(filter),
63 device_id_(kUndefinedDeviceId), 120 device_id_(kUndefinedDeviceId),
64 session_id_(session_id), 121 session_id_(session_id),
65 state_(VIDEO_CAPTURE_STATE_STOPPED), 122 state_(VIDEO_CAPTURE_STATE_STOPPED),
66 weak_factory_(this) { 123 weak_factory_(this) {
67 DCHECK(filter); 124 DCHECK(filter);
68 } 125 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 196
140 void VideoCaptureImpl::StopCapture() { 197 void VideoCaptureImpl::StopCapture() {
141 DCHECK(io_task_runner_->BelongsToCurrentThread()); 198 DCHECK(io_task_runner_->BelongsToCurrentThread());
142 if (state_ == VIDEO_CAPTURE_STATE_STOPPED || !IsInitialized()) 199 if (state_ == VIDEO_CAPTURE_STATE_STOPPED || !IsInitialized())
143 return; 200 return;
144 201
145 DVLOG(1) << "StopCapture: Stopping capture."; 202 DVLOG(1) << "StopCapture: Stopping capture.";
146 state_update_cb_.Run(VIDEO_CAPTURE_STATE_STOPPED); 203 state_update_cb_.Run(VIDEO_CAPTURE_STATE_STOPPED);
147 StopDevice(); 204 StopDevice();
148 client_buffers_.clear(); 205 client_buffers_.clear();
206 client_buffer2s_.clear();
149 ResetClient(); 207 ResetClient();
150 weak_factory_.InvalidateWeakPtrs(); 208 weak_factory_.InvalidateWeakPtrs();
151 } 209 }
152 210
153 void VideoCaptureImpl::GetDeviceSupportedFormats( 211 void VideoCaptureImpl::GetDeviceSupportedFormats(
154 const VideoCaptureDeviceFormatsCB& callback) { 212 const VideoCaptureDeviceFormatsCB& callback) {
155 DCHECK(io_task_runner_->BelongsToCurrentThread()); 213 DCHECK(io_task_runner_->BelongsToCurrentThread());
156 device_formats_cb_queue_.push_back(callback); 214 device_formats_cb_queue_.push_back(callback);
157 if (device_formats_cb_queue_.size() == 1) 215 if (device_formats_cb_queue_.size() == 1)
158 Send(new VideoCaptureHostMsg_GetDeviceSupportedFormats(device_id_, 216 Send(new VideoCaptureHostMsg_GetDeviceSupportedFormats(device_id_,
(...skipping 19 matching lines...) Expand all
178 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { 236 if (state_ != VIDEO_CAPTURE_STATE_STARTED) {
179 base::SharedMemory::CloseHandle(handle); 237 base::SharedMemory::CloseHandle(handle);
180 return; 238 return;
181 } 239 }
182 240
183 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false)); 241 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false));
184 if (!shm->Map(length)) { 242 if (!shm->Map(length)) {
185 DLOG(ERROR) << "OnBufferCreated: Map failed."; 243 DLOG(ERROR) << "OnBufferCreated: Map failed.";
186 return; 244 return;
187 } 245 }
188
189 const bool inserted = 246 const bool inserted =
190 client_buffers_.insert(std::make_pair(buffer_id, new ClientBuffer( 247 client_buffers_.insert(std::make_pair(buffer_id, new ClientBuffer(
191 shm.Pass(), length))) 248 shm.Pass(), length)))
192 .second; 249 .second;
193 DCHECK(inserted); 250 DCHECK(inserted);
194 } 251 }
195 252
253 void VideoCaptureImpl::OnBufferCreated2(
254 const std::vector<gfx::GpuMemoryBufferHandle>& handles,
255 const gfx::Size& size,
256 int buffer_id) {
257 DCHECK(io_task_runner_->BelongsToCurrentThread());
258
259 // In case client calls StopCapture before the arrival of created buffer,
260 // just close this buffer and return.
261 if (state_ != VIDEO_CAPTURE_STATE_STARTED)
262 return;
263
264 const bool inserted =
265 client_buffer2s_.insert(std::make_pair(buffer_id,
266 new ClientBuffer2(handles, size)))
267 .second;
268 DCHECK(inserted);
269 }
270
196 void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { 271 void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) {
197 DCHECK(io_task_runner_->BelongsToCurrentThread()); 272 DCHECK(io_task_runner_->BelongsToCurrentThread());
198 273
199 const ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); 274 const auto& cb_iter = client_buffers_.find(buffer_id);
200 if (iter == client_buffers_.end()) 275 if (cb_iter != client_buffers_.end()) {
201 return; 276 DCHECK(!cb_iter->second.get() || cb_iter->second->HasOneRef())
202 277 << "Instructed to delete buffer we are still using.";
203 DCHECK(!iter->second.get() || iter->second->HasOneRef()) 278 client_buffers_.erase(cb_iter);
204 << "Instructed to delete buffer we are still using."; 279 } else {
205 client_buffers_.erase(iter); 280 const auto& cb2_iter = client_buffer2s_.find(buffer_id);
281 if (cb2_iter != client_buffer2s_.end()) {
282 DCHECK(!cb2_iter->second.get() || cb2_iter->second->HasOneRef())
283 << "Instructed to delete buffer we are still using.";
284 client_buffer2s_.erase(cb2_iter);
285 }
286 }
206 } 287 }
207 288
208 void VideoCaptureImpl::OnBufferReceived( 289 void VideoCaptureImpl::OnBufferReceived(
209 int buffer_id, 290 int buffer_id,
210 base::TimeTicks timestamp, 291 base::TimeTicks timestamp,
211 const base::DictionaryValue& metadata, 292 const base::DictionaryValue& metadata,
212 media::VideoPixelFormat pixel_format, 293 media::VideoPixelFormat pixel_format,
213 media::VideoFrame::StorageType storage_type, 294 media::VideoFrame::StorageType storage_type,
214 const gfx::Size& coded_size, 295 const gfx::Size& coded_size,
215 const gfx::Rect& visible_rect, 296 const gfx::Rect& visible_rect,
216 const gpu::MailboxHolder& mailbox_holder) { 297 const gpu::MailboxHolder& mailbox_holder) {
217 DCHECK(io_task_runner_->BelongsToCurrentThread()); 298 DCHECK(io_task_runner_->BelongsToCurrentThread());
218 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { 299 if (state_ != VIDEO_CAPTURE_STATE_STARTED) {
219 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0, -1.0)); 300 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0, -1.0));
220 return; 301 return;
221 } 302 }
222 if (first_frame_timestamp_.is_null()) 303 if (first_frame_timestamp_.is_null())
223 first_frame_timestamp_ = timestamp; 304 first_frame_timestamp_ = timestamp;
224 305
225 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc 306 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
226 TRACE_EVENT_INSTANT2("cast_perf_test", "OnBufferReceived", 307 TRACE_EVENT_INSTANT2("cast_perf_test", "OnBufferReceived",
227 TRACE_EVENT_SCOPE_THREAD, "timestamp", 308 TRACE_EVENT_SCOPE_THREAD, "timestamp",
228 timestamp.ToInternalValue(), "time_delta", 309 timestamp.ToInternalValue(), "time_delta",
229 (timestamp - first_frame_timestamp_).ToInternalValue()); 310 (timestamp - first_frame_timestamp_).ToInternalValue());
311 // TODO(emircan): Handle texture upload and video frame creation for GMB
312 // backed buffers.
230 313
231 scoped_refptr<media::VideoFrame> frame; 314 scoped_refptr<media::VideoFrame> frame;
232 uint32* release_sync_point_storage = nullptr; 315 uint32* release_sync_point_storage = nullptr;
233 scoped_refptr<ClientBuffer> buffer; 316 scoped_refptr<ClientBuffer> buffer;
234
235 if (mailbox_holder.mailbox.IsZero()) { 317 if (mailbox_holder.mailbox.IsZero()) {
236 DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format); 318 DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format);
237 const ClientBufferMap::const_iterator iter = 319 const auto& iter = client_buffers_.find(buffer_id);
238 client_buffers_.find(buffer_id);
239 DCHECK(iter != client_buffers_.end()); 320 DCHECK(iter != client_buffers_.end());
240 buffer = iter->second; 321 buffer = iter->second;
241 frame = media::VideoFrame::WrapExternalSharedMemory( 322 frame = media::VideoFrame::WrapExternalSharedMemory(
242 pixel_format, 323 pixel_format,
243 coded_size, 324 coded_size,
244 visible_rect, 325 visible_rect,
245 gfx::Size(visible_rect.width(), visible_rect.height()), 326 gfx::Size(visible_rect.width(), visible_rect.height()),
246 reinterpret_cast<uint8*>(buffer->buffer->memory()), 327 reinterpret_cast<uint8*>(buffer->buffer()->memory()),
247 buffer->buffer_size, 328 buffer->buffer_size(),
248 buffer->buffer->handle(), 329 buffer->buffer()->handle(),
249 0 /* shared_memory_offset */, 330 0 /* shared_memory_offset */,
250 timestamp - first_frame_timestamp_); 331 timestamp - first_frame_timestamp_);
251
252 } else { 332 } else {
253 DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format); 333 DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format);
254 DCHECK(mailbox_holder.mailbox.Verify()); // Paranoia? 334 DCHECK(mailbox_holder.mailbox.Verify()); // Paranoia?
255 // To be deleted in DidFinishConsumingFrame(). 335 // To be deleted in DidFinishConsumingFrame().
256 release_sync_point_storage = new uint32(0); 336 release_sync_point_storage = new uint32(0);
257 frame = media::VideoFrame::WrapNativeTexture( 337 frame = media::VideoFrame::WrapNativeTexture(
258 pixel_format, 338 pixel_format,
259 mailbox_holder, 339 mailbox_holder,
260 base::Bind(&SaveReleaseSyncPoint, release_sync_point_storage), 340 base::Bind(&SaveReleaseSyncPoint, release_sync_point_storage),
261 coded_size, 341 coded_size,
262 gfx::Rect(coded_size), 342 gfx::Rect(coded_size),
263 coded_size, 343 coded_size,
264 timestamp - first_frame_timestamp_); 344 timestamp - first_frame_timestamp_);
265 } 345 }
266 frame->AddDestructionObserver( 346 frame->AddDestructionObserver(
267 base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(), 347 base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(),
268 release_sync_point_storage, 348 release_sync_point_storage,
269 media::BindToCurrentLoop(base::Bind( 349 media::BindToCurrentLoop(base::Bind(
270 &VideoCaptureImpl::OnClientBufferFinished, 350 &VideoCaptureImpl::OnClientBufferFinished,
271 weak_factory_.GetWeakPtr(), buffer_id, buffer)))); 351 weak_factory_.GetWeakPtr(), buffer_id, buffer))));
272 352
273 frame->metadata()->MergeInternalValuesFrom(metadata); 353 frame->metadata()->MergeInternalValuesFrom(metadata);
274 deliver_frame_cb_.Run(frame, timestamp); 354 deliver_frame_cb_.Run(frame, timestamp);
275 } 355 }
276 356
277 void VideoCaptureImpl::OnClientBufferFinished( 357 void VideoCaptureImpl::OnClientBufferFinished(
278 int buffer_id, 358 int buffer_id,
279 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, 359 const scoped_refptr<ClientBuffer>& /* ignored_buffer */,
280 uint32 release_sync_point, 360 uint32 release_sync_point,
281 double consumer_resource_utilization) { 361 double consumer_resource_utilization) {
282 DCHECK(io_task_runner_->BelongsToCurrentThread()); 362 DCHECK(io_task_runner_->BelongsToCurrentThread());
283 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 363 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id,
284 release_sync_point, 364 release_sync_point,
285 consumer_resource_utilization)); 365 consumer_resource_utilization));
286 } 366 }
367 void VideoCaptureImpl::OnClientBufferFinished2(
368 int buffer_id,
369 const scoped_refptr<ClientBuffer2>& gpu_memory_buffer,
370 uint32 release_sync_point,
371 double consumer_resource_utilization) {
372 OnClientBufferFinished(buffer_id, scoped_refptr<ClientBuffer>(),
373 release_sync_point, consumer_resource_utilization);
374 }
287 375
288 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { 376 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) {
289 // TODO(ajose): http://crbug.com/522155 improve this state machine. 377 // TODO(ajose): http://crbug.com/522155 improve this state machine.
290 DCHECK(io_task_runner_->BelongsToCurrentThread()); 378 DCHECK(io_task_runner_->BelongsToCurrentThread());
291 state_ = state; 379 state_ = state;
292 380
293 if (state == VIDEO_CAPTURE_STATE_STOPPED) { 381 if (state == VIDEO_CAPTURE_STATE_STOPPED) {
294 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; 382 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_;
295 client_buffers_.clear(); 383 client_buffers_.clear();
384 client_buffer2s_.clear();
296 weak_factory_.InvalidateWeakPtrs(); 385 weak_factory_.InvalidateWeakPtrs();
297 return; 386 return;
298 } 387 }
299 if (state == VIDEO_CAPTURE_STATE_ERROR) { 388 if (state == VIDEO_CAPTURE_STATE_ERROR) {
300 DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_; 389 DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_;
301 if (!state_update_cb_.is_null()) 390 if (!state_update_cb_.is_null())
302 state_update_cb_.Run(VIDEO_CAPTURE_STATE_ERROR); 391 state_update_cb_.Run(VIDEO_CAPTURE_STATE_ERROR);
303 ResetClient(); 392 ResetClient();
304 return; 393 return;
305 } 394 }
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 void VideoCaptureImpl::ResetClient() { 488 void VideoCaptureImpl::ResetClient() {
400 client_params_ = media::VideoCaptureParams(); 489 client_params_ = media::VideoCaptureParams();
401 state_update_cb_.Reset(); 490 state_update_cb_.Reset();
402 deliver_frame_cb_.Reset(); 491 deliver_frame_cb_.Reset();
403 first_frame_timestamp_ = base::TimeTicks(); 492 first_frame_timestamp_ = base::TimeTicks();
404 device_id_ = kUndefinedDeviceId; 493 device_id_ = kUndefinedDeviceId;
405 state_ = VIDEO_CAPTURE_STATE_STOPPED; 494 state_ = VIDEO_CAPTURE_STATE_STOPPED;
406 } 495 }
407 496
408 } // namespace content 497 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/video_capture_impl.h ('k') | content/renderer/media/video_capture_message_filter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698