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