| 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 #include "content/browser/renderer_host/media/video_capture_controller.h" | 5 #include "content/browser/renderer_host/media/video_capture_controller.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "content/browser/renderer_host/media/media_stream_manager.h" | 12 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 13 #include "content/browser/renderer_host/media/video_capture_manager.h" | 13 #include "content/browser/renderer_host/media/video_capture_manager.h" |
| 14 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
| 15 #include "media/base/encoded_bitstream_buffer.h" |
| 15 #include "media/base/video_frame.h" | 16 #include "media/base/video_frame.h" |
| 16 #include "media/base/video_util.h" | 17 #include "media/base/video_util.h" |
| 17 #include "media/base/yuv_convert.h" | 18 #include "media/base/yuv_convert.h" |
| 18 | 19 |
| 19 #if !defined(OS_IOS) && !defined(OS_ANDROID) | 20 #if !defined(OS_IOS) && !defined(OS_ANDROID) |
| 20 #include "third_party/libyuv/include/libyuv.h" | 21 #include "third_party/libyuv/include/libyuv.h" |
| 21 #endif | 22 #endif |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 | 80 |
| 80 // State of capture session, controlled by VideoCaptureManager directly. | 81 // State of capture session, controlled by VideoCaptureManager directly. |
| 81 bool session_closed; | 82 bool session_closed; |
| 82 }; | 83 }; |
| 83 | 84 |
| 84 VideoCaptureController::VideoCaptureController( | 85 VideoCaptureController::VideoCaptureController( |
| 85 VideoCaptureManager* video_capture_manager) | 86 VideoCaptureManager* video_capture_manager) |
| 86 : chopped_width_(0), | 87 : chopped_width_(0), |
| 87 chopped_height_(0), | 88 chopped_height_(0), |
| 88 frame_info_available_(false), | 89 frame_info_available_(false), |
| 90 encoded_frame_info_available_(false), |
| 89 video_capture_manager_(video_capture_manager), | 91 video_capture_manager_(video_capture_manager), |
| 90 device_in_use_(false), | 92 device_in_use_(false), |
| 91 state_(VIDEO_CAPTURE_STATE_STOPPED) { | 93 state_(VIDEO_CAPTURE_STATE_STOPPED) { |
| 92 memset(¤t_params_, 0, sizeof(current_params_)); | 94 memset(¤t_params_, 0, sizeof(current_params_)); |
| 93 } | 95 } |
| 94 | 96 |
| 95 void VideoCaptureController::StartCapture( | 97 void VideoCaptureController::StartCapture( |
| 96 const VideoCaptureControllerID& id, | 98 const VideoCaptureControllerID& id, |
| 97 VideoCaptureControllerEventHandler* event_handler, | 99 VideoCaptureControllerEventHandler* event_handler, |
| 98 base::ProcessHandle render_process, | 100 base::ProcessHandle render_process, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 122 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 124 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 123 // TODO(wjia): Temporarily disable restarting till client supports resampling. | 125 // TODO(wjia): Temporarily disable restarting till client supports resampling. |
| 124 #if 0 | 126 #if 0 |
| 125 // This client has higher resolution than what is currently requested. | 127 // This client has higher resolution than what is currently requested. |
| 126 // Need restart capturing. | 128 // Need restart capturing. |
| 127 if (params.width > current_params_.width || | 129 if (params.width > current_params_.width || |
| 128 params.height > current_params_.height) { | 130 params.height > current_params_.height) { |
| 129 video_capture_manager_->Stop(current_params_.session_id, | 131 video_capture_manager_->Stop(current_params_.session_id, |
| 130 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); | 132 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); |
| 131 frame_info_available_ = false; | 133 frame_info_available_ = false; |
| 134 encoded_frame_info_available_ = false; |
| 132 state_ = VIDEO_CAPTURE_STATE_STOPPING; | 135 state_ = VIDEO_CAPTURE_STATE_STOPPING; |
| 133 pending_clients_.push_back(client); | 136 pending_clients_.push_back(client); |
| 134 return; | 137 return; |
| 135 } | 138 } |
| 136 #endif | 139 #endif |
| 137 | 140 |
| 138 // This client's resolution is no larger than what's currently requested. | 141 // This client's resolution is no larger than what's currently requested. |
| 139 // When frame_info has been returned by device, send them to client. | 142 // When frame_info has been returned by device, send them to client. |
| 140 if (frame_info_available_) { | 143 if (frame_info_available_ || encoded_frame_info_available_) { |
| 141 SendFrameInfoAndBuffers(client); | 144 SendFrameInfoAndBuffers(client); |
| 142 } | 145 } |
| 143 controller_clients_.push_back(client); | 146 controller_clients_.push_back(client); |
| 144 return; | 147 return; |
| 145 } | 148 } |
| 146 | 149 |
| 147 // In case the device is in the middle of stopping, put the client in | 150 // In case the device is in the middle of stopping, put the client in |
| 148 // pending queue. | 151 // pending queue. |
| 149 if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { | 152 if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { |
| 150 pending_clients_.push_back(client); | 153 pending_clients_.push_back(client); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 delete client; | 195 delete client; |
| 193 controller_clients_.remove(client); | 196 controller_clients_.remove(client); |
| 194 | 197 |
| 195 // No more clients. Stop device. | 198 // No more clients. Stop device. |
| 196 if (controller_clients_.empty() && | 199 if (controller_clients_.empty() && |
| 197 (state_ == VIDEO_CAPTURE_STATE_STARTED || | 200 (state_ == VIDEO_CAPTURE_STATE_STARTED || |
| 198 state_ == VIDEO_CAPTURE_STATE_ERROR)) { | 201 state_ == VIDEO_CAPTURE_STATE_ERROR)) { |
| 199 video_capture_manager_->Stop(session_id, | 202 video_capture_manager_->Stop(session_id, |
| 200 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); | 203 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); |
| 201 frame_info_available_ = false; | 204 frame_info_available_ = false; |
| 205 encoded_frame_info_available_ = false; |
| 202 state_ = VIDEO_CAPTURE_STATE_STOPPING; | 206 state_ = VIDEO_CAPTURE_STATE_STOPPING; |
| 203 } | 207 } |
| 204 } | 208 } |
| 205 | 209 |
| 206 void VideoCaptureController::StopSession( | 210 void VideoCaptureController::StopSession( |
| 207 int session_id) { | 211 int session_id) { |
| 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 212 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 209 DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id; | 213 DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id; |
| 210 | 214 |
| 211 ControllerClient* client = FindClient(session_id, pending_clients_); | 215 ControllerClient* client = FindClient(session_id, pending_clients_); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 238 | 242 |
| 239 // When all buffers have been returned by clients and device has been | 243 // When all buffers have been returned by clients and device has been |
| 240 // called to stop, check if restart is needed. This could happen when | 244 // called to stop, check if restart is needed. This could happen when |
| 241 // capture needs to be restarted due to resolution change. | 245 // capture needs to be restarted due to resolution change. |
| 242 if (!buffer_pool_->IsAnyBufferHeldForConsumers() && | 246 if (!buffer_pool_->IsAnyBufferHeldForConsumers() && |
| 243 state_ == VIDEO_CAPTURE_STATE_STOPPING) { | 247 state_ == VIDEO_CAPTURE_STATE_STOPPING) { |
| 244 PostStopping(); | 248 PostStopping(); |
| 245 } | 249 } |
| 246 } | 250 } |
| 247 | 251 |
| 248 scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveOutputBuffer() { | 252 void VideoCaptureController::TryConfigureEncodedBitstream( |
| 249 base::AutoLock lock(buffer_pool_lock_); | 253 const media::RuntimeVideoEncodingParameters& params) { |
| 250 if (!buffer_pool_.get()) | 254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 251 return NULL; | 255 video_capture_manager_->TryConfigureEncodedBitstream( |
| 252 return ReserveI420VideoFrame(buffer_pool_, gfx::Size(frame_info_.width, | 256 current_params_.session_id, |
| 253 frame_info_.height)); | 257 params); |
| 254 } | 258 } |
| 255 | 259 |
| 256 // Implements VideoCaptureDevice::EventHandler. | 260 // Implements VideoCaptureDevice::EventHandler. |
| 257 // OnIncomingCapturedFrame is called the thread running the capture device. | 261 // OnIncomingCapturedFrame is called the thread running the capture device. |
| 258 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 262 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
| 259 void VideoCaptureController::OnIncomingCapturedFrame( | 263 void VideoCaptureController::OnIncomingCapturedFrame( |
| 260 const uint8* data, | 264 const uint8* data, |
| 261 int length, | 265 int length, |
| 262 base::Time timestamp, | 266 base::Time timestamp, |
| 263 int rotation, | 267 int rotation, |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 libyuv::kRotate0, libyuv::FOURCC_MJPG); | 354 libyuv::kRotate0, libyuv::FOURCC_MJPG); |
| 351 break; | 355 break; |
| 352 } | 356 } |
| 353 #endif | 357 #endif |
| 354 default: | 358 default: |
| 355 NOTREACHED(); | 359 NOTREACHED(); |
| 356 } | 360 } |
| 357 | 361 |
| 358 BrowserThread::PostTask(BrowserThread::IO, | 362 BrowserThread::PostTask(BrowserThread::IO, |
| 359 FROM_HERE, | 363 FROM_HERE, |
| 360 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 364 base::Bind( |
| 361 this, dst, timestamp)); | 365 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, |
| 366 this, |
| 367 dst, |
| 368 timestamp)); |
| 362 } | 369 } |
| 363 | 370 |
| 364 // OnIncomingCapturedVideoFrame is called the thread running the capture device. | 371 // OnIncomingCapturedVideoFrame is called the thread running the capture device. |
| 365 void VideoCaptureController::OnIncomingCapturedVideoFrame( | 372 void VideoCaptureController::OnIncomingCapturedVideoFrame( |
| 366 const scoped_refptr<media::VideoFrame>& frame, | 373 const scoped_refptr<media::VideoFrame>& frame, |
| 367 base::Time timestamp) { | 374 base::Time timestamp) { |
| 368 | 375 |
| 369 scoped_refptr<media::VideoFrame> target; | 376 scoped_refptr<media::VideoFrame> target; |
| 370 { | 377 { |
| 371 base::AutoLock lock(buffer_pool_lock_); | 378 base::AutoLock lock(buffer_pool_lock_); |
| 372 | 379 |
| 373 if (!buffer_pool_.get()) | 380 if (!buffer_pool_.get()) |
| 374 return; | 381 return; |
| 375 | 382 |
| 376 // If this is a frame that belongs to the buffer pool, we can forward it | 383 // If this is a frame that belongs to the buffer pool, we can forward it |
| 377 // directly to the IO thread and be done. | 384 // directly to the IO thread and be done. |
| 378 if (buffer_pool_->RecognizeReservedBuffer( | 385 if (buffer_pool_->RecognizeReservedBuffer( |
| 379 frame->shared_memory_handle()) >= 0) { | 386 frame->shared_memory_handle()) >= 0) { |
| 380 BrowserThread::PostTask(BrowserThread::IO, | 387 BrowserThread::PostTask(BrowserThread::IO, |
| 381 FROM_HERE, | 388 FROM_HERE, |
| 382 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 389 base::Bind( |
| 383 this, frame, timestamp)); | 390 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, |
| 391 this, |
| 392 frame, |
| 393 timestamp)); |
| 384 return; | 394 return; |
| 385 } | 395 } |
| 386 // Otherwise, this is a frame that belongs to the caller, and we must copy | 396 // Otherwise, this is a frame that belongs to the caller, and we must copy |
| 387 // it to a frame from the buffer pool. | 397 // it to a frame from the buffer pool. |
| 388 target = ReserveI420VideoFrame(buffer_pool_, gfx::Size(frame_info_.width, | 398 target = ReserveI420VideoFrame(buffer_pool_, gfx::Size(frame_info_.width, |
| 389 frame_info_.height)); | 399 frame_info_.height)); |
| 390 } | 400 } |
| 391 | 401 |
| 392 if (!target.get()) | 402 if (!target.get()) |
| 393 return; | 403 return; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 target->coded_size().height(), | 478 target->coded_size().height(), |
| 469 frame->stride(kRGBPlane), | 479 frame->stride(kRGBPlane), |
| 470 target->stride(kYPlane), | 480 target->stride(kYPlane), |
| 471 target->stride(kUPlane)); | 481 target->stride(kUPlane)); |
| 472 break; | 482 break; |
| 473 } | 483 } |
| 474 } | 484 } |
| 475 | 485 |
| 476 BrowserThread::PostTask(BrowserThread::IO, | 486 BrowserThread::PostTask(BrowserThread::IO, |
| 477 FROM_HERE, | 487 FROM_HERE, |
| 478 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 488 base::Bind( |
| 479 this, target, timestamp)); | 489 &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, |
| 490 this, |
| 491 target, |
| 492 timestamp)); |
| 493 } |
| 494 |
| 495 void VideoCaptureController::OnIncomingCapturedEncodedBitstreamBuffer( |
| 496 const scoped_refptr<media::EncodedBitstreamBuffer>& buffer, |
| 497 size_t data_size, |
| 498 base::Time timestamp) { |
| 499 |
| 500 scoped_refptr<media::EncodedBitstreamBuffer> target; |
| 501 { |
| 502 base::AutoLock lock(buffer_pool_lock_); |
| 503 if (!buffer_pool_.get()) |
| 504 return; |
| 505 // If this is a frame that belongs to the buffer pool, we can forward it |
| 506 // directly to the IO thread and be done. |
| 507 if (buffer_pool_->RecognizeReservedBuffer( |
| 508 buffer->shared_memory_handle()) >= 0) { |
| 509 BrowserThread::PostTask(BrowserThread::IO, |
| 510 FROM_HERE, |
| 511 base::Bind( |
| 512 &VideoCaptureController:: |
| 513 DoIncomingCapturedEncodedBitstreamBufferOnIOThread, |
| 514 this, |
| 515 buffer, |
| 516 data_size, |
| 517 timestamp)); |
| 518 return; |
| 519 } |
| 520 // Otherwise, this is a frame that belongs to the caller, and we must copy |
| 521 // it to a frame from the buffer pool. |
| 522 target = ReserveOutputEncodedBitstreamBuffer(); |
| 523 } |
| 524 |
| 525 if (!target.get()) |
| 526 return; |
| 527 if (data_size > target->size()) |
| 528 return; |
| 529 memcpy(buffer_pool_->GetMemory(target->buffer_id()), |
| 530 buffer->buffer(), data_size); |
| 531 BrowserThread::PostTask(BrowserThread::IO, |
| 532 FROM_HERE, |
| 533 base::Bind( |
| 534 &VideoCaptureController:: |
| 535 DoIncomingCapturedEncodedBitstreamBufferOnIOThread, |
| 536 this, |
| 537 target, |
| 538 data_size, |
| 539 timestamp)); |
| 480 } | 540 } |
| 481 | 541 |
| 482 void VideoCaptureController::OnError() { | 542 void VideoCaptureController::OnError() { |
| 483 BrowserThread::PostTask(BrowserThread::IO, | 543 BrowserThread::PostTask(BrowserThread::IO, |
| 484 FROM_HERE, | 544 FROM_HERE, |
| 485 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); | 545 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); |
| 486 } | 546 } |
| 487 | 547 |
| 488 void VideoCaptureController::OnFrameInfo( | 548 void VideoCaptureController::OnFrameInfo( |
| 489 const media::VideoCaptureCapability& info) { | 549 const media::VideoCaptureCapability& info) { |
| 490 frame_info_= info; | 550 frame_info_= info; |
| 491 // Handle cases when |info| has odd numbers for width/height. | 551 // Handle cases when |info| has odd numbers for width/height. |
| 492 if (info.width & 1) { | 552 if (info.width & 1) { |
| 493 --frame_info_.width; | 553 --frame_info_.width; |
| 494 chopped_width_ = 1; | 554 chopped_width_ = 1; |
| 495 } else { | 555 } else { |
| 496 chopped_width_ = 0; | 556 chopped_width_ = 0; |
| 497 } | 557 } |
| 498 if (info.height & 1) { | 558 if (info.height & 1) { |
| 499 --frame_info_.height; | 559 --frame_info_.height; |
| 500 chopped_height_ = 1; | 560 chopped_height_ = 1; |
| 501 } else { | 561 } else { |
| 502 chopped_height_ = 0; | 562 chopped_height_ = 0; |
| 503 } | 563 } |
| 564 |
| 565 BrowserThread::PostTask( |
| 566 BrowserThread::IO, |
| 567 FROM_HERE, |
| 568 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this, false)); |
| 569 } |
| 570 |
| 571 void VideoCaptureController::OnEncodedFrameInfo( |
| 572 const media::VideoEncodingParameters& encoded_info) { |
| 573 encoded_frame_info_ = encoded_info; |
| 574 |
| 575 BrowserThread::PostTask( |
| 576 BrowserThread::IO, |
| 577 FROM_HERE, |
| 578 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this, true)); |
| 579 } |
| 580 |
| 581 void VideoCaptureController::OnBitstreamConfigChanged( |
| 582 const media::RuntimeVideoEncodingParameters& params) { |
| 504 BrowserThread::PostTask(BrowserThread::IO, | 583 BrowserThread::PostTask(BrowserThread::IO, |
| 505 FROM_HERE, | 584 FROM_HERE, |
| 506 base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, this)); | 585 base::Bind(&VideoCaptureController::DoBitstreamConfigChangedOnIOThread, |
| 586 this, |
| 587 params)); |
| 507 } | 588 } |
| 508 | 589 |
| 509 // static | 590 scoped_refptr<media::VideoFrame> |
| 510 scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveI420VideoFrame( | 591 VideoCaptureController::ReserveOutputVideoFrame() { |
| 511 VideoCaptureBufferPool* buffer_pool, const gfx::Size& size) { | 592 base::AutoLock lock(buffer_pool_lock_); |
| 512 if ((size_t)(size.GetArea() * 3 / 2) > buffer_pool->GetMemorySize()) | 593 if (!buffer_pool_.get()) |
| 513 return NULL; | 594 return NULL; |
| 595 return ReserveI420VideoFrame(buffer_pool_, gfx::Size(frame_info_.width, |
| 596 frame_info_.height)); |
| 597 } |
| 514 | 598 |
| 515 int buffer_id = buffer_pool->ReserveForProducer(); | 599 scoped_refptr<media::EncodedBitstreamBuffer> |
| 516 if (buffer_id < 0) | 600 VideoCaptureController::ReserveOutputEncodedBitstreamBuffer() { |
| 601 base::AutoLock lock(buffer_pool_lock_); |
| 602 if (!buffer_pool_.get()) |
| 517 return NULL; | 603 return NULL; |
| 518 | 604 return ReserveEncodedBitstreamBuffer(buffer_pool_); |
| 519 base::Closure disposal_handler = base::Bind( | |
| 520 &VideoCaptureBufferPool::RelinquishProducerReservation, | |
| 521 buffer_pool, | |
| 522 buffer_id); | |
| 523 | |
| 524 // Wrap the buffer in a VideoFrame container. | |
| 525 uint8* base_ptr = static_cast<uint8*>(buffer_pool->GetMemory(buffer_id)); | |
| 526 size_t u_offset = size.GetArea(); | |
| 527 size_t v_offset = u_offset + u_offset / 4; | |
| 528 scoped_refptr<media::VideoFrame> frame = | |
| 529 media::VideoFrame::WrapExternalYuvData( | |
| 530 buffer_pool->GetHandle(buffer_id), | |
| 531 media::VideoFrame::YV12, // Actually it's I420, but equivalent here. | |
| 532 size, gfx::Rect(size), size, | |
| 533 size.width(), // y stride | |
| 534 size.width() / 2, // u stride | |
| 535 size.width() / 2, // v stride | |
| 536 base_ptr, // y address | |
| 537 base_ptr + u_offset, // u address | |
| 538 base_ptr + v_offset, // v address | |
| 539 base::TimeDelta(), // timestamp (unused). | |
| 540 disposal_handler); | |
| 541 | |
| 542 return frame; | |
| 543 } | 605 } |
| 544 | 606 |
| 545 VideoCaptureController::~VideoCaptureController() { | 607 VideoCaptureController::~VideoCaptureController() { |
| 546 buffer_pool_ = NULL; // Release all buffers. | 608 buffer_pool_ = NULL; // Release all buffers. |
| 547 STLDeleteContainerPointers(controller_clients_.begin(), | 609 STLDeleteContainerPointers(controller_clients_.begin(), |
| 548 controller_clients_.end()); | 610 controller_clients_.end()); |
| 549 STLDeleteContainerPointers(pending_clients_.begin(), | 611 STLDeleteContainerPointers(pending_clients_.begin(), |
| 550 pending_clients_.end()); | 612 pending_clients_.end()); |
| 551 } | 613 } |
| 552 | 614 |
| 553 // Called by VideoCaptureManager when a device have been stopped. | 615 // Called by VideoCaptureManager when a device have been stopped. |
| 554 void VideoCaptureController::OnDeviceStopped() { | 616 void VideoCaptureController::OnDeviceStopped() { |
| 555 BrowserThread::PostTask(BrowserThread::IO, | 617 BrowserThread::PostTask(BrowserThread::IO, |
| 556 FROM_HERE, | 618 FROM_HERE, |
| 557 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); | 619 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); |
| 558 } | 620 } |
| 559 | 621 |
| 560 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | 622 void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread( |
| 561 const scoped_refptr<media::VideoFrame>& reserved_frame, | 623 const scoped_refptr<media::VideoFrame>& frame, |
| 624 base::Time timestamp) { |
| 625 DoIncomingCapturedSharedMemoryOnIOThread( |
| 626 frame->shared_memory_handle(), |
| 627 frame->coded_size().GetArea() * 3 / 2, |
| 628 timestamp); |
| 629 } |
| 630 |
| 631 void VideoCaptureController::DoIncomingCapturedEncodedBitstreamBufferOnIOThread( |
| 632 const scoped_refptr<media::EncodedBitstreamBuffer>& buffer, |
| 633 size_t data_size, |
| 634 base::Time timestamp) { |
| 635 DoIncomingCapturedSharedMemoryOnIOThread( |
| 636 buffer->shared_memory_handle(), |
| 637 data_size, |
| 638 timestamp); |
| 639 } |
| 640 |
| 641 void VideoCaptureController::DoIncomingCapturedSharedMemoryOnIOThread( |
| 642 base::SharedMemoryHandle reserved_handle, |
| 643 size_t data_size, |
| 562 base::Time timestamp) { | 644 base::Time timestamp) { |
| 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 645 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 564 | 646 |
| 565 if (!buffer_pool_.get()) | 647 if (!buffer_pool_.get()) |
| 566 return; | 648 return; |
| 567 | 649 |
| 568 int buffer_id = buffer_pool_->RecognizeReservedBuffer( | 650 int buffer_id = buffer_pool_->RecognizeReservedBuffer(reserved_handle); |
| 569 reserved_frame->shared_memory_handle()); | |
| 570 if (buffer_id < 0) { | 651 if (buffer_id < 0) { |
| 571 NOTREACHED(); | 652 NOTREACHED(); |
| 572 return; | 653 return; |
| 573 } | 654 } |
| 574 | 655 |
| 575 int count = 0; | 656 int count = 0; |
| 576 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 657 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 577 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 658 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 578 client_it != controller_clients_.end(); ++client_it) { | 659 client_it != controller_clients_.end(); ++client_it) { |
| 579 if ((*client_it)->session_closed) | 660 if ((*client_it)->session_closed) |
| 580 continue; | 661 continue; |
| 581 | 662 |
| 582 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, | 663 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, |
| 583 buffer_id, timestamp); | 664 buffer_id, data_size, |
| 665 timestamp, false); |
| 584 (*client_it)->buffers.insert(buffer_id); | 666 (*client_it)->buffers.insert(buffer_id); |
| 585 count++; | 667 count++; |
| 586 } | 668 } |
| 587 } | 669 } |
| 588 | 670 |
| 589 buffer_pool_->HoldForConsumers(buffer_id, count); | 671 buffer_pool_->HoldForConsumers(buffer_id, count); |
| 590 } | 672 } |
| 591 | 673 |
| 592 void VideoCaptureController::DoFrameInfoOnIOThread() { | 674 void VideoCaptureController::DoFrameInfoOnIOThread(bool encoded) { |
| 593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 675 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 594 DCHECK(!buffer_pool_.get()) | 676 DCHECK(!buffer_pool_.get()) |
| 595 << "Device is restarted without releasing shared memory."; | 677 << "Device is restarted without releasing shared memory."; |
| 596 | 678 |
| 597 // Allocate memory only when device has been started. | 679 // Allocate memory only when device has been started. |
| 598 if (state_ != VIDEO_CAPTURE_STATE_STARTED) | 680 if (state_ != VIDEO_CAPTURE_STATE_STARTED) |
| 599 return; | 681 return; |
| 600 | 682 |
| 601 scoped_refptr<VideoCaptureBufferPool> buffer_pool = | 683 scoped_refptr<VideoCaptureBufferPool> buffer_pool; |
| 602 new VideoCaptureBufferPool(frame_info_.width * frame_info_.height * 3 / 2, | 684 if (encoded) { |
| 603 kNoOfBuffers); | 685 buffer_pool = new VideoCaptureBufferPool( |
| 686 encoded_frame_info_.runtime_params.max_bitrate, kNoOfBuffers); |
| 687 } else { |
| 688 buffer_pool = new VideoCaptureBufferPool( |
| 689 frame_info_.width * frame_info_.height * 3 / 2, kNoOfBuffers); |
| 690 } |
| 604 | 691 |
| 605 // Check whether all buffers were created successfully. | 692 // Check whether all buffers were created successfully. |
| 606 if (!buffer_pool->Allocate()) { | 693 if (!buffer_pool->Allocate()) { |
| 607 state_ = VIDEO_CAPTURE_STATE_ERROR; | 694 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 608 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 695 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 609 client_it != controller_clients_.end(); ++client_it) { | 696 client_it != controller_clients_.end(); ++client_it) { |
| 610 (*client_it)->event_handler->OnError((*client_it)->controller_id); | 697 (*client_it)->event_handler->OnError((*client_it)->controller_id); |
| 611 } | 698 } |
| 612 return; | 699 return; |
| 613 } | 700 } |
| 614 | 701 |
| 615 { | 702 { |
| 616 base::AutoLock lock(buffer_pool_lock_); | 703 base::AutoLock lock(buffer_pool_lock_); |
| 617 buffer_pool_ = buffer_pool; | 704 buffer_pool_ = buffer_pool; |
| 618 } | 705 } |
| 619 frame_info_available_ = true; | 706 if (encoded) |
| 707 encoded_frame_info_available_ = true; |
| 708 else |
| 709 frame_info_available_ = true; |
| 620 | 710 |
| 621 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 711 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 622 client_it != controller_clients_.end(); ++client_it) { | 712 client_it != controller_clients_.end(); ++client_it) { |
| 623 SendFrameInfoAndBuffers(*client_it); | 713 SendFrameInfoAndBuffers(*client_it); |
| 624 } | 714 } |
| 625 } | 715 } |
| 626 | 716 |
| 717 void VideoCaptureController::DoBitstreamConfigChangedOnIOThread( |
| 718 const media::RuntimeVideoEncodingParameters& params) { |
| 719 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 720 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| 721 client_it != controller_clients_.end(); ++client_it) { |
| 722 (*client_it)->event_handler->OnBitstreamConfigChanged( |
| 723 (*client_it)->controller_id, |
| 724 params); |
| 725 } |
| 726 } |
| 727 |
| 627 void VideoCaptureController::DoErrorOnIOThread() { | 728 void VideoCaptureController::DoErrorOnIOThread() { |
| 628 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 729 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 629 state_ = VIDEO_CAPTURE_STATE_ERROR; | 730 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 630 ControllerClients::iterator client_it; | 731 ControllerClients::iterator client_it; |
| 631 for (client_it = controller_clients_.begin(); | 732 for (client_it = controller_clients_.begin(); |
| 632 client_it != controller_clients_.end(); ++client_it) { | 733 client_it != controller_clients_.end(); ++client_it) { |
| 633 (*client_it)->event_handler->OnError((*client_it)->controller_id); | 734 (*client_it)->event_handler->OnError((*client_it)->controller_id); |
| 634 } | 735 } |
| 635 for (client_it = pending_clients_.begin(); | 736 for (client_it = pending_clients_.begin(); |
| 636 client_it != pending_clients_.end(); ++client_it) { | 737 client_it != pending_clients_.end(); ++client_it) { |
| 637 (*client_it)->event_handler->OnError((*client_it)->controller_id); | 738 (*client_it)->event_handler->OnError((*client_it)->controller_id); |
| 638 } | 739 } |
| 639 } | 740 } |
| 640 | 741 |
| 641 void VideoCaptureController::DoDeviceStoppedOnIOThread() { | 742 void VideoCaptureController::DoDeviceStoppedOnIOThread() { |
| 642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 743 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 643 device_in_use_ = false; | 744 device_in_use_ = false; |
| 644 if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { | 745 if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { |
| 645 PostStopping(); | 746 PostStopping(); |
| 646 } | 747 } |
| 647 } | 748 } |
| 648 | 749 |
| 649 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { | 750 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { |
| 650 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 751 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 651 DCHECK(frame_info_available_); | 752 DCHECK(frame_info_available_ || encoded_frame_info_available_); |
| 652 client->event_handler->OnFrameInfo(client->controller_id, | |
| 653 frame_info_.width, frame_info_.height, | |
| 654 frame_info_.frame_rate); | |
| 655 if (!buffer_pool_.get()) | |
| 656 return; | |
| 657 | 753 |
| 754 std::vector<base::SharedMemoryHandle> handles; |
| 658 for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) { | 755 for (int buffer_id = 0; buffer_id < buffer_pool_->count(); ++buffer_id) { |
| 659 base::SharedMemoryHandle remote_handle = | 756 base::SharedMemoryHandle remote_handle = |
| 660 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); | 757 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); |
| 661 | 758 handles.push_back(remote_handle); |
| 662 client->event_handler->OnBufferCreated(client->controller_id, | 759 } |
| 663 remote_handle, | 760 if (frame_info_available_) { |
| 664 buffer_pool_->GetMemorySize(), | 761 DCHECK(!encoded_frame_info_available_); |
| 665 buffer_id); | 762 media::VideoCaptureParams params; |
| 763 params.width = frame_info_.width; |
| 764 params.height = frame_info_.height; |
| 765 params.frame_per_second = frame_info_.frame_rate; |
| 766 params.session_id = client->parameters.session_id; |
| 767 client->event_handler->OnFrameInfo(client->controller_id, |
| 768 params, |
| 769 handles, |
| 770 buffer_pool_->GetMemorySize()); |
| 771 } else { |
| 772 DCHECK(!frame_info_available_); |
| 773 client->event_handler->OnEncodedFrameInfo(client->controller_id, |
| 774 encoded_frame_info_, |
| 775 handles, |
| 776 buffer_pool_->GetMemorySize()); |
| 666 } | 777 } |
| 667 } | 778 } |
| 668 | 779 |
| 669 VideoCaptureController::ControllerClient* | 780 VideoCaptureController::ControllerClient* |
| 670 VideoCaptureController::FindClient( | 781 VideoCaptureController::FindClient( |
| 671 const VideoCaptureControllerID& id, | 782 const VideoCaptureControllerID& id, |
| 672 VideoCaptureControllerEventHandler* handler, | 783 VideoCaptureControllerEventHandler* handler, |
| 673 const ControllerClients& clients) { | 784 const ControllerClients& clients) { |
| 674 for (ControllerClients::const_iterator client_it = clients.begin(); | 785 for (ControllerClients::const_iterator client_it = clients.begin(); |
| 675 client_it != clients.end(); ++client_it) { | 786 client_it != clients.end(); ++client_it) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 687 const ControllerClients& clients) { | 798 const ControllerClients& clients) { |
| 688 for (ControllerClients::const_iterator client_it = clients.begin(); | 799 for (ControllerClients::const_iterator client_it = clients.begin(); |
| 689 client_it != clients.end(); ++client_it) { | 800 client_it != clients.end(); ++client_it) { |
| 690 if ((*client_it)->parameters.session_id == session_id) { | 801 if ((*client_it)->parameters.session_id == session_id) { |
| 691 return *client_it; | 802 return *client_it; |
| 692 } | 803 } |
| 693 } | 804 } |
| 694 return NULL; | 805 return NULL; |
| 695 } | 806 } |
| 696 | 807 |
| 808 // static |
| 809 scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveI420VideoFrame( |
| 810 VideoCaptureBufferPool* buffer_pool, const gfx::Size& size) { |
| 811 if ((size_t)(size.GetArea() * 3 / 2) > buffer_pool->GetMemorySize()) |
| 812 return NULL; |
| 813 |
| 814 int buffer_id = buffer_pool->ReserveForProducer(); |
| 815 if (buffer_id < 0) |
| 816 return NULL; |
| 817 |
| 818 base::Closure disposal_handler = base::Bind( |
| 819 &VideoCaptureBufferPool::RelinquishProducerReservation, |
| 820 buffer_pool, |
| 821 buffer_id); |
| 822 |
| 823 // Wrap the buffer in a VideoFrame container. |
| 824 uint8* base_ptr = static_cast<uint8*>(buffer_pool->GetMemory(buffer_id)); |
| 825 size_t u_offset = size.GetArea(); |
| 826 size_t v_offset = u_offset + u_offset / 4; |
| 827 scoped_refptr<media::VideoFrame> frame = |
| 828 media::VideoFrame::WrapExternalYuvData( |
| 829 buffer_pool->GetHandle(buffer_id), |
| 830 media::VideoFrame::YV12, // Actually it's I420, but equivalent here. |
| 831 size, gfx::Rect(size), size, |
| 832 size.width(), // y stride |
| 833 size.width() / 2, // u stride |
| 834 size.width() / 2, // v stride |
| 835 base_ptr, // y address |
| 836 base_ptr + u_offset, // u address |
| 837 base_ptr + v_offset, // v address |
| 838 base::TimeDelta(), // timestamp (unused). |
| 839 disposal_handler); |
| 840 |
| 841 return frame; |
| 842 } |
| 843 |
| 844 // static |
| 845 scoped_refptr<media::EncodedBitstreamBuffer> |
| 846 VideoCaptureController::ReserveEncodedBitstreamBuffer( |
| 847 VideoCaptureBufferPool* buffer_pool) { |
| 848 int buffer_id = buffer_pool->ReserveForProducer(); |
| 849 if (buffer_id < 0) |
| 850 return NULL; |
| 851 |
| 852 base::Closure disposal_handler = base::Bind( |
| 853 &VideoCaptureBufferPool::RelinquishProducerReservation, |
| 854 buffer_pool, |
| 855 buffer_id); |
| 856 |
| 857 // Wrap the buffer in a VideoFrame container. |
| 858 media::BufferEncodingMetadata metadata; |
| 859 metadata.key_frame = false; |
| 860 scoped_refptr<media::EncodedBitstreamBuffer> frame = |
| 861 new media::EncodedBitstreamBuffer( |
| 862 buffer_id, |
| 863 reinterpret_cast<uint8*>(buffer_pool->GetMemory(buffer_id)), |
| 864 buffer_pool->GetMemorySize(), |
| 865 buffer_pool->GetHandle(buffer_id), |
| 866 metadata, |
| 867 disposal_handler); |
| 868 return frame; |
| 869 } |
| 870 |
| 697 // This function is called when all buffers have been returned to controller, | 871 // This function is called when all buffers have been returned to controller, |
| 698 // or when device is stopped. It decides whether the device needs to be | 872 // or when device is stopped. It decides whether the device needs to be |
| 699 // restarted. | 873 // restarted. |
| 700 void VideoCaptureController::PostStopping() { | 874 void VideoCaptureController::PostStopping() { |
| 701 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 875 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 702 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPING); | 876 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPING); |
| 703 | 877 |
| 704 // When clients still have some buffers, or device has not been stopped yet, | 878 // When clients still have some buffers, or device has not been stopped yet, |
| 705 // do nothing. | 879 // do nothing. |
| 706 if ((buffer_pool_.get() && buffer_pool_->IsAnyBufferHeldForConsumers()) || | 880 if ((buffer_pool_.get() && buffer_pool_->IsAnyBufferHeldForConsumers()) || |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 controller_clients_.push_back((*client_it)); | 912 controller_clients_.push_back((*client_it)); |
| 739 pending_clients_.erase(client_it++); | 913 pending_clients_.erase(client_it++); |
| 740 } | 914 } |
| 741 // Request the manager to start the actual capture. | 915 // Request the manager to start the actual capture. |
| 742 video_capture_manager_->Start(current_params_, this); | 916 video_capture_manager_->Start(current_params_, this); |
| 743 state_ = VIDEO_CAPTURE_STATE_STARTED; | 917 state_ = VIDEO_CAPTURE_STATE_STARTED; |
| 744 device_in_use_ = true; | 918 device_in_use_ = true; |
| 745 } | 919 } |
| 746 | 920 |
| 747 } // namespace content | 921 } // namespace content |
| OLD | NEW |