| 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_GE(dib->created_size(), |
| 276 static_cast<size_t>(frame_info_.width * 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 // Implements VideoCaptureDevice::EventHandler. |
| 285 // OnIncomingCapturedFrame is called the thread running the capture device. |
| 286 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
| 287 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, |
| 288 int length, |
| 289 base::Time timestamp) { |
| 290 int buffer_id = 0; |
| 291 uint8* yplane = NULL; |
| 292 uint8* uplane = NULL; |
| 293 uint8* vplane = NULL; |
| 294 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) |
| 273 return; | 295 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 | 296 |
| 284 // Do color conversion from the camera format to I420. | 297 // Do color conversion from the camera format to I420. |
| 285 switch (frame_info_.color) { | 298 switch (frame_info_.color) { |
| 286 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. | 299 case media::VideoCaptureCapability::kColorUnknown: // Color format not set. |
| 287 break; | 300 break; |
| 288 case media::VideoCaptureCapability::kI420: { | 301 case media::VideoCaptureCapability::kI420: { |
| 289 DCHECK(!chopped_width_ && !chopped_height_); | 302 DCHECK(!chopped_width_ && !chopped_height_); |
| 290 memcpy(target, data, (frame_info_.width * frame_info_.height * 3) / 2); | 303 memcpy(yplane, data, (frame_info_.width * frame_info_.height * 3) / 2); |
| 291 break; | 304 break; |
| 292 } | 305 } |
| 293 case media::VideoCaptureCapability::kYV12: { | 306 case media::VideoCaptureCapability::kYV12: { |
| 294 DCHECK(!chopped_width_ && !chopped_height_); | 307 DCHECK(!chopped_width_ && !chopped_height_); |
| 295 const uint8* ptr = data; | 308 const uint8* ptr = data; |
| 296 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); | 309 memcpy(yplane, ptr, (frame_info_.width * frame_info_.height)); |
| 297 ptr += frame_info_.width * frame_info_.height; | 310 ptr += frame_info_.width * frame_info_.height; |
| 298 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); | 311 memcpy(vplane, ptr, (frame_info_.width * frame_info_.height) >> 2); |
| 299 ptr += (frame_info_.width * frame_info_.height) >> 2; | 312 ptr += (frame_info_.width * frame_info_.height) >> 2; |
| 300 memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2); | 313 memcpy(uplane, ptr, (frame_info_.width * frame_info_.height) >> 2); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 default: | 371 default: |
| 359 NOTREACHED(); | 372 NOTREACHED(); |
| 360 } | 373 } |
| 361 | 374 |
| 362 BrowserThread::PostTask(BrowserThread::IO, | 375 BrowserThread::PostTask(BrowserThread::IO, |
| 363 FROM_HERE, | 376 FROM_HERE, |
| 364 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, | 377 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 365 this, buffer_id, timestamp)); | 378 this, buffer_id, timestamp)); |
| 366 } | 379 } |
| 367 | 380 |
| 381 // OnIncomingCapturedVideoFrame is called the thread running the capture device. |
| 382 void VideoCaptureController::OnIncomingCapturedVideoFrame( |
| 383 media::VideoFrame* frame, |
| 384 base::Time timestamp) { |
| 385 // Validate the inputs. |
| 386 gfx::Size target_size = gfx::Size(frame_info_.width, frame_info_.height); |
| 387 if (frame->coded_size() != target_size) |
| 388 return; // Only exact copies are supported. |
| 389 if (!(frame->format() == media::VideoFrame::I420 || |
| 390 frame->format() == media::VideoFrame::YV12 || |
| 391 frame->format() == media::VideoFrame::RGB32)) { |
| 392 NOTREACHED() << "Unsupported format passed to OnIncomingCapturedVideoFrame"; |
| 393 return; |
| 394 } |
| 395 |
| 396 // Carve out a shared memory buffer. |
| 397 int buffer_id = 0; |
| 398 uint8* yplane = NULL; |
| 399 uint8* uplane = NULL; |
| 400 uint8* vplane = NULL; |
| 401 if (!ReserveSharedMemory(&buffer_id, &yplane, &uplane, &vplane)) |
| 402 return; |
| 403 |
| 404 scoped_refptr<media::VideoFrame> target_as_frame( |
| 405 media::VideoFrame::WrapExternalYuvData( |
| 406 media::VideoFrame::YV12, // Actually I420, but it's equivalent here. |
| 407 target_size, gfx::Rect(target_size), target_size, |
| 408 frame_info_.width, // y stride |
| 409 frame_info_.width / 2, // v stride |
| 410 frame_info_.width / 2, // u stride |
| 411 yplane, |
| 412 uplane, |
| 413 vplane, |
| 414 base::TimeDelta(), |
| 415 base::Bind(&base::DoNothing))); |
| 416 |
| 417 const int kYPlane = media::VideoFrame::kYPlane; |
| 418 const int kUPlane = media::VideoFrame::kUPlane; |
| 419 const int kVPlane = media::VideoFrame::kVPlane; |
| 420 const int kRGBPlane = media::VideoFrame::kRGBPlane; |
| 421 |
| 422 // Do color conversion from the camera format to I420. |
| 423 switch (frame->format()) { |
| 424 case media::VideoFrame::INVALID: |
| 425 case media::VideoFrame::YV16: |
| 426 case media::VideoFrame::EMPTY: |
| 427 case media::VideoFrame::NATIVE_TEXTURE: { |
| 428 NOTREACHED(); |
| 429 break; |
| 430 } |
| 431 case media::VideoFrame::I420: |
| 432 case media::VideoFrame::YV12: { |
| 433 DCHECK(!chopped_width_ && !chopped_height_); |
| 434 media::CopyYPlane(frame->data(kYPlane), |
| 435 frame->stride(kYPlane), |
| 436 frame->rows(kYPlane), |
| 437 target_as_frame); |
| 438 media::CopyUPlane(frame->data(kUPlane), |
| 439 frame->stride(kUPlane), |
| 440 frame->rows(kUPlane), |
| 441 target_as_frame); |
| 442 media::CopyVPlane(frame->data(kVPlane), |
| 443 frame->stride(kVPlane), |
| 444 frame->rows(kVPlane), |
| 445 target_as_frame); |
| 446 break; |
| 447 } |
| 448 case media::VideoFrame::RGB32: { |
| 449 media::ConvertRGB32ToYUV(frame->data(kRGBPlane), |
| 450 target_as_frame->data(kYPlane), |
| 451 target_as_frame->data(kUPlane), |
| 452 target_as_frame->data(kVPlane), |
| 453 target_size.width(), |
| 454 target_size.height(), |
| 455 frame->stride(kRGBPlane), |
| 456 target_as_frame->stride(kYPlane), |
| 457 target_as_frame->stride(kUPlane)); |
| 458 break; |
| 459 } |
| 460 } |
| 461 |
| 462 BrowserThread::PostTask(BrowserThread::IO, |
| 463 FROM_HERE, |
| 464 base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| 465 this, buffer_id, timestamp)); |
| 466 } |
| 467 |
| 368 void VideoCaptureController::OnError() { | 468 void VideoCaptureController::OnError() { |
| 369 BrowserThread::PostTask(BrowserThread::IO, | 469 BrowserThread::PostTask(BrowserThread::IO, |
| 370 FROM_HERE, | 470 FROM_HERE, |
| 371 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); | 471 base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); |
| 372 } | 472 } |
| 373 | 473 |
| 374 void VideoCaptureController::OnFrameInfo( | 474 void VideoCaptureController::OnFrameInfo( |
| 375 const media::VideoCaptureCapability& info) { | 475 const media::VideoCaptureCapability& info) { |
| 376 frame_info_= info; | 476 frame_info_= info; |
| 377 // Handle cases when |info| has odd numbers for width/height. | 477 // Handle cases when |info| has odd numbers for width/height. |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 base::AutoLock lock(lock_); | 699 base::AutoLock lock(lock_); |
| 600 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | 700 for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
| 601 dib_it != owned_dibs_.end(); dib_it++) { | 701 dib_it != owned_dibs_.end(); dib_it++) { |
| 602 if (dib_it->second->references > 0) | 702 if (dib_it->second->references > 0) |
| 603 return true; | 703 return true; |
| 604 } | 704 } |
| 605 return false; | 705 return false; |
| 606 } | 706 } |
| 607 | 707 |
| 608 } // namespace content | 708 } // namespace content |
| OLD | NEW |