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" |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 if (client) { | 171 if (client) { |
172 pending_clients_.remove(client); | 172 pending_clients_.remove(client); |
173 return; | 173 return; |
174 } | 174 } |
175 | 175 |
176 client = FindClient(id, event_handler, controller_clients_); | 176 client = FindClient(id, event_handler, controller_clients_); |
177 if (!client) | 177 if (!client) |
178 return; | 178 return; |
179 | 179 |
180 // Take back all buffers held by the |client|. | 180 // Take back all buffers held by the |client|. |
181 if (buffer_pool_) { | 181 if (buffer_pool_.get()) { |
182 for (std::set<int>::iterator buffer_it = client->buffers.begin(); | 182 for (std::set<int>::iterator buffer_it = client->buffers.begin(); |
183 buffer_it != client->buffers.end(); ++buffer_it) { | 183 buffer_it != client->buffers.end(); |
| 184 ++buffer_it) { |
184 int buffer_id = *buffer_it; | 185 int buffer_id = *buffer_it; |
185 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); | 186 buffer_pool_->RelinquishConsumerHold(buffer_id, 1); |
186 } | 187 } |
187 } | 188 } |
188 client->buffers.clear(); | 189 client->buffers.clear(); |
189 | 190 |
190 int session_id = client->parameters.session_id; | 191 int session_id = client->parameters.session_id; |
191 delete client; | 192 delete client; |
192 controller_clients_.remove(client); | 193 controller_clients_.remove(client); |
193 | 194 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 // called to stop, check if restart is needed. This could happen when | 240 // called to stop, check if restart is needed. This could happen when |
240 // capture needs to be restarted due to resolution change. | 241 // capture needs to be restarted due to resolution change. |
241 if (!buffer_pool_->IsAnyBufferHeldForConsumers() && | 242 if (!buffer_pool_->IsAnyBufferHeldForConsumers() && |
242 state_ == VIDEO_CAPTURE_STATE_STOPPING) { | 243 state_ == VIDEO_CAPTURE_STATE_STOPPING) { |
243 PostStopping(); | 244 PostStopping(); |
244 } | 245 } |
245 } | 246 } |
246 | 247 |
247 scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveOutputBuffer() { | 248 scoped_refptr<media::VideoFrame> VideoCaptureController::ReserveOutputBuffer() { |
248 base::AutoLock lock(buffer_pool_lock_); | 249 base::AutoLock lock(buffer_pool_lock_); |
249 if (!buffer_pool_) | 250 if (!buffer_pool_.get()) |
250 return NULL; | 251 return NULL; |
251 return buffer_pool_->ReserveForProducer(0); | 252 return buffer_pool_->ReserveForProducer(0); |
252 } | 253 } |
253 | 254 |
254 // Implements VideoCaptureDevice::EventHandler. | 255 // Implements VideoCaptureDevice::EventHandler. |
255 // OnIncomingCapturedFrame is called the thread running the capture device. | 256 // OnIncomingCapturedFrame is called the thread running the capture device. |
256 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 257 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
257 void VideoCaptureController::OnIncomingCapturedFrame( | 258 void VideoCaptureController::OnIncomingCapturedFrame( |
258 const uint8* data, | 259 const uint8* data, |
259 int length, | 260 int length, |
260 base::Time timestamp, | 261 base::Time timestamp, |
261 int rotation, | 262 int rotation, |
262 bool flip_vert, | 263 bool flip_vert, |
263 bool flip_horiz) { | 264 bool flip_horiz) { |
264 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || | 265 DCHECK(frame_info_.color == media::VideoCaptureCapability::kI420 || |
265 frame_info_.color == media::VideoCaptureCapability::kYV12 || | 266 frame_info_.color == media::VideoCaptureCapability::kYV12 || |
266 (rotation == 0 && !flip_vert && !flip_horiz)); | 267 (rotation == 0 && !flip_vert && !flip_horiz)); |
267 | 268 |
268 scoped_refptr<media::VideoFrame> dst; | 269 scoped_refptr<media::VideoFrame> dst; |
269 { | 270 { |
270 base::AutoLock lock(buffer_pool_lock_); | 271 base::AutoLock lock(buffer_pool_lock_); |
271 if (!buffer_pool_) | 272 if (!buffer_pool_.get()) |
272 return; | 273 return; |
273 dst = buffer_pool_->ReserveForProducer(rotation); | 274 dst = buffer_pool_->ReserveForProducer(rotation); |
274 } | 275 } |
275 | 276 |
276 if (!dst) | 277 if (!dst.get()) |
277 return; | 278 return; |
278 | 279 |
279 uint8* yplane = dst->data(media::VideoFrame::kYPlane); | 280 uint8* yplane = dst->data(media::VideoFrame::kYPlane); |
280 uint8* uplane = dst->data(media::VideoFrame::kUPlane); | 281 uint8* uplane = dst->data(media::VideoFrame::kUPlane); |
281 uint8* vplane = dst->data(media::VideoFrame::kVPlane); | 282 uint8* vplane = dst->data(media::VideoFrame::kVPlane); |
282 | 283 |
283 // Do color conversion from the camera format to I420. | 284 // Do color conversion from the camera format to I420. |
284 switch (frame_info_.color) { | 285 switch (frame_info_.color) { |
285 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. | 286 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. |
286 break; | 287 break; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 | 361 |
361 // OnIncomingCapturedVideoFrame is called the thread running the capture device. | 362 // OnIncomingCapturedVideoFrame is called the thread running the capture device. |
362 void VideoCaptureController::OnIncomingCapturedVideoFrame( | 363 void VideoCaptureController::OnIncomingCapturedVideoFrame( |
363 const scoped_refptr<media::VideoFrame>& frame, | 364 const scoped_refptr<media::VideoFrame>& frame, |
364 base::Time timestamp) { | 365 base::Time timestamp) { |
365 | 366 |
366 scoped_refptr<media::VideoFrame> target; | 367 scoped_refptr<media::VideoFrame> target; |
367 { | 368 { |
368 base::AutoLock lock(buffer_pool_lock_); | 369 base::AutoLock lock(buffer_pool_lock_); |
369 | 370 |
370 if (!buffer_pool_) | 371 if (!buffer_pool_.get()) |
371 return; | 372 return; |
372 | 373 |
373 // If this is a frame that belongs to the buffer pool, we can forward it | 374 // If this is a frame that belongs to the buffer pool, we can forward it |
374 // directly to the IO thread and be done. | 375 // directly to the IO thread and be done. |
375 if (buffer_pool_->RecognizeReservedBuffer(frame)) { | 376 if (buffer_pool_->RecognizeReservedBuffer(frame)) { |
376 BrowserThread::PostTask(BrowserThread::IO, | 377 BrowserThread::PostTask(BrowserThread::IO, |
377 FROM_HERE, | 378 FROM_HERE, |
378 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 379 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
379 this, frame, timestamp)); | 380 this, frame, timestamp)); |
380 return; | 381 return; |
381 } | 382 } |
382 // Otherwise, this is a frame that belongs to the caller, and we must copy | 383 // Otherwise, this is a frame that belongs to the caller, and we must copy |
383 // it to a frame from the buffer pool. | 384 // it to a frame from the buffer pool. |
384 target = buffer_pool_->ReserveForProducer(0); | 385 target = buffer_pool_->ReserveForProducer(0); |
385 } | 386 } |
386 | 387 |
387 if (!target) | 388 if (!target.get()) |
388 return; | 389 return; |
389 | 390 |
390 // Validate the inputs. | 391 // Validate the inputs. |
391 if (frame->coded_size() != target->coded_size()) | 392 if (frame->coded_size() != target->coded_size()) |
392 return; // Only exact copies are supported. | 393 return; // Only exact copies are supported. |
393 if (!(frame->format() == media::VideoFrame::I420 || | 394 if (!(frame->format() == media::VideoFrame::I420 || |
394 frame->format() == media::VideoFrame::YV12 || | 395 frame->format() == media::VideoFrame::YV12 || |
395 frame->format() == media::VideoFrame::RGB32)) { | 396 frame->format() == media::VideoFrame::RGB32)) { |
396 NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame"; | 397 NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame"; |
397 return; | 398 return; |
(...skipping 17 matching lines...) Expand all Loading... |
415 case media::VideoFrame::NATIVE_TEXTURE: { | 416 case media::VideoFrame::NATIVE_TEXTURE: { |
416 NOTREACHED(); | 417 NOTREACHED(); |
417 break; | 418 break; |
418 } | 419 } |
419 case media::VideoFrame::I420: | 420 case media::VideoFrame::I420: |
420 case media::VideoFrame::YV12: { | 421 case media::VideoFrame::YV12: { |
421 DCHECK(!chopped_width_ && !chopped_height_); | 422 DCHECK(!chopped_width_ && !chopped_height_); |
422 media::CopyYPlane(frame->data(kYPlane), | 423 media::CopyYPlane(frame->data(kYPlane), |
423 frame->stride(kYPlane), | 424 frame->stride(kYPlane), |
424 frame->rows(kYPlane), | 425 frame->rows(kYPlane), |
425 target); | 426 target.get()); |
426 media::CopyUPlane(frame->data(kUPlane), | 427 media::CopyUPlane(frame->data(kUPlane), |
427 frame->stride(kUPlane), | 428 frame->stride(kUPlane), |
428 frame->rows(kUPlane), | 429 frame->rows(kUPlane), |
429 target); | 430 target.get()); |
430 media::CopyVPlane(frame->data(kVPlane), | 431 media::CopyVPlane(frame->data(kVPlane), |
431 frame->stride(kVPlane), | 432 frame->stride(kVPlane), |
432 frame->rows(kVPlane), | 433 frame->rows(kVPlane), |
433 target); | 434 target.get()); |
434 break; | 435 break; |
435 } | 436 } |
436 case media::VideoFrame::YV12A: { | 437 case media::VideoFrame::YV12A: { |
437 DCHECK(!chopped_width_ && !chopped_height_); | 438 DCHECK(!chopped_width_ && !chopped_height_); |
438 media::CopyYPlane(frame->data(kYPlane), | 439 media::CopyYPlane(frame->data(kYPlane), |
439 frame->stride(kYPlane), | 440 frame->stride(kYPlane), |
440 frame->rows(kYPlane), | 441 frame->rows(kYPlane), |
441 target); | 442 target.get()); |
442 media::CopyUPlane(frame->data(kUPlane), | 443 media::CopyUPlane(frame->data(kUPlane), |
443 frame->stride(kUPlane), | 444 frame->stride(kUPlane), |
444 frame->rows(kUPlane), | 445 frame->rows(kUPlane), |
445 target); | 446 target.get()); |
446 media::CopyVPlane(frame->data(kVPlane), | 447 media::CopyVPlane(frame->data(kVPlane), |
447 frame->stride(kVPlane), | 448 frame->stride(kVPlane), |
448 frame->rows(kVPlane), | 449 frame->rows(kVPlane), |
449 target); | 450 target.get()); |
450 media::CopyAPlane(frame->data(kAPlane), | 451 media::CopyAPlane(frame->data(kAPlane), |
451 frame->stride(kAPlane), | 452 frame->stride(kAPlane), |
452 frame->rows(kAPlane), | 453 frame->rows(kAPlane), |
453 target); | 454 target.get()); |
454 break; | 455 break; |
455 } | 456 } |
456 case media::VideoFrame::RGB32: { | 457 case media::VideoFrame::RGB32: { |
457 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), | 458 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), |
458 target->data(kYPlane), | 459 target->data(kYPlane), |
459 target->data(kUPlane), | 460 target->data(kUPlane), |
460 target->data(kVPlane), | 461 target->data(kVPlane), |
461 target->coded_size().width(), | 462 target->coded_size().width(), |
462 target->coded_size().height(), | 463 target->coded_size().height(), |
463 frame->stride(kRGBPlane), | 464 frame->stride(kRGBPlane), |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 BrowserThread::PostTask(BrowserThread::IO, | 514 BrowserThread::PostTask(BrowserThread::IO, |
514 FROM_HERE, | 515 FROM_HERE, |
515 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); | 516 base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); |
516 } | 517 } |
517 | 518 |
518 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | 519 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( |
519 const scoped_refptr<media::VideoFrame>& reserved_frame, | 520 const scoped_refptr<media::VideoFrame>& reserved_frame, |
520 base::Time timestamp) { | 521 base::Time timestamp) { |
521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 522 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
522 | 523 |
523 if (!buffer_pool_) | 524 if (!buffer_pool_.get()) |
524 return; | 525 return; |
525 | 526 |
526 int buffer_id = buffer_pool_->RecognizeReservedBuffer(reserved_frame); | 527 int buffer_id = buffer_pool_->RecognizeReservedBuffer(reserved_frame); |
527 if (!buffer_id) { | 528 if (!buffer_id) { |
528 NOTREACHED(); | 529 NOTREACHED(); |
529 return; | 530 return; |
530 } | 531 } |
531 | 532 |
532 int count = 0; | 533 int count = 0; |
533 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 534 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
534 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 535 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
535 client_it != controller_clients_.end(); ++client_it) { | 536 client_it != controller_clients_.end(); ++client_it) { |
536 if ((*client_it)->session_closed) | 537 if ((*client_it)->session_closed) |
537 continue; | 538 continue; |
538 | 539 |
539 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, | 540 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, |
540 buffer_id, timestamp); | 541 buffer_id, timestamp); |
541 (*client_it)->buffers.insert(buffer_id); | 542 (*client_it)->buffers.insert(buffer_id); |
542 count++; | 543 count++; |
543 } | 544 } |
544 } | 545 } |
545 | 546 |
546 buffer_pool_->HoldForConsumers(reserved_frame, buffer_id, count); | 547 buffer_pool_->HoldForConsumers(reserved_frame, buffer_id, count); |
547 } | 548 } |
548 | 549 |
549 void VideoCaptureController::DoFrameInfoOnIOThread() { | 550 void VideoCaptureController::DoFrameInfoOnIOThread() { |
550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
551 DCHECK(!buffer_pool_) | 552 DCHECK(!buffer_pool_.get()) |
552 << "Device is restarted without releasing shared memory."; | 553 << "Device is restarted without releasing shared memory."; |
553 | 554 |
554 // Allocate memory only when device has been started. | 555 // Allocate memory only when device has been started. |
555 if (state_ != VIDEO_CAPTURE_STATE_STARTED) | 556 if (state_ != VIDEO_CAPTURE_STATE_STARTED) |
556 return; | 557 return; |
557 | 558 |
558 scoped_refptr<VideoCaptureBufferPool> buffer_pool = | 559 scoped_refptr<VideoCaptureBufferPool> buffer_pool = |
559 new VideoCaptureBufferPool( | 560 new VideoCaptureBufferPool( |
560 gfx::Size(frame_info_.width, frame_info_.height), kNoOfBuffers); | 561 gfx::Size(frame_info_.width, frame_info_.height), kNoOfBuffers); |
561 | 562 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
602 PostStopping(); | 603 PostStopping(); |
603 } | 604 } |
604 } | 605 } |
605 | 606 |
606 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { | 607 void VideoCaptureController::SendFrameInfoAndBuffers(ControllerClient* client) { |
607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
608 DCHECK(frame_info_available_); | 609 DCHECK(frame_info_available_); |
609 client->event_handler->OnFrameInfo(client->controller_id, | 610 client->event_handler->OnFrameInfo(client->controller_id, |
610 frame_info_.width, frame_info_.height, | 611 frame_info_.width, frame_info_.height, |
611 frame_info_.frame_rate); | 612 frame_info_.frame_rate); |
612 if (!buffer_pool_) | 613 if (!buffer_pool_.get()) |
613 return; | 614 return; |
614 | 615 |
615 for (int buffer_id = 1; buffer_id <= buffer_pool_->count(); ++buffer_id) { | 616 for (int buffer_id = 1; buffer_id <= buffer_pool_->count(); ++buffer_id) { |
616 base::SharedMemoryHandle remote_handle = | 617 base::SharedMemoryHandle remote_handle = |
617 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); | 618 buffer_pool_->ShareToProcess(buffer_id, client->render_process_handle); |
618 | 619 |
619 client->event_handler->OnBufferCreated(client->controller_id, | 620 client->event_handler->OnBufferCreated(client->controller_id, |
620 remote_handle, | 621 remote_handle, |
621 buffer_pool_->GetMemorySize(), | 622 buffer_pool_->GetMemorySize(), |
622 buffer_id); | 623 buffer_id); |
(...skipping 30 matching lines...) Expand all Loading... |
653 | 654 |
654 // This function is called when all buffers have been returned to controller, | 655 // This function is called when all buffers have been returned to controller, |
655 // or when device is stopped. It decides whether the device needs to be | 656 // or when device is stopped. It decides whether the device needs to be |
656 // restarted. | 657 // restarted. |
657 void VideoCaptureController::PostStopping() { | 658 void VideoCaptureController::PostStopping() { |
658 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
659 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPING); | 660 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPING); |
660 | 661 |
661 // When clients still have some buffers, or device has not been stopped yet, | 662 // When clients still have some buffers, or device has not been stopped yet, |
662 // do nothing. | 663 // do nothing. |
663 if ((buffer_pool_ && buffer_pool_->IsAnyBufferHeldForConsumers()) || | 664 if ((buffer_pool_.get() && buffer_pool_->IsAnyBufferHeldForConsumers()) || |
664 device_in_use_) | 665 device_in_use_) |
665 return; | 666 return; |
666 | 667 |
667 { | 668 { |
668 base::AutoLock lock(buffer_pool_lock_); | 669 base::AutoLock lock(buffer_pool_lock_); |
669 buffer_pool_ = NULL; | 670 buffer_pool_ = NULL; |
670 } | 671 } |
671 | 672 |
672 // No more client. Therefore the controller is stopped. | 673 // No more client. Therefore the controller is stopped. |
673 if (controller_clients_.empty() && pending_clients_.empty()) { | 674 if (controller_clients_.empty() && pending_clients_.empty()) { |
(...skipping 21 matching lines...) Expand all Loading... |
695 controller_clients_.push_back((*client_it)); | 696 controller_clients_.push_back((*client_it)); |
696 pending_clients_.erase(client_it++); | 697 pending_clients_.erase(client_it++); |
697 } | 698 } |
698 // Request the manager to start the actual capture. | 699 // Request the manager to start the actual capture. |
699 video_capture_manager_->Start(current_params_, this); | 700 video_capture_manager_->Start(current_params_, this); |
700 state_ = VIDEO_CAPTURE_STATE_STARTED; | 701 state_ = VIDEO_CAPTURE_STATE_STARTED; |
701 device_in_use_ = true; | 702 device_in_use_ = true; |
702 } | 703 } |
703 | 704 |
704 } // namespace content | 705 } // namespace content |
OLD | NEW |