| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/renderer/media/rtc_video_encoder.h" | 5 #include "content/renderer/media/rtc_video_encoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/location.h" | 8 #include "base/location.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_vector.h" | 10 #include "base/memory/scoped_vector.h" |
| 11 #include "base/message_loop/message_loop_proxy.h" | 11 #include "base/message_loop/message_loop_proxy.h" |
| 12 #include "base/synchronization/waitable_event.h" | 12 #include "base/synchronization/waitable_event.h" |
| 13 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" | 13 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" |
| 14 #include "media/base/bitstream_buffer.h" | 14 #include "media/base/bitstream_buffer.h" |
| 15 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
| 16 #include "media/base/video_util.h" |
| 16 #include "media/filters/gpu_video_accelerator_factories.h" | 17 #include "media/filters/gpu_video_accelerator_factories.h" |
| 17 #include "media/video/video_encode_accelerator.h" | 18 #include "media/video/video_encode_accelerator.h" |
| 18 | 19 |
| 19 #define NOTIFY_ERROR(x) \ | 20 #define NOTIFY_ERROR(x) \ |
| 20 do { \ | 21 do { \ |
| 21 DLOG(ERROR) << "calling NotifyError(): " << x; \ | 22 DLOG(ERROR) << "calling NotifyError(): " << x; \ |
| 22 NotifyError(x); \ | 23 NotifyError(x); \ |
| 23 } while (0) | 24 } while (0) |
| 24 | 25 |
| 25 namespace content { | 26 namespace content { |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 << ", output_buffer_size=" << output_buffer_size; | 262 << ", output_buffer_size=" << output_buffer_size; |
| 262 DCHECK(thread_checker_.CalledOnValidThread()); | 263 DCHECK(thread_checker_.CalledOnValidThread()); |
| 263 | 264 |
| 264 if (!video_encoder_) | 265 if (!video_encoder_) |
| 265 return; | 266 return; |
| 266 | 267 |
| 267 input_frame_coded_size_ = input_coded_size; | 268 input_frame_coded_size_ = input_coded_size; |
| 268 | 269 |
| 269 for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) { | 270 for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) { |
| 270 base::SharedMemory* shm = | 271 base::SharedMemory* shm = |
| 271 gpu_factories_->CreateSharedMemory(input_coded_size.GetArea() * 3 / 2); | 272 gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize( |
| 273 media::VideoFrame::I420, input_coded_size)); |
| 272 if (!shm) { | 274 if (!shm) { |
| 273 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): " | 275 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): " |
| 274 "failed to create input buffer " << i; | 276 "failed to create input buffer " << i; |
| 275 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | 277 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 276 return; | 278 return; |
| 277 } | 279 } |
| 278 input_buffers_.push_back(shm); | 280 input_buffers_.push_back(shm); |
| 279 input_buffers_free_.push_back(i); | 281 input_buffers_free_.push_back(i); |
| 280 } | 282 } |
| 281 | 283 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 input_next_frame_ = NULL; | 391 input_next_frame_ = NULL; |
| 390 input_next_frame_keyframe_ = false; | 392 input_next_frame_keyframe_ = false; |
| 391 | 393 |
| 392 if (!video_encoder_) { | 394 if (!video_encoder_) { |
| 393 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR); | 395 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR); |
| 394 return; | 396 return; |
| 395 } | 397 } |
| 396 | 398 |
| 397 const int index = input_buffers_free_.back(); | 399 const int index = input_buffers_free_.back(); |
| 398 base::SharedMemory* input_buffer = input_buffers_[index]; | 400 base::SharedMemory* input_buffer = input_buffers_[index]; |
| 399 | |
| 400 // Do a strided copy of the input frame to match the input requirements for | |
| 401 // the encoder. | |
| 402 // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312 | |
| 403 const uint8_t* src = next_frame->buffer(webrtc::kYPlane); | |
| 404 uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory()); | |
| 405 uint8* const y_dst = dst; | |
| 406 int width = input_frame_coded_size_.width(); | |
| 407 int stride = next_frame->stride(webrtc::kYPlane); | |
| 408 for (int i = 0; i < next_frame->height(); ++i) { | |
| 409 memcpy(dst, src, width); | |
| 410 src += stride; | |
| 411 dst += width; | |
| 412 } | |
| 413 src = next_frame->buffer(webrtc::kUPlane); | |
| 414 width = input_frame_coded_size_.width() / 2; | |
| 415 stride = next_frame->stride(webrtc::kUPlane); | |
| 416 for (int i = 0; i < next_frame->height() / 2; ++i) { | |
| 417 memcpy(dst, src, width); | |
| 418 src += stride; | |
| 419 dst += width; | |
| 420 } | |
| 421 src = next_frame->buffer(webrtc::kVPlane); | |
| 422 width = input_frame_coded_size_.width() / 2; | |
| 423 stride = next_frame->stride(webrtc::kVPlane); | |
| 424 for (int i = 0; i < next_frame->height() / 2; ++i) { | |
| 425 memcpy(dst, src, width); | |
| 426 src += stride; | |
| 427 dst += width; | |
| 428 } | |
| 429 | |
| 430 scoped_refptr<media::VideoFrame> frame = | 401 scoped_refptr<media::VideoFrame> frame = |
| 431 media::VideoFrame::WrapExternalSharedMemory( | 402 media::VideoFrame::WrapExternalSharedMemory( |
| 432 media::VideoFrame::I420, | 403 media::VideoFrame::I420, |
| 433 input_frame_coded_size_, | 404 input_frame_coded_size_, |
| 434 gfx::Rect(input_visible_size_), | 405 gfx::Rect(input_visible_size_), |
| 435 input_visible_size_, | 406 input_visible_size_, |
| 436 y_dst, | 407 reinterpret_cast<uint8*>(input_buffer->memory()), |
| 408 input_buffer->mapped_size(), |
| 437 input_buffer->handle(), | 409 input_buffer->handle(), |
| 438 base::TimeDelta(), | 410 base::TimeDelta(), |
| 439 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index)); | 411 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index)); |
| 412 if (!frame) { |
| 413 DLOG(ERROR) << "Impl::EncodeOneFrame(): failed to create frame"; |
| 414 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 415 return; |
| 416 } |
| 417 |
| 418 // Do a strided copy of the input frame to match the input requirements for |
| 419 // the encoder. |
| 420 // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312 |
| 421 media::CopyYPlane(next_frame->buffer(webrtc::kYPlane), |
| 422 next_frame->stride(webrtc::kYPlane), |
| 423 next_frame->height(), |
| 424 frame.get()); |
| 425 media::CopyUPlane(next_frame->buffer(webrtc::kUPlane), |
| 426 next_frame->stride(webrtc::kUPlane), |
| 427 next_frame->height(), |
| 428 frame.get()); |
| 429 media::CopyVPlane(next_frame->buffer(webrtc::kVPlane), |
| 430 next_frame->stride(webrtc::kVPlane), |
| 431 next_frame->height(), |
| 432 frame.get()); |
| 440 | 433 |
| 441 video_encoder_->Encode(frame, next_frame_keyframe); | 434 video_encoder_->Encode(frame, next_frame_keyframe); |
| 442 input_buffers_free_.pop_back(); | 435 input_buffers_free_.pop_back(); |
| 443 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); | 436 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); |
| 444 } | 437 } |
| 445 | 438 |
| 446 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) { | 439 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) { |
| 447 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index; | 440 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index; |
| 448 DCHECK(thread_checker_.CalledOnValidThread()); | 441 DCHECK(thread_checker_.CalledOnValidThread()); |
| 449 DCHECK_GE(index, 0); | 442 DCHECK_GE(index, 0); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 478 // | 471 // |
| 479 //////////////////////////////////////////////////////////////////////////////// | 472 //////////////////////////////////////////////////////////////////////////////// |
| 480 | 473 |
| 481 RTCVideoEncoder::RTCVideoEncoder( | 474 RTCVideoEncoder::RTCVideoEncoder( |
| 482 webrtc::VideoCodecType type, | 475 webrtc::VideoCodecType type, |
| 483 media::VideoCodecProfile profile, | 476 media::VideoCodecProfile profile, |
| 484 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories) | 477 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories) |
| 485 : video_codec_type_(type), | 478 : video_codec_type_(type), |
| 486 video_codec_profile_(profile), | 479 video_codec_profile_(profile), |
| 487 gpu_factories_(gpu_factories), | 480 gpu_factories_(gpu_factories), |
| 481 weak_this_factory_(this), |
| 488 encoded_image_callback_(NULL), | 482 encoded_image_callback_(NULL), |
| 489 impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) { | 483 impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) { |
| 490 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile; | 484 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile; |
| 491 } | 485 } |
| 492 | 486 |
| 493 RTCVideoEncoder::~RTCVideoEncoder() { | 487 RTCVideoEncoder::~RTCVideoEncoder() { |
| 494 DCHECK(thread_checker_.CalledOnValidThread()); | 488 DCHECK(thread_checker_.CalledOnValidThread()); |
| 495 Release(); | 489 Release(); |
| 496 DCHECK(!impl_); | 490 DCHECK(!impl_); |
| 497 } | 491 } |
| 498 | 492 |
| 499 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, | 493 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, |
| 500 int32_t number_of_cores, | 494 int32_t number_of_cores, |
| 501 uint32_t max_payload_size) { | 495 uint32_t max_payload_size) { |
| 502 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType | 496 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType |
| 503 << ", width=" << codec_settings->width | 497 << ", width=" << codec_settings->width |
| 504 << ", height=" << codec_settings->height | 498 << ", height=" << codec_settings->height |
| 505 << ", startBitrate=" << codec_settings->startBitrate; | 499 << ", startBitrate=" << codec_settings->startBitrate; |
| 506 DCHECK(thread_checker_.CalledOnValidThread()); | 500 DCHECK(thread_checker_.CalledOnValidThread()); |
| 507 DCHECK(!impl_); | 501 DCHECK(!impl_); |
| 508 | 502 |
| 509 weak_this_factory_.reset(new base::WeakPtrFactory<RTCVideoEncoder>(this)); | 503 weak_this_factory_.InvalidateWeakPtrs(); |
| 510 impl_ = new Impl(weak_this_factory_->GetWeakPtr(), gpu_factories_); | 504 impl_ = new Impl(weak_this_factory_.GetWeakPtr(), gpu_factories_); |
| 511 base::WaitableEvent initialization_waiter(true, false); | 505 base::WaitableEvent initialization_waiter(true, false); |
| 512 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 506 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 513 gpu_factories_->GetMessageLoop()->PostTask( | 507 gpu_factories_->GetMessageLoop()->PostTask( |
| 514 FROM_HERE, | 508 FROM_HERE, |
| 515 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, | 509 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, |
| 516 impl_, | 510 impl_, |
| 517 gfx::Size(codec_settings->width, codec_settings->height), | 511 gfx::Size(codec_settings->width, codec_settings->height), |
| 518 codec_settings->startBitrate, | 512 codec_settings->startBitrate, |
| 519 video_codec_profile_, | 513 video_codec_profile_, |
| 520 &initialization_waiter, | 514 &initialization_waiter, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 DVLOG(3) << "Release()"; | 565 DVLOG(3) << "Release()"; |
| 572 DCHECK(thread_checker_.CalledOnValidThread()); | 566 DCHECK(thread_checker_.CalledOnValidThread()); |
| 573 | 567 |
| 574 // Reset the gpu_factory_, in case we reuse this encoder. | 568 // Reset the gpu_factory_, in case we reuse this encoder. |
| 575 gpu_factories_->Abort(); | 569 gpu_factories_->Abort(); |
| 576 gpu_factories_ = gpu_factories_->Clone(); | 570 gpu_factories_ = gpu_factories_->Clone(); |
| 577 if (impl_) { | 571 if (impl_) { |
| 578 gpu_factories_->GetMessageLoop()->PostTask( | 572 gpu_factories_->GetMessageLoop()->PostTask( |
| 579 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); | 573 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); |
| 580 impl_ = NULL; | 574 impl_ = NULL; |
| 581 weak_this_factory_.reset(); | 575 weak_this_factory_.InvalidateWeakPtrs(); |
| 582 impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 576 impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 583 } | 577 } |
| 584 return WEBRTC_VIDEO_CODEC_OK; | 578 return WEBRTC_VIDEO_CODEC_OK; |
| 585 } | 579 } |
| 586 | 580 |
| 587 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) { | 581 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) { |
| 588 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss | 582 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss |
| 589 << ", rtt=" << rtt; | 583 << ", rtt=" << rtt; |
| 590 DCHECK(thread_checker_.CalledOnValidThread()); | 584 DCHECK(thread_checker_.CalledOnValidThread()); |
| 591 // Ignored. | 585 // Ignored. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 DCHECK(thread_checker_.CalledOnValidThread()); | 643 DCHECK(thread_checker_.CalledOnValidThread()); |
| 650 DVLOG(1) << "NotifyError(): error=" << error; | 644 DVLOG(1) << "NotifyError(): error=" << error; |
| 651 | 645 |
| 652 impl_status_ = error; | 646 impl_status_ = error; |
| 653 gpu_factories_->GetMessageLoop()->PostTask( | 647 gpu_factories_->GetMessageLoop()->PostTask( |
| 654 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); | 648 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); |
| 655 impl_ = NULL; | 649 impl_ = NULL; |
| 656 } | 650 } |
| 657 | 651 |
| 658 } // namespace content | 652 } // namespace content |
| OLD | NEW |