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( |
| 249 // Implements VideoCaptureDevice::EventHandler. | 251 int* buffer_id_out, uint8** yplane, uint8** uplane, uint8** vplane) { |
| 250 // OnIncomingCapturedFrame is called the thread running the capture device. | |
| 251 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | |
| 252 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | |
| 253 int length, | |
| 254 base::Time timestamp) { | |
| 255 int buffer_id = 0; | 252 int buffer_id = 0; |
| 256 base::SharedMemory* dib = NULL; | 253 base::SharedMemory* dib = NULL; |
| 257 { | 254 { |
| 258 base::AutoLock lock(lock_); | 255 base::AutoLock lock(lock_); |
| 259 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | 256 for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
| 260 dib_it != owned_dibs_.end(); dib_it++) { | 257 dib_it != owned_dibs_.end(); dib_it++) { |
| 261 if (dib_it->second->references == 0) { | 258 if (dib_it->second->references == 0) { |
| 262 buffer_id = dib_it->first; | 259 buffer_id = dib_it->first; |
| 263 // Use special value "-1" in order to not be treated as buffer at | 260 // Use special value "-1" in order to not be treated as buffer at |
| 264 // renderer side. | 261 // renderer side. |
| 265 dib_it->second->references = -1; | 262 dib_it->second->references = -1; |
| 266 dib = dib_it->second->shared_memory.get(); | 263 dib = dib_it->second->shared_memory.get(); |
| 267 break; | 264 break; |
| 268 } | 265 } |
| 269 } | 266 } |
| 270 } | 267 } |
| 271 | 268 |
| 272 if (!dib) { | 269 if (!dib) |
| 270 return false; | |
| 271 | |
| 272 *buffer_id_out = buffer_id; | |
| 273 CHECK(dib->created_size() >= static_cast<size_t>(frame_info_.width * | |
| 274 frame_info_.height * 3) / 2); | |
| 275 uint8* target = static_cast<uint8*>(dib->memory()); | |
| 276 *yplane = target; | |
| 277 *uplane = *yplane + frame_info_.width * frame_info_.height; | |
| 278 *vplane = *uplane + (frame_info_.width * frame_info_.height) / 4; | |
| 279 return true; | |
| 280 } | |
| 281 | |
| 282 /////////////////////////////////////////////////////////////////////////////// | |
| 283 // Implements VideoCaptureDevice::EventHandler. | |
| 284 // OnIncomingCapturedFrame is called the thread running the capture device. | |
| 285 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | |
| 286 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | |
| 287 int length, | |
| 288 base::Time timestamp) { | |
| 289 int buffer_id = 0; | |
| 290 uint8* yplane = NULL; | |
| 291 uint8* uplane = NULL; | |
| 292 uint8* vplane = NULL; | |
| 293 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) | |
| 273 return; | 294 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 | 295 |
| 284 // Do color conversion from the camera format to I420. | 296 // Do color conversion from the camera format to I420. |
| 285 switch (frame_info_.color) { | 297 switch (frame_info_.color) { |
| 286 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. | 298 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. |
| 287 break; | 299 break; |
| 288 case media::VideoCaptureCapability::kI420: { | 300 case media::VideoCaptureCapability::kI420: { |
| 289 DCHECK(!chopped_width_ && !chopped_height_); | 301 DCHECK(!chopped_width_ && !chopped_height_); |
| 290 memcpy(target, data, (frame_info_.width * frame_info_.height * 3) / 2); | 302 memcpy(yplane, data, (frame_info_.width * frame_info_.height * 3) / 2); |
| 291 break; | 303 break; |
| 292 } | 304 } |
| 293 case media::VideoCaptureCapability::kYV12: { | 305 case media::VideoCaptureCapability::kYV12: { |
| 294 DCHECK(!chopped_width_ && !chopped_height_); | 306 DCHECK(!chopped_width_ && !chopped_height_); |
| 295 const uint8* ptr = data; | 307 const uint8* ptr = data; |
| 296 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); | 308 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); |
| 297 ptr += frame_info_.width * frame_info_.height; | 309 ptr += frame_info_.width * frame_info_.height; |
| 298 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); | 310 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); |
| 299 ptr += (frame_info_.width * frame_info_.height) >> 2; | 311 ptr += (frame_info_.width * frame_info_.height) >> 2; |
| 300 memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2); | 312 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: | 364 default: |
| 353 NOTREACHED(); | 365 NOTREACHED(); |
| 354 } | 366 } |
| 355 | 367 |
| 356 BrowserThread::PostTask(BrowserThread::IO, | 368 BrowserThread::PostTask(BrowserThread::IO, |
| 357 FROM_HERE, | 369 FROM_HERE, |
| 358 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 370 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 359 this, buffer_id, timestamp)); | 371 this, buffer_id, timestamp)); |
| 360 } | 372 } |
| 361 | 373 |
| 374 // OnIncomingCapturedVideoFrame is called the thread running the capture device. | |
| 375 void VideoCaptureController::OnIncomingCapturedVideoFrame( | |
| 376 media::VideoFrame* frame, base::Time timestamp) { | |
| 377 int buffer_id = 0; | |
| 378 uint8* yplane = NULL; | |
| 379 uint8* uplane = NULL; | |
| 380 uint8* vplane = NULL; | |
| 381 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) | |
| 382 return; | |
| 383 | |
| 384 gfx::Size target_size = gfx::Size(frame_info_.width, frame_info_.height); | |
| 385 | |
| 386 if (frame->coded_size() != target_size) | |
| 387 return; // Only exact copies are supported. | |
| 388 | |
| 389 scoped_refptr<media::VideoFrame> target_as_frame( | |
| 390 media::VideoFrame::WrapExternalYuvData( | |
| 391 media::VideoFrame::YV12, // Actually I420, but it's equivalent here. | |
|
wjia(left Chromium)
2013/02/04 23:48:40
nit: indent by 4.
ncarter (slow)
2013/02/05 17:36:08
Done.
| |
| 392 target_size, gfx::Rect(target_size), target_size, | |
| 393 frame_info_.width, // y stride | |
| 394 frame_info_.width / 2, // v stride | |
| 395 frame_info_.width / 2, // u stride | |
| 396 yplane, | |
| 397 uplane, | |
| 398 vplane, | |
| 399 base::TimeDelta(), | |
| 400 base::Bind(&base::DoNothing))); | |
| 401 | |
| 402 const int kYPlane = media::VideoFrame::kYPlane; | |
| 403 const int kUPlane = media::VideoFrame::kUPlane; | |
| 404 const int kVPlane = media::VideoFrame::kVPlane; | |
| 405 const int kRGBPlane = media::VideoFrame::kRGBPlane; | |
| 406 | |
| 407 // Do color conversion from the camera format to I420. | |
| 408 switch (frame->format()) { | |
| 409 case media::VideoFrame::EMPTY: | |
| 410 case media::VideoFrame::INVALID: // Color format not set. | |
| 411 case media::VideoFrame::NATIVE_TEXTURE: | |
| 412 // These types will never work. | |
| 413 break; | |
| 414 case media::VideoFrame::I420: | |
| 415 case media::VideoFrame::YV12: { | |
| 416 DCHECK(!chopped_width_ && !chopped_height_); | |
| 417 media::CopyYPlane(frame->data(kYPlane), | |
| 418 frame->stride(kYPlane), | |
| 419 frame->rows(kYPlane), | |
| 420 target_as_frame); | |
| 421 media::CopyUPlane(frame->data(kUPlane), | |
| 422 frame->stride(kUPlane), | |
| 423 frame->rows(kUPlane), | |
| 424 target_as_frame); | |
| 425 media::CopyVPlane(frame->data(kVPlane), | |
| 426 frame->stride(kVPlane), | |
| 427 frame->rows(kVPlane), | |
| 428 target_as_frame); | |
| 429 break; | |
| 430 } | |
| 431 case media::VideoFrame::RGB32: { | |
| 432 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), | |
| 433 target_as_frame->data(kYPlane), | |
| 434 target_as_frame->data(kUPlane), | |
| 435 target_as_frame->data(kVPlane), | |
| 436 target_size.width(), | |
| 437 target_size.height(), | |
| 438 frame->stride(kRGBPlane), | |
| 439 target_as_frame->stride(kYPlane), | |
| 440 target_as_frame->stride(kUPlane)); | |
| 441 break; | |
| 442 } | |
| 443 default: | |
| 444 NOTREACHED(); | |
| 445 } | |
| 446 | |
| 447 target_as_frame = NULL; // Wrapper was for temporary use only. | |
|
wjia(left Chromium)
2013/02/04 23:48:40
this is not needed.
ncarter (slow)
2013/02/05 17:36:08
Done.
| |
| 448 | |
| 449 BrowserThread::PostTask(BrowserThread::IO, | |
| 450 FROM_HERE, | |
| 451 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | |
| 452 this, buffer_id, timestamp)); | |
| 453 } | |
| 454 | |
| 362 void VideoCaptureController::OnError() { | 455 void VideoCaptureController::OnError() { |
| 363 BrowserThread::PostTask(BrowserThread::IO, | 456 BrowserThread::PostTask(BrowserThread::IO, |
| 364 FROM_HERE, | 457 FROM_HERE, |
| 365 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); | 458 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); |
| 366 } | 459 } |
| 367 | 460 |
| 368 void VideoCaptureController::OnFrameInfo( | 461 void VideoCaptureController::OnFrameInfo( |
| 369 const media::VideoCaptureCapability& info) { | 462 const media::VideoCaptureCapability& info) { |
| 370 frame_info_= info; | 463 frame_info_= info; |
| 371 // Handle cases when |info| has odd numbers for width/height. | 464 // 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_); | 686 base::AutoLock lock(lock_); |
| 594 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | 687 for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
| 595 dib_it != owned_dibs_.end(); dib_it++) { | 688 dib_it != owned_dibs_.end(); dib_it++) { |
| 596 if (dib_it->second->references > 0) | 689 if (dib_it->second->references > 0) |
| 597 return true; | 690 return true; |
| 598 } | 691 } |
| 599 return false; | 692 return false; |
| 600 } | 693 } |
| 601 | 694 |
| 602 } // namespace content | 695 } // namespace content |
| OLD | NEW |