Chromium Code Reviews| 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/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
| 14 #include "base/synchronization/waitable_event.h" | 14 #include "base/synchronization/waitable_event.h" |
| 15 #include "media/base/bitstream_buffer.h" | 15 #include "media/base/bitstream_buffer.h" |
| 16 #include "media/base/video_frame.h" | 16 #include "media/base/video_frame.h" |
| 17 #include "media/base/video_util.h" | 17 #include "media/base/video_util.h" |
| 18 #include "media/filters/gpu_video_accelerator_factories.h" | 18 #include "media/filters/gpu_video_accelerator_factories.h" |
| 19 #include "media/filters/h264_parser.h" | |
| 19 #include "media/video/video_encode_accelerator.h" | 20 #include "media/video/video_encode_accelerator.h" |
| 20 #include "third_party/webrtc/system_wrappers/interface/tick_util.h" | 21 #include "third_party/webrtc/system_wrappers/interface/tick_util.h" |
| 21 | 22 |
| 22 #define NOTIFY_ERROR(x) \ | 23 #define NOTIFY_ERROR(x) \ |
| 23 do { \ | 24 do { \ |
| 24 DLOG(ERROR) << "calling NotifyError(): " << x; \ | 25 DLOG(ERROR) << "calling NotifyError(): " << x; \ |
| 25 NotifyError(x); \ | 26 NotifyError(x); \ |
| 26 } while (0) | 27 } while (0) |
| 27 | 28 |
| 28 namespace content { | 29 namespace content { |
| 29 | 30 |
| 31 namespace { | |
| 32 | |
| 33 void GetRTPFragmentationHeaderH264( | |
|
Pawel Osciak
2014/08/10 00:30:30
Please document.
hshi1
2014/08/12 01:06:55
Done.
| |
| 34 webrtc::RTPFragmentationHeader& header, uint8_t* data, uint32_t length) { | |
| 35 media::H264Parser parser; | |
| 36 parser.SetStream(data, length); | |
| 37 | |
| 38 std::vector<media::H264NALU> nalu_vector; | |
| 39 while (true) { | |
| 40 media::H264NALU nalu; | |
| 41 media::H264Parser::Result result; | |
| 42 result = parser.AdvanceToNextNALU(&nalu); | |
| 43 if (result == media::H264Parser::kOk) { | |
|
Pawel Osciak
2014/08/10 00:30:30
Nit: switch?
hshi1
2014/08/10 00:36:10
I thought about that but then a "break" in the swi
| |
| 44 nalu_vector.push_back(nalu); | |
| 45 } else if (result == media::H264Parser::kEOStream) { | |
| 46 break; | |
| 47 } else { | |
| 48 DLOG(ERROR) << "Unexpected H264 parser result"; | |
| 49 break; | |
|
Pawel Osciak
2014/08/10 00:30:29
I think we should handle errors? What happens if t
hshi1
2014/08/12 01:06:55
Should errors be expected? The stream is returned
Pawel Osciak
2014/08/12 11:06:38
Well, we check for this anyway, and I'd expect thi
hshi1
2014/08/12 18:08:22
Sounds reasonable. Note that this function is in t
| |
| 50 } | |
| 51 } | |
| 52 | |
| 53 header.VerifyAndAllocateFragmentationHeader(nalu_vector.size()); | |
| 54 for (size_t i = 0; i < nalu_vector.size(); ++i) { | |
| 55 header.fragmentationOffset[i] = nalu_vector[i].data - data; | |
| 56 header.fragmentationLength[i] = nalu_vector[i].size; | |
| 57 header.fragmentationPlType[i] = 0; | |
| 58 header.fragmentationTimeDiff[i] = 0; | |
| 59 } | |
| 60 } | |
| 61 | |
| 62 } // namespace | |
| 63 | |
| 30 // This private class of RTCVideoEncoder does the actual work of communicating | 64 // This private class of RTCVideoEncoder does the actual work of communicating |
| 31 // with a media::VideoEncodeAccelerator for handling video encoding. It can | 65 // with a media::VideoEncodeAccelerator for handling video encoding. It can |
| 32 // be created on any thread, but should subsequently be posted to (and Destroy() | 66 // be created on any thread, but should subsequently be posted to (and Destroy() |
| 33 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the | 67 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the |
| 34 // thread on which the instance was constructed. | 68 // thread on which the instance was constructed. |
| 35 // | 69 // |
| 36 // This class separates state related to the thread that RTCVideoEncoder | 70 // This class separates state related to the thread that RTCVideoEncoder |
| 37 // operates on (presently the libjingle worker thread) from the thread that | 71 // operates on (presently the libjingle worker thread) from the thread that |
| 38 // |gpu_factories_| provides for accelerator operations (presently the media | 72 // |gpu_factories_| provides for accelerator operations (presently the media |
| 39 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while | 73 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while |
| (...skipping 601 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 int32 bitstream_buffer_id, | 675 int32 bitstream_buffer_id, |
| 642 uint16 picture_id) { | 676 uint16 picture_id) { |
| 643 DCHECK(thread_checker_.CalledOnValidThread()); | 677 DCHECK(thread_checker_.CalledOnValidThread()); |
| 644 DVLOG(3) << "ReturnEncodedImage(): " | 678 DVLOG(3) << "ReturnEncodedImage(): " |
| 645 << "bitstream_buffer_id=" << bitstream_buffer_id | 679 << "bitstream_buffer_id=" << bitstream_buffer_id |
| 646 << ", picture_id=" << picture_id; | 680 << ", picture_id=" << picture_id; |
| 647 | 681 |
| 648 if (!encoded_image_callback_) | 682 if (!encoded_image_callback_) |
| 649 return; | 683 return; |
| 650 | 684 |
| 685 webrtc::RTPFragmentationHeader header; | |
| 686 memset(&header, 0, sizeof(header)); | |
| 687 switch (video_codec_type_) { | |
| 688 case webrtc::kVideoCodecVP8: | |
| 689 case webrtc::kVideoCodecGeneric: | |
|
Pawel Osciak
2014/08/10 00:30:30
Generic wasn't here before. And given that it's tr
hshi1
2014/08/10 00:36:10
We're keeping Generic (and the payload type "CAST1
Pawel Osciak
2014/08/10 01:14:34
Generic is treated as H264 in the format conversio
hshi1
2014/08/11 17:43:00
You're correct that Generic is treated differently
Pawel Osciak
2014/08/12 11:06:38
Ok, I'm fine with this, but please add a comment a
hshi1
2014/08/12 18:08:22
Done.
| |
| 690 header.VerifyAndAllocateFragmentationHeader(1); | |
| 691 header.fragmentationOffset[0] = 0; | |
| 692 header.fragmentationLength[0] = image->_length; | |
| 693 header.fragmentationPlType[0] = 0; | |
| 694 header.fragmentationTimeDiff[0] = 0; | |
| 695 break; | |
| 696 case webrtc::kVideoCodecH264: | |
| 697 GetRTPFragmentationHeaderH264(header, image->_buffer, image->_length); | |
| 698 break; | |
| 699 default: | |
| 700 NOTREACHED() << "Invalid video codec type"; | |
| 701 return; | |
| 702 } | |
| 703 | |
| 651 webrtc::CodecSpecificInfo info; | 704 webrtc::CodecSpecificInfo info; |
| 652 memset(&info, 0, sizeof(info)); | 705 memset(&info, 0, sizeof(info)); |
| 653 info.codecType = video_codec_type_; | 706 info.codecType = video_codec_type_; |
| 654 if (video_codec_type_ == webrtc::kVideoCodecVP8) { | 707 if (video_codec_type_ == webrtc::kVideoCodecVP8) { |
| 655 info.codecSpecific.VP8.pictureId = picture_id; | 708 info.codecSpecific.VP8.pictureId = picture_id; |
| 656 info.codecSpecific.VP8.tl0PicIdx = -1; | 709 info.codecSpecific.VP8.tl0PicIdx = -1; |
| 657 info.codecSpecific.VP8.keyIdx = -1; | 710 info.codecSpecific.VP8.keyIdx = -1; |
| 658 } | 711 } |
| 659 | 712 |
| 660 // Generate a header describing a single fragment. | |
| 661 webrtc::RTPFragmentationHeader header; | |
| 662 memset(&header, 0, sizeof(header)); | |
| 663 header.VerifyAndAllocateFragmentationHeader(1); | |
| 664 header.fragmentationOffset[0] = 0; | |
| 665 header.fragmentationLength[0] = image->_length; | |
| 666 header.fragmentationPlType[0] = 0; | |
| 667 header.fragmentationTimeDiff[0] = 0; | |
| 668 | |
| 669 int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header); | 713 int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header); |
| 670 if (retval < 0) { | 714 if (retval < 0) { |
| 671 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned " | 715 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned " |
| 672 << retval; | 716 << retval; |
| 673 } | 717 } |
| 674 | 718 |
| 675 // The call through webrtc::EncodedImageCallback is synchronous, so we can | 719 // The call through webrtc::EncodedImageCallback is synchronous, so we can |
| 676 // immediately recycle the output buffer back to the Impl. | 720 // immediately recycle the output buffer back to the Impl. |
| 677 gpu_factories_->GetTaskRunner()->PostTask( | 721 gpu_factories_->GetTaskRunner()->PostTask( |
| 678 FROM_HERE, | 722 FROM_HERE, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 695 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess", | 739 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess", |
| 696 init_retval == WEBRTC_VIDEO_CODEC_OK); | 740 init_retval == WEBRTC_VIDEO_CODEC_OK); |
| 697 if (init_retval == WEBRTC_VIDEO_CODEC_OK) { | 741 if (init_retval == WEBRTC_VIDEO_CODEC_OK) { |
| 698 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile", | 742 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile", |
| 699 video_codec_profile_, | 743 video_codec_profile_, |
| 700 media::VIDEO_CODEC_PROFILE_MAX + 1); | 744 media::VIDEO_CODEC_PROFILE_MAX + 1); |
| 701 } | 745 } |
| 702 } | 746 } |
| 703 | 747 |
| 704 } // namespace content | 748 } // namespace content |
| OLD | NEW |