| 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/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
| 13 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
| 14 #include "base/synchronization/waitable_event.h" | 14 #include "base/synchronization/waitable_event.h" |
| 15 #include "base/thread_task_runner_handle.h" | 15 #include "base/thread_task_runner_handle.h" |
| 16 #include "media/base/bind_to_current_loop.h" |
| 16 #include "media/base/bitstream_buffer.h" | 17 #include "media/base/bitstream_buffer.h" |
| 17 #include "media/base/video_frame.h" | 18 #include "media/base/video_frame.h" |
| 18 #include "media/base/video_util.h" | 19 #include "media/base/video_util.h" |
| 19 #include "media/filters/h264_parser.h" | 20 #include "media/filters/h264_parser.h" |
| 20 #include "media/renderers/gpu_video_accelerator_factories.h" | 21 #include "media/renderers/gpu_video_accelerator_factories.h" |
| 21 #include "media/video/video_encode_accelerator.h" | 22 #include "media/video/video_encode_accelerator.h" |
| 22 #include "third_party/libyuv/include/libyuv.h" | 23 #include "third_party/libyuv/include/libyuv.h" |
| 23 #include "third_party/webrtc/system_wrappers/interface/tick_util.h" | 24 #include "third_party/webrtc/system_wrappers/interface/tick_util.h" |
| 24 | 25 |
| 25 #define NOTIFY_ERROR(x) \ | 26 #define NOTIFY_ERROR(x) \ |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | 416 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 416 return; | 417 return; |
| 417 } | 418 } |
| 418 output_buffers_free_count_--; | 419 output_buffers_free_count_--; |
| 419 | 420 |
| 420 // Use webrtc timestamps to ensure correct RTP sender behavior. | 421 // Use webrtc timestamps to ensure correct RTP sender behavior. |
| 421 // TODO(hshi): obtain timestamp from the capturer, see crbug.com/350106. | 422 // TODO(hshi): obtain timestamp from the capturer, see crbug.com/350106. |
| 422 const int64 capture_time_us = webrtc::TickTime::MicrosecondTimestamp(); | 423 const int64 capture_time_us = webrtc::TickTime::MicrosecondTimestamp(); |
| 423 | 424 |
| 424 // Derive the capture time (in ms) and RTP timestamp (in 90KHz ticks). | 425 // Derive the capture time (in ms) and RTP timestamp (in 90KHz ticks). |
| 425 int64 capture_time_ms = capture_time_us / 1000; | 426 const int64 capture_time_ms = capture_time_us / 1000; |
| 426 uint32_t rtp_timestamp = static_cast<uint32_t>(capture_time_us * 90 / 1000); | 427 const uint32_t rtp_timestamp = |
| 428 static_cast<uint32_t>(capture_time_us * 90 / 1000); |
| 427 | 429 |
| 428 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage( | 430 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage( |
| 429 reinterpret_cast<uint8_t*>(output_buffer->memory()), | 431 reinterpret_cast<uint8_t*>(output_buffer->memory()), |
| 430 payload_size, | 432 payload_size, |
| 431 output_buffer->mapped_size())); | 433 output_buffer->mapped_size())); |
| 432 image->_encodedWidth = input_visible_size_.width(); | 434 image->_encodedWidth = input_visible_size_.width(); |
| 433 image->_encodedHeight = input_visible_size_.height(); | 435 image->_encodedHeight = input_visible_size_.height(); |
| 434 image->_timeStamp = rtp_timestamp; | 436 image->_timeStamp = rtp_timestamp; |
| 435 image->capture_time_ms_ = capture_time_ms; | 437 image->capture_time_ms_ = capture_time_ms; |
| 436 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame); | 438 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 DVLOG(3) << "Impl::EncodeOneFrame()"; | 476 DVLOG(3) << "Impl::EncodeOneFrame()"; |
| 475 DCHECK(thread_checker_.CalledOnValidThread()); | 477 DCHECK(thread_checker_.CalledOnValidThread()); |
| 476 DCHECK(input_next_frame_); | 478 DCHECK(input_next_frame_); |
| 477 DCHECK(!input_buffers_free_.empty()); | 479 DCHECK(!input_buffers_free_.empty()); |
| 478 | 480 |
| 479 // EncodeOneFrame() may re-enter EncodeFrameFinished() if VEA::Encode() fails, | 481 // EncodeOneFrame() may re-enter EncodeFrameFinished() if VEA::Encode() fails, |
| 480 // we receive a VEA::NotifyError(), and the media::VideoFrame we pass to | 482 // we receive a VEA::NotifyError(), and the media::VideoFrame we pass to |
| 481 // Encode() gets destroyed early. Handle this by resetting our | 483 // Encode() gets destroyed early. Handle this by resetting our |
| 482 // input_next_frame_* state before we hand off the VideoFrame to the VEA. | 484 // input_next_frame_* state before we hand off the VideoFrame to the VEA. |
| 483 const webrtc::VideoFrame* next_frame = input_next_frame_; | 485 const webrtc::VideoFrame* next_frame = input_next_frame_; |
| 484 bool next_frame_keyframe = input_next_frame_keyframe_; | 486 const bool next_frame_keyframe = input_next_frame_keyframe_; |
| 485 input_next_frame_ = NULL; | 487 input_next_frame_ = NULL; |
| 486 input_next_frame_keyframe_ = false; | 488 input_next_frame_keyframe_ = false; |
| 487 | 489 |
| 488 if (!video_encoder_) { | 490 if (!video_encoder_) { |
| 489 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR); | 491 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR); |
| 490 return; | 492 return; |
| 491 } | 493 } |
| 492 | 494 |
| 493 const int index = input_buffers_free_.back(); | 495 const int index = input_buffers_free_.back(); |
| 494 base::SharedMemory* input_buffer = input_buffers_[index]; | 496 scoped_refptr<media::VideoFrame> frame; |
| 495 scoped_refptr<media::VideoFrame> frame = | 497 if (next_frame->native_handle()) { |
| 496 media::VideoFrame::WrapExternalSharedMemory( | 498 frame = static_cast<media::VideoFrame*>(next_frame->native_handle()); |
| 497 media::VideoFrame::I420, | 499 } else { |
| 498 input_frame_coded_size_, | 500 base::SharedMemory* input_buffer = input_buffers_[index]; |
| 499 gfx::Rect(input_visible_size_), | 501 frame = media::VideoFrame::WrapExternalSharedMemory( |
| 500 input_visible_size_, | 502 media::VideoFrame::I420, |
| 501 reinterpret_cast<uint8*>(input_buffer->memory()), | 503 input_frame_coded_size_, |
| 502 input_buffer->mapped_size(), | 504 gfx::Rect(input_visible_size_), |
| 503 input_buffer->handle(), | 505 input_visible_size_, |
| 504 0, | 506 reinterpret_cast<uint8*>(input_buffer->memory()), |
| 505 base::TimeDelta()); | 507 input_buffer->mapped_size(), |
| 506 frame->AddDestructionObserver( | 508 input_buffer->handle(), |
| 507 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index)); | 509 0, |
| 508 if (!frame.get()) { | 510 base::TimeDelta()); |
| 509 DLOG(ERROR) << "Impl::EncodeOneFrame(): failed to create frame"; | 511 if (!frame.get()) { |
| 510 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | 512 DLOG(ERROR) << "Impl::EncodeOneFrame(): failed to create frame"; |
| 511 return; | 513 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 514 return; |
| 515 } |
| 516 // Do a strided copy of the input frame to match the input requirements for |
| 517 // the encoder. |
| 518 // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312 |
| 519 if (libyuv::I420Copy(next_frame->buffer(webrtc::kYPlane), |
| 520 next_frame->stride(webrtc::kYPlane), |
| 521 next_frame->buffer(webrtc::kUPlane), |
| 522 next_frame->stride(webrtc::kUPlane), |
| 523 next_frame->buffer(webrtc::kVPlane), |
| 524 next_frame->stride(webrtc::kVPlane), |
| 525 frame->data(media::VideoFrame::kYPlane), |
| 526 frame->stride(media::VideoFrame::kYPlane), |
| 527 frame->data(media::VideoFrame::kUPlane), |
| 528 frame->stride(media::VideoFrame::kUPlane), |
| 529 frame->data(media::VideoFrame::kVPlane), |
| 530 frame->stride(media::VideoFrame::kVPlane), |
| 531 next_frame->width(), next_frame->height())) { |
| 532 DLOG(ERROR) << "Failed to copy buffer"; |
| 533 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 534 return; |
| 535 } |
| 512 } | 536 } |
| 513 | 537 frame->AddDestructionObserver(media::BindToCurrentLoop( |
| 514 // Do a strided copy of the input frame to match the input requirements for | 538 base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index))); |
| 515 // the encoder. | |
| 516 // TODO(sheu): support zero-copy from WebRTC. http://crbug.com/269312 | |
| 517 if (libyuv::I420Copy(next_frame->buffer(webrtc::kYPlane), | |
| 518 next_frame->stride(webrtc::kYPlane), | |
| 519 next_frame->buffer(webrtc::kUPlane), | |
| 520 next_frame->stride(webrtc::kUPlane), | |
| 521 next_frame->buffer(webrtc::kVPlane), | |
| 522 next_frame->stride(webrtc::kVPlane), | |
| 523 frame->data(media::VideoFrame::kYPlane), | |
| 524 frame->stride(media::VideoFrame::kYPlane), | |
| 525 frame->data(media::VideoFrame::kUPlane), | |
| 526 frame->stride(media::VideoFrame::kUPlane), | |
| 527 frame->data(media::VideoFrame::kVPlane), | |
| 528 frame->stride(media::VideoFrame::kVPlane), | |
| 529 next_frame->width(), | |
| 530 next_frame->height())) { | |
| 531 DLOG(ERROR) << "Failed to copy buffer"; | |
| 532 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | |
| 533 return; | |
| 534 } | |
| 535 | |
| 536 video_encoder_->Encode(frame, next_frame_keyframe); | 539 video_encoder_->Encode(frame, next_frame_keyframe); |
| 537 input_buffers_free_.pop_back(); | 540 input_buffers_free_.pop_back(); |
| 538 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); | 541 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); |
| 539 } | 542 } |
| 540 | 543 |
| 541 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) { | 544 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) { |
| 542 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index; | 545 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index; |
| 543 DCHECK(thread_checker_.CalledOnValidThread()); | 546 DCHECK(thread_checker_.CalledOnValidThread()); |
| 544 DCHECK_GE(index, 0); | 547 DCHECK_GE(index, 0); |
| 545 DCHECK_LT(index, static_cast<int>(input_buffers_.size())); | 548 DCHECK_LT(index, static_cast<int>(input_buffers_.size())); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 594 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, | 597 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, |
| 595 int32_t number_of_cores, | 598 int32_t number_of_cores, |
| 596 size_t max_payload_size) { | 599 size_t max_payload_size) { |
| 597 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType | 600 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType |
| 598 << ", width=" << codec_settings->width | 601 << ", width=" << codec_settings->width |
| 599 << ", height=" << codec_settings->height | 602 << ", height=" << codec_settings->height |
| 600 << ", startBitrate=" << codec_settings->startBitrate; | 603 << ", startBitrate=" << codec_settings->startBitrate; |
| 601 DCHECK(thread_checker_.CalledOnValidThread()); | 604 DCHECK(thread_checker_.CalledOnValidThread()); |
| 602 DCHECK(!impl_.get()); | 605 DCHECK(!impl_.get()); |
| 603 | 606 |
| 604 media::VideoCodecProfile profile = WebRTCVideoCodecToVideoCodecProfile( | 607 const media::VideoCodecProfile profile = |
| 605 video_codec_type_, codec_settings); | 608 WebRTCVideoCodecToVideoCodecProfile(video_codec_type_, codec_settings); |
| 606 | 609 |
| 607 weak_factory_.InvalidateWeakPtrs(); | 610 weak_factory_.InvalidateWeakPtrs(); |
| 608 impl_ = new Impl(weak_factory_.GetWeakPtr(), gpu_factories_); | 611 impl_ = new Impl(weak_factory_.GetWeakPtr(), gpu_factories_); |
| 609 base::WaitableEvent initialization_waiter(true, false); | 612 base::WaitableEvent initialization_waiter(true, false); |
| 610 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 613 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 611 gpu_factories_->GetTaskRunner()->PostTask( | 614 gpu_factories_->GetTaskRunner()->PostTask( |
| 612 FROM_HERE, | 615 FROM_HERE, |
| 613 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, | 616 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, |
| 614 impl_, | 617 impl_, |
| 615 gfx::Size(codec_settings->width, codec_settings->height), | 618 gfx::Size(codec_settings->width, codec_settings->height), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 627 int32_t RTCVideoEncoder::Encode( | 630 int32_t RTCVideoEncoder::Encode( |
| 628 const webrtc::VideoFrame& input_image, | 631 const webrtc::VideoFrame& input_image, |
| 629 const webrtc::CodecSpecificInfo* codec_specific_info, | 632 const webrtc::CodecSpecificInfo* codec_specific_info, |
| 630 const std::vector<webrtc::VideoFrameType>* frame_types) { | 633 const std::vector<webrtc::VideoFrameType>* frame_types) { |
| 631 DVLOG(3) << "Encode()"; | 634 DVLOG(3) << "Encode()"; |
| 632 if (!impl_.get()) { | 635 if (!impl_.get()) { |
| 633 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_; | 636 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_; |
| 634 return impl_status_; | 637 return impl_status_; |
| 635 } | 638 } |
| 636 | 639 |
| 637 bool want_key_frame = frame_types && frame_types->size() && | 640 const bool want_key_frame = frame_types && frame_types->size() && |
| 638 frame_types->front() == webrtc::kKeyFrame; | 641 frame_types->front() == webrtc::kKeyFrame; |
| 639 base::WaitableEvent encode_waiter(true, false); | 642 base::WaitableEvent encode_waiter(true, false); |
| 640 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 643 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 641 gpu_factories_->GetTaskRunner()->PostTask( | 644 gpu_factories_->GetTaskRunner()->PostTask( |
| 642 FROM_HERE, | 645 FROM_HERE, |
| 643 base::Bind(&RTCVideoEncoder::Impl::Enqueue, | 646 base::Bind(&RTCVideoEncoder::Impl::Enqueue, |
| 644 impl_, | 647 impl_, |
| 645 &input_image, | 648 &input_image, |
| 646 want_key_frame, | 649 want_key_frame, |
| 647 &encode_waiter, | 650 &encode_waiter, |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess", | 782 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess", |
| 780 init_retval == WEBRTC_VIDEO_CODEC_OK); | 783 init_retval == WEBRTC_VIDEO_CODEC_OK); |
| 781 if (init_retval == WEBRTC_VIDEO_CODEC_OK) { | 784 if (init_retval == WEBRTC_VIDEO_CODEC_OK) { |
| 782 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile", | 785 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile", |
| 783 profile, | 786 profile, |
| 784 media::VIDEO_CODEC_PROFILE_MAX + 1); | 787 media::VIDEO_CODEC_PROFILE_MAX + 1); |
| 785 } | 788 } |
| 786 } | 789 } |
| 787 | 790 |
| 788 } // namespace content | 791 } // namespace content |
| OLD | NEW |