Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/media/video_capture_messages.h" | 18 #include "content/common/media/video_capture_messages.h" |
| 19 #include "media/base/bind_to_current_loop.h" | 19 #include "media/base/bind_to_current_loop.h" |
| 20 #include "media/base/limits.h" | 20 #include "media/base/limits.h" |
| 21 #include "media/base/video_frame.h" | 21 #include "media/base/video_frame.h" |
| 22 | 22 |
| 23 namespace content { | 23 namespace content { |
| 24 | 24 |
| 25 namespace { | |
| 26 | |
| 27 // This is called on an unknown thread when the VideoFrame destructor executes. | |
|
hubbe
2015/06/02 00:23:22
This explains what happens, but not why.
I think s
miu
2015/06/02 03:07:34
Done. Basically, it's the only interface. I don'
| |
| 28 // VideoCaptureImpl::DidFinishConsumingFrame() reads the saved value and passes | |
| 29 // it back to the IO thread to pass back to the host via the BufferReady IPC. | |
| 30 void SaveReleaseSyncPoint(uint32* storage, uint32 release_sync_point) { | |
| 31 *storage = release_sync_point; | |
| 32 } | |
| 33 | |
| 34 } // namespace | |
| 35 | |
| 25 class VideoCaptureImpl::ClientBuffer | 36 class VideoCaptureImpl::ClientBuffer |
| 26 : public base::RefCountedThreadSafe<ClientBuffer> { | 37 : public base::RefCountedThreadSafe<ClientBuffer> { |
| 27 public: | 38 public: |
| 28 ClientBuffer(scoped_ptr<base::SharedMemory> buffer, | 39 ClientBuffer(scoped_ptr<base::SharedMemory> buffer, |
| 29 size_t buffer_size) | 40 size_t buffer_size) |
| 30 : buffer(buffer.Pass()), | 41 : buffer(buffer.Pass()), |
| 31 buffer_size(buffer_size) {} | 42 buffer_size(buffer_size) {} |
| 32 const scoped_ptr<base::SharedMemory> buffer; | 43 const scoped_ptr<base::SharedMemory> buffer; |
| 33 const size_t buffer_size; | 44 const size_t buffer_size; |
| 34 | 45 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 213 } | 224 } |
| 214 | 225 |
| 215 void VideoCaptureImpl::OnBufferReceived(int buffer_id, | 226 void VideoCaptureImpl::OnBufferReceived(int buffer_id, |
| 216 const gfx::Size& coded_size, | 227 const gfx::Size& coded_size, |
| 217 const gfx::Rect& visible_rect, | 228 const gfx::Rect& visible_rect, |
| 218 base::TimeTicks timestamp, | 229 base::TimeTicks timestamp, |
| 219 const base::DictionaryValue& metadata) { | 230 const base::DictionaryValue& metadata) { |
| 220 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 231 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 221 | 232 |
| 222 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { | 233 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { |
| 223 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0)); | 234 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0, -1.0)); |
| 224 return; | 235 return; |
| 225 } | 236 } |
| 226 | 237 |
| 227 if (first_frame_timestamp_.is_null()) | 238 if (first_frame_timestamp_.is_null()) |
| 228 first_frame_timestamp_ = timestamp; | 239 first_frame_timestamp_ = timestamp; |
| 229 | 240 |
| 230 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 241 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
| 231 TRACE_EVENT_INSTANT2( | 242 TRACE_EVENT_INSTANT2( |
| 232 "cast_perf_test", "OnBufferReceived", | 243 "cast_perf_test", "OnBufferReceived", |
| 233 TRACE_EVENT_SCOPE_THREAD, | 244 TRACE_EVENT_SCOPE_THREAD, |
| 234 "timestamp", timestamp.ToInternalValue(), | 245 "timestamp", timestamp.ToInternalValue(), |
| 235 "time_delta", (timestamp - first_frame_timestamp_).ToInternalValue()); | 246 "time_delta", (timestamp - first_frame_timestamp_).ToInternalValue()); |
| 236 | 247 |
| 237 const ClientBufferMap::const_iterator iter = client_buffers_.find(buffer_id); | 248 const ClientBufferMap::const_iterator iter = client_buffers_.find(buffer_id); |
| 238 DCHECK(iter != client_buffers_.end()); | 249 DCHECK(iter != client_buffers_.end()); |
| 239 scoped_refptr<ClientBuffer> buffer = iter->second; | 250 scoped_refptr<ClientBuffer> buffer = iter->second; |
| 240 scoped_refptr<media::VideoFrame> frame = | 251 scoped_refptr<media::VideoFrame> frame = |
| 241 media::VideoFrame::WrapExternalPackedMemory( | 252 media::VideoFrame::WrapExternalPackedMemory( |
| 242 media::VideoFrame::I420, | 253 media::VideoFrame::I420, |
| 243 coded_size, | 254 coded_size, |
| 244 visible_rect, | 255 visible_rect, |
| 245 gfx::Size(visible_rect.width(), visible_rect.height()), | 256 gfx::Size(visible_rect.width(), visible_rect.height()), |
| 246 reinterpret_cast<uint8*>(buffer->buffer->memory()), | 257 reinterpret_cast<uint8*>(buffer->buffer->memory()), |
| 247 buffer->buffer_size, | 258 buffer->buffer_size, |
| 248 buffer->buffer->handle(), | 259 buffer->buffer->handle(), |
| 249 0, | 260 0, |
| 250 timestamp - first_frame_timestamp_); | 261 timestamp - first_frame_timestamp_); |
| 251 frame->AddDestructionObserver( | 262 frame->AddDestructionObserver( |
| 252 media::BindToCurrentLoop( | 263 base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, |
| 253 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, | 264 frame->metadata(), |
| 254 weak_factory_.GetWeakPtr(), | 265 nullptr, |
| 255 buffer_id, | 266 media::BindToCurrentLoop( |
| 256 buffer, | 267 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, |
| 257 0))); | 268 weak_factory_.GetWeakPtr(), |
| 269 buffer_id, | |
| 270 buffer)))); | |
| 258 frame->metadata()->MergeInternalValuesFrom(metadata); | 271 frame->metadata()->MergeInternalValuesFrom(metadata); |
| 259 | 272 |
| 260 for (const auto& client : clients_) | 273 for (const auto& client : clients_) |
| 261 client.second.deliver_frame_cb.Run(frame, timestamp); | 274 client.second.deliver_frame_cb.Run(frame, timestamp); |
| 262 } | 275 } |
| 263 | 276 |
| 264 void VideoCaptureImpl::OnMailboxBufferReceived( | 277 void VideoCaptureImpl::OnMailboxBufferReceived( |
| 265 int buffer_id, | 278 int buffer_id, |
| 266 const gpu::MailboxHolder& mailbox_holder, | 279 const gpu::MailboxHolder& mailbox_holder, |
| 267 const gfx::Size& packed_frame_size, | 280 const gfx::Size& packed_frame_size, |
| 268 base::TimeTicks timestamp, | 281 base::TimeTicks timestamp, |
| 269 const base::DictionaryValue& metadata) { | 282 const base::DictionaryValue& metadata) { |
| 270 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 283 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 271 | 284 |
| 272 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { | 285 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { |
| 273 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0)); | 286 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0, -1.0)); |
| 274 return; | 287 return; |
| 275 } | 288 } |
| 276 | 289 |
| 277 if (first_frame_timestamp_.is_null()) | 290 if (first_frame_timestamp_.is_null()) |
| 278 first_frame_timestamp_ = timestamp; | 291 first_frame_timestamp_ = timestamp; |
| 279 | 292 |
| 293 uint32* const release_sync_point_storage = | |
| 294 new uint32(0); // Deleted in DidFinishConsumingFrame(). | |
| 280 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture( | 295 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture( |
| 281 mailbox_holder, | 296 mailbox_holder, |
| 282 media::BindToCurrentLoop(base::Bind( | 297 base::Bind(&SaveReleaseSyncPoint, release_sync_point_storage), |
| 283 &VideoCaptureImpl::OnClientBufferFinished, weak_factory_.GetWeakPtr(), | |
| 284 buffer_id, scoped_refptr<ClientBuffer>())), | |
| 285 packed_frame_size, gfx::Rect(packed_frame_size), packed_frame_size, | 298 packed_frame_size, gfx::Rect(packed_frame_size), packed_frame_size, |
| 286 timestamp - first_frame_timestamp_, false /* allow_overlay */, | 299 timestamp - first_frame_timestamp_, false /* allow_overlay */, |
| 287 true /* has_alpha */); | 300 true /* has_alpha */); |
| 301 frame->AddDestructionObserver( | |
| 302 base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, | |
| 303 frame->metadata(), | |
| 304 release_sync_point_storage, | |
| 305 media::BindToCurrentLoop(base::Bind( | |
| 306 &VideoCaptureImpl::OnClientBufferFinished, | |
| 307 weak_factory_.GetWeakPtr(), | |
| 308 buffer_id, | |
| 309 scoped_refptr<ClientBuffer>())))); | |
| 310 | |
| 288 frame->metadata()->MergeInternalValuesFrom(metadata); | 311 frame->metadata()->MergeInternalValuesFrom(metadata); |
| 289 | 312 |
| 290 for (const auto& client : clients_) | 313 for (const auto& client : clients_) |
| 291 client.second.deliver_frame_cb.Run(frame, timestamp); | 314 client.second.deliver_frame_cb.Run(frame, timestamp); |
| 292 } | 315 } |
| 293 | 316 |
| 294 void VideoCaptureImpl::OnClientBufferFinished( | 317 void VideoCaptureImpl::OnClientBufferFinished( |
| 295 int buffer_id, | 318 int buffer_id, |
| 296 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, | 319 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, |
| 297 uint32 release_sync_point) { | 320 uint32 release_sync_point, |
| 321 double consumer_stress_level) { | |
| 298 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 322 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 299 Send(new VideoCaptureHostMsg_BufferReady( | 323 Send(new VideoCaptureHostMsg_BufferReady( |
| 300 device_id_, buffer_id, release_sync_point)); | 324 device_id_, buffer_id, release_sync_point, consumer_stress_level)); |
| 301 } | 325 } |
| 302 | 326 |
| 303 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { | 327 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { |
| 304 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 328 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 305 | 329 |
| 306 switch (state) { | 330 switch (state) { |
| 307 case VIDEO_CAPTURE_STATE_STARTED: | 331 case VIDEO_CAPTURE_STATE_STARTED: |
| 308 // Camera has started in the browser process. Since we have already | 332 // Camera has started in the browser process. Since we have already |
| 309 // told all clients that we have started there's nothing to do. | 333 // told all clients that we have started there's nothing to do. |
| 310 break; | 334 break; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 | 446 |
| 423 const ClientInfoMap::iterator it = clients->find(client_id); | 447 const ClientInfoMap::iterator it = clients->find(client_id); |
| 424 if (it != clients->end()) { | 448 if (it != clients->end()) { |
| 425 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); | 449 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); |
| 426 clients->erase(it); | 450 clients->erase(it); |
| 427 found = true; | 451 found = true; |
| 428 } | 452 } |
| 429 return found; | 453 return found; |
| 430 } | 454 } |
| 431 | 455 |
| 456 // static | |
| 457 void VideoCaptureImpl::DidFinishConsumingFrame( | |
| 458 const media::VideoFrameMetadata* metadata, | |
| 459 uint32* release_sync_point_storage, | |
| 460 const base::Callback<void(uint32, double)>& callback_to_io_thread) { | |
| 461 // Note: This function may be called on any thread by the VideoFrame | |
| 462 // destructor. |metadata| is still valid for read-access at this point. | |
| 463 | |
| 464 uint32 release_sync_point = 0u; | |
| 465 if (release_sync_point_storage) { | |
| 466 release_sync_point = *release_sync_point_storage; | |
| 467 delete release_sync_point_storage; | |
| 468 } | |
| 469 | |
| 470 double consumer_stress_level = -1.0; | |
| 471 if (!metadata->GetDouble(media::VideoFrameMetadata::STRESS_LEVEL, | |
| 472 &consumer_stress_level)) { | |
| 473 consumer_stress_level = -1.0; | |
| 474 } | |
| 475 | |
| 476 callback_to_io_thread.Run(release_sync_point, consumer_stress_level); | |
| 477 } | |
| 478 | |
| 432 } // namespace content | 479 } // namespace content |
| OLD | NEW |