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 #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/video_frame.h" | |
| 16 #include "media/base/video_util.h" | |
| 15 #include "media/base/yuv_convert.h" | 17 #include "media/base/yuv_convert.h" |
| 16 | 18 |
| 17 #if !defined(OS_IOS) && !defined(OS_ANDROID) | 19 #if !defined(OS_IOS) && !defined(OS_ANDROID) |
| 18 #include "third_party/libyuv/include/libyuv.h" | 20 #include "third_party/libyuv/include/libyuv.h" |
| 19 #endif | 21 #endif |
| 20 | 22 |
| 21 namespace content { | 23 namespace content { |
| 22 | 24 |
| 23 // The number of DIBs VideoCaptureController allocate. | 25 // The number of DIBs VideoCaptureController allocate. |
| 24 static const size_t kNoOfDIBS = 3; | 26 static const size_t kNoOfDIBS = 3; |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 } | 240 } |
| 239 | 241 |
| 240 // When all buffers have been returned by clients and device has been | 242 // When all buffers have been returned by clients and device has been |
| 241 // called to stop, check if restart is needed. This could happen when | 243 // called to stop, check if restart is needed. This could happen when |
| 242 // capture needs to be restarted due to resolution change. | 244 // capture needs to be restarted due to resolution change. |
| 243 if (!ClientHasDIB() && state_ == VIDEO_CAPTURE_STATE_STOPPING) { | 245 if (!ClientHasDIB() && state_ == VIDEO_CAPTURE_STATE_STOPPING) { |
| 244 PostStopping(); | 246 PostStopping(); |
| 245 } | 247 } |
| 246 } | 248 } |
| 247 | 249 |
| 248 /////////////////////////////////////////////////////////////////////////////// | 250 bool VideoCaptureController::ReserveSharedMemory(int* buffer_id_out, |
| 249 // Implements VideoCaptureDevice::EventHandler. | 251 uint8** yplane, |
| 250 // OnIncomingCapturedFrame is called the thread running the capture device. | 252 uint8** uplane, |
| 251 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 253 uint8** vplane) { |
| 252 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | |
| 253 int length, | |
| 254 base::Time timestamp) { | |
| 255 int buffer_id = 0; | 254 int buffer_id = 0; |
| 256 base::SharedMemory* dib = NULL; | 255 base::SharedMemory* dib = NULL; |
| 257 { | 256 { |
| 258 base::AutoLock lock(lock_); | 257 base::AutoLock lock(lock_); |
| 259 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | 258 for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
| 260 dib_it != owned_dibs_.end(); dib_it++) { | 259 dib_it != owned_dibs_.end(); dib_it++) { |
| 261 if (dib_it->second->references == 0) { | 260 if (dib_it->second->references == 0) { |
| 262 buffer_id = dib_it->first; | 261 buffer_id = dib_it->first; |
| 263 // Use special value "-1" in order to not be treated as buffer at | 262 // Use special value "-1" in order to not be treated as buffer at |
| 264 // renderer side. | 263 // renderer side. |
| 265 dib_it->second->references = -1; | 264 dib_it->second->references = -1; |
| 266 dib = dib_it->second->shared_memory.get(); | 265 dib = dib_it->second->shared_memory.get(); |
| 267 break; | 266 break; |
| 268 } | 267 } |
| 269 } | 268 } |
| 270 } | 269 } |
| 271 | 270 |
| 272 if (!dib) { | 271 if (!dib) |
| 272 return false; | |
| 273 | |
| 274 *buffer_id_out = buffer_id; | |
| 275 CHECK(dib->created_size() >= static_cast<size_t>(frame_info_.width * | |
|
scherkus (not reviewing)
2013/02/05 22:40:44
nit: CHECK_GE()?
ncarter (slow)
2013/02/06 23:54:44
Done.
| |
| 276 frame_info_.height * 3) / 2); | |
| 277 uint8* target = static_cast<uint8*>(dib->memory()); | |
| 278 *yplane = target; | |
| 279 *uplane = *yplane + frame_info_.width * frame_info_.height; | |
| 280 *vplane = *uplane + (frame_info_.width * frame_info_.height) / 4; | |
| 281 return true; | |
| 282 } | |
| 283 | |
| 284 /////////////////////////////////////////////////////////////////////////////// | |
| 285 // Implements VideoCaptureDevice::EventHandler. | |
| 286 // OnIncomingCapturedFrame is called the thread running the capture device. | |
| 287 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | |
| 288 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | |
| 289 int length, | |
| 290 base::Time timestamp) { | |
| 291 int buffer_id = 0; | |
| 292 uint8* yplane = NULL; | |
| 293 uint8* uplane = NULL; | |
| 294 uint8* vplane = NULL; | |
| 295 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) | |
| 273 return; | 296 return; |
| 274 } | |
| 275 | |
| 276 uint8* target = static_cast<uint8*>(dib->memory()); | |
| 277 CHECK(dib->created_size() >= static_cast<size_t> (frame_info_.width * | |
| 278 frame_info_.height * 3) / | |
| 279 2); | |
| 280 uint8* yplane = target; | |
| 281 uint8* uplane = target + frame_info_.width * frame_info_.height; | |
| 282 uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; | |
| 283 | 297 |
| 284 // Do color conversion from the camera format to I420. | 298 // Do color conversion from the camera format to I420. |
| 285 switch (frame_info_.color) { | 299 switch (frame_info_.color) { |
| 286 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. | 300 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. |
| 287 break; | 301 break; |
| 288 case media::VideoCaptureCapability::kI420: { | 302 case media::VideoCaptureCapability::kI420: { |
| 289 DCHECK(!chopped_width_ && !chopped_height_); | 303 DCHECK(!chopped_width_ && !chopped_height_); |
| 290 memcpy(target, data, (frame_info_.width * frame_info_.height * 3) / 2); | 304 memcpy(yplane, data, (frame_info_.width * frame_info_.height * 3) / 2); |
| 291 break; | 305 break; |
| 292 } | 306 } |
| 293 case media::VideoCaptureCapability::kYV12: { | 307 case media::VideoCaptureCapability::kYV12: { |
| 294 DCHECK(!chopped_width_ && !chopped_height_); | 308 DCHECK(!chopped_width_ && !chopped_height_); |
| 295 const uint8* ptr = data; | 309 const uint8* ptr = data; |
| 296 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); | 310 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); |
| 297 ptr += frame_info_.width * frame_info_.height; | 311 ptr += frame_info_.width * frame_info_.height; |
| 298 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); | 312 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); |
| 299 ptr += (frame_info_.width * frame_info_.height) >> 2; | 313 ptr += (frame_info_.width * frame_info_.height) >> 2; |
| 300 memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2); | 314 memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 352 default: | 366 default: |
| 353 NOTREACHED(); | 367 NOTREACHED(); |
| 354 } | 368 } |
| 355 | 369 |
| 356 BrowserThread::PostTask(BrowserThread::IO, | 370 BrowserThread::PostTask(BrowserThread::IO, |
| 357 FROM_HERE, | 371 FROM_HERE, |
| 358 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 372 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 359 this, buffer_id, timestamp)); | 373 this, buffer_id, timestamp)); |
| 360 } | 374 } |
| 361 | 375 |
| 376 // OnIncomingCapturedVideoFrame is called the thread running the capture device. | |
| 377 void VideoCaptureController::OnIncomingCapturedVideoFrame( | |
| 378 media::VideoFrame* frame, | |
| 379 base::Time timestamp) { | |
| 380 int buffer_id = 0; | |
| 381 uint8* yplane = NULL; | |
| 382 uint8* uplane = NULL; | |
| 383 uint8* vplane = NULL; | |
| 384 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) | |
| 385 return; | |
| 386 | |
| 387 gfx::Size target_size = gfx::Size(frame_info_.width, frame_info_.height); | |
| 388 | |
| 389 if (frame->coded_size() != target_size) | |
| 390 return; // Only exact copies are supported. | |
|
scherkus (not reviewing)
2013/02/05 22:40:44
if you reserve a DIB but return here, does the DIB
ncarter (slow)
2013/02/06 23:54:44
Good catch! Reordered these operations.
| |
| 391 | |
| 392 scoped_refptr<media::VideoFrame> target_as_frame( | |
| 393 media::VideoFrame::WrapExternalYuvData( | |
| 394 media::VideoFrame::YV12, // Actually I420, but it's equivalent here. | |
| 395 target_size, gfx::Rect(target_size), target_size, | |
| 396 frame_info_.width, // y stride | |
| 397 frame_info_.width / 2, // v stride | |
| 398 frame_info_.width / 2, // u stride | |
| 399 yplane, | |
| 400 uplane, | |
| 401 vplane, | |
| 402 base::TimeDelta(), | |
| 403 base::Bind(&base::DoNothing))); | |
| 404 | |
| 405 const int kYPlane = media::VideoFrame::kYPlane; | |
| 406 const int kUPlane = media::VideoFrame::kUPlane; | |
| 407 const int kVPlane = media::VideoFrame::kVPlane; | |
| 408 const int kRGBPlane = media::VideoFrame::kRGBPlane; | |
| 409 | |
| 410 // Do color conversion from the camera format to I420. | |
| 411 switch (frame->format()) { | |
| 412 case media::VideoFrame::EMPTY: | |
| 413 case media::VideoFrame::INVALID: // Color format not set. | |
| 414 case media::VideoFrame::NATIVE_TEXTURE: | |
| 415 // These types will never work. | |
|
scherkus (not reviewing)
2013/02/05 22:40:44
if possible, my preference would be to CHECK()sinc
ncarter (slow)
2013/02/06 23:54:44
CHECK() isn't as much fun for the user when it hap
| |
| 416 break; | |
| 417 case media::VideoFrame::I420: | |
| 418 case media::VideoFrame::YV12: { | |
| 419 DCHECK(!chopped_width_ && !chopped_height_); | |
| 420 media::CopyYPlane(frame->data(kYPlane), | |
| 421 frame->stride(kYPlane), | |
| 422 frame->rows(kYPlane), | |
| 423 target_as_frame); | |
| 424 media::CopyUPlane(frame->data(kUPlane), | |
| 425 frame->stride(kUPlane), | |
| 426 frame->rows(kUPlane), | |
| 427 target_as_frame); | |
| 428 media::CopyVPlane(frame->data(kVPlane), | |
| 429 frame->stride(kVPlane), | |
| 430 frame->rows(kVPlane), | |
| 431 target_as_frame); | |
| 432 break; | |
| 433 } | |
| 434 case media::VideoFrame::RGB32: { | |
| 435 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), | |
| 436 target_as_frame->data(kYPlane), | |
| 437 target_as_frame->data(kUPlane), | |
| 438 target_as_frame->data(kVPlane), | |
| 439 target_size.width(), | |
| 440 target_size.height(), | |
| 441 frame->stride(kRGBPlane), | |
| 442 target_as_frame->stride(kYPlane), | |
| 443 target_as_frame->stride(kUPlane)); | |
| 444 break; | |
| 445 } | |
| 446 default: | |
|
scherkus (not reviewing)
2013/02/05 22:40:44
I like having the compiler break when enums are ad
ncarter (slow)
2013/02/06 23:54:44
See above.
| |
| 447 NOTREACHED(); | |
| 448 } | |
| 449 | |
| 450 BrowserThread::PostTask(BrowserThread::IO, | |
| 451 FROM_HERE, | |
| 452 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
| 453 this, buffer_id, timestamp)); | |
| 454 } | |
| 455 | |
| 362 void VideoCaptureController::OnError() { | 456 void VideoCaptureController::OnError() { |
| 363 BrowserThread::PostTask(BrowserThread::IO, | 457 BrowserThread::PostTask(BrowserThread::IO, |
| 364 FROM_HERE, | 458 FROM_HERE, |
| 365 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); | 459 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); |
| 366 } | 460 } |
| 367 | 461 |
| 368 void VideoCaptureController::OnFrameInfo( | 462 void VideoCaptureController::OnFrameInfo( |
| 369 const media::VideoCaptureCapability& info) { | 463 const media::VideoCaptureCapability& info) { |
| 370 frame_info_= info; | 464 frame_info_= info; |
| 371 // Handle cases when |info| has odd numbers for width/height. | 465 // Handle cases when |info| has odd numbers for width/height. |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 base::AutoLock lock(lock_); | 687 base::AutoLock lock(lock_); |
| 594 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | 688 for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
| 595 dib_it != owned_dibs_.end(); dib_it++) { | 689 dib_it != owned_dibs_.end(); dib_it++) { |
| 596 if (dib_it->second->references > 0) | 690 if (dib_it->second->references > 0) |
| 597 return true; | 691 return true; |
| 598 } | 692 } |
| 599 return false; | 693 return false; |
| 600 } | 694 } |
| 601 | 695 |
| 602 } // namespace content | 696 } // namespace content |
| OLD | NEW |