Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(543)

Side by Side Diff: content/renderer/media/gpu/rtc_video_encoder.cc

Issue 2499973002: RTCVideoEncoder: Report H264 profile information to WebRTC (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/gpu/rtc_video_encoder.h" 5 #include "content/renderer/media/gpu/rtc_video_encoder.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 14 matching lines...) Expand all
25 #include "media/filters/h264_parser.h" 25 #include "media/filters/h264_parser.h"
26 #include "media/renderers/gpu_video_accelerator_factories.h" 26 #include "media/renderers/gpu_video_accelerator_factories.h"
27 #include "media/video/video_encode_accelerator.h" 27 #include "media/video/video_encode_accelerator.h"
28 #include "third_party/libyuv/include/libyuv.h" 28 #include "third_party/libyuv/include/libyuv.h"
29 #include "third_party/webrtc/base/timeutils.h" 29 #include "third_party/webrtc/base/timeutils.h"
30 30
31 namespace content { 31 namespace content {
32 32
33 namespace { 33 namespace {
34 34
35 // Translate from webrtc::VideoCodecType and webrtc::VideoCodec to
36 // media::VideoCodecProfile.
37 media::VideoCodecProfile WebRTCVideoCodecToVideoCodecProfile(
38 webrtc::VideoCodecType type,
39 const webrtc::VideoCodec* codec_settings) {
40 DCHECK_EQ(type, codec_settings->codecType);
41 switch (type) {
42 case webrtc::kVideoCodecVP8:
43 return media::VP8PROFILE_ANY;
44 case webrtc::kVideoCodecH264:
45 // TODO(magjed): WebRTC is only using Baseline profile for now. Update
46 // once http://crbug/webrtc/6337 is fixed.
47 return media::H264PROFILE_BASELINE;
48 default:
49 NOTREACHED() << "Unrecognized video codec type";
50 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
51 }
52 }
53
54 // Populates struct webrtc::RTPFragmentationHeader for H264 codec. 35 // Populates struct webrtc::RTPFragmentationHeader for H264 codec.
55 // Each entry specifies the offset and length (excluding start code) of a NALU. 36 // Each entry specifies the offset and length (excluding start code) of a NALU.
56 // Returns true if successful. 37 // Returns true if successful.
57 bool GetRTPFragmentationHeaderH264(webrtc::RTPFragmentationHeader* header, 38 bool GetRTPFragmentationHeaderH264(webrtc::RTPFragmentationHeader* header,
58 const uint8_t* data, uint32_t length) { 39 const uint8_t* data, uint32_t length) {
59 media::H264Parser parser; 40 media::H264Parser parser;
60 parser.SetStream(data, length); 41 parser.SetStream(data, length);
61 42
62 std::vector<media::H264NALU> nalu_vector; 43 std::vector<media::H264NALU> nalu_vector;
63 while (true) { 44 while (true) {
(...skipping 27 matching lines...) Expand all
91 // called on) a single thread. 72 // called on) a single thread.
92 // 73 //
93 // This class separates state related to the thread that RTCVideoEncoder 74 // This class separates state related to the thread that RTCVideoEncoder
94 // operates on from the thread that |gpu_factories_| provides for accelerator 75 // operates on from the thread that |gpu_factories_| provides for accelerator
95 // operations (presently the media thread). 76 // operations (presently the media thread).
96 class RTCVideoEncoder::Impl 77 class RTCVideoEncoder::Impl
97 : public media::VideoEncodeAccelerator::Client, 78 : public media::VideoEncodeAccelerator::Client,
98 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> { 79 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
99 public: 80 public:
100 Impl(media::GpuVideoAcceleratorFactories* gpu_factories, 81 Impl(media::GpuVideoAcceleratorFactories* gpu_factories,
101 webrtc::VideoCodecType video_codec_type); 82 const media::VideoCodecProfile& profile);
102 83
103 // Create the VEA and call Initialize() on it. Called once per instantiation, 84 // Create the VEA and call Initialize() on it. Called once per instantiation,
104 // and then the instance is bound forevermore to whichever thread made the 85 // and then the instance is bound forevermore to whichever thread made the
105 // call. 86 // call.
106 // RTCVideoEncoder expects to be able to call this function synchronously from 87 // RTCVideoEncoder expects to be able to call this function synchronously from
107 // its own thread, hence the |async_waiter| and |async_retval| arguments. 88 // its own thread, hence the |async_waiter| and |async_retval| arguments.
108 void CreateAndInitializeVEA(const gfx::Size& input_visible_size, 89 void CreateAndInitializeVEA(const gfx::Size& input_visible_size,
109 uint32_t bitrate, 90 uint32_t bitrate,
110 media::VideoCodecProfile profile, 91 media::VideoCodecProfile profile,
111 base::WaitableEvent* async_waiter, 92 base::WaitableEvent* async_waiter,
(...skipping 18 matching lines...) Expand all
130 int32_t* async_retval, 111 int32_t* async_retval,
131 webrtc::EncodedImageCallback* callback); 112 webrtc::EncodedImageCallback* callback);
132 113
133 // Destroy this Impl's encoder. The destructor is not explicitly called, as 114 // Destroy this Impl's encoder. The destructor is not explicitly called, as
134 // Impl is a base::RefCountedThreadSafe. 115 // Impl is a base::RefCountedThreadSafe.
135 void Destroy(base::WaitableEvent* async_waiter); 116 void Destroy(base::WaitableEvent* async_waiter);
136 117
137 // Return the status of Impl. One of WEBRTC_VIDEO_CODEC_XXX value. 118 // Return the status of Impl. One of WEBRTC_VIDEO_CODEC_XXX value.
138 int32_t GetStatus() const; 119 int32_t GetStatus() const;
139 120
140 webrtc::VideoCodecType video_codec_type() { return video_codec_type_; }
141
142 // media::VideoEncodeAccelerator::Client implementation. 121 // media::VideoEncodeAccelerator::Client implementation.
143 void RequireBitstreamBuffers(unsigned int input_count, 122 void RequireBitstreamBuffers(unsigned int input_count,
144 const gfx::Size& input_coded_size, 123 const gfx::Size& input_coded_size,
145 size_t output_buffer_size) override; 124 size_t output_buffer_size) override;
146 void BitstreamBufferReady(int32_t bitstream_buffer_id, 125 void BitstreamBufferReady(int32_t bitstream_buffer_id,
147 size_t payload_size, 126 size_t payload_size,
148 bool key_frame, 127 bool key_frame,
149 base::TimeDelta timestamp) override; 128 base::TimeDelta timestamp) override;
150 void NotifyError(media::VideoEncodeAccelerator::Error error) override; 129 void NotifyError(media::VideoEncodeAccelerator::Error error) override;
151 130
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 // encoder. 210 // encoder.
232 int output_buffers_free_count_; 211 int output_buffers_free_count_;
233 212
234 // 15 bits running index of the VP8 frames. See VP8 RTP spec for details. 213 // 15 bits running index of the VP8 frames. See VP8 RTP spec for details.
235 uint16_t picture_id_; 214 uint16_t picture_id_;
236 215
237 // webrtc::VideoEncoder encode complete callback. 216 // webrtc::VideoEncoder encode complete callback.
238 webrtc::EncodedImageCallback* encoded_image_callback_; 217 webrtc::EncodedImageCallback* encoded_image_callback_;
239 218
240 // The video codec type, as reported to WebRTC. 219 // The video codec type, as reported to WebRTC.
241 const webrtc::VideoCodecType video_codec_type_; 220 const media::VideoCodecProfile profile_;
242 221
243 // Protect |status_|. |status_| is read or written on |gpu_task_runner_| in 222 // Protect |status_|. |status_| is read or written on |gpu_task_runner_| in
244 // Impl. It can be read in RTCVideoEncoder on other threads. 223 // Impl. It can be read in RTCVideoEncoder on other threads.
245 mutable base::Lock status_lock_; 224 mutable base::Lock status_lock_;
246 225
247 // We cannot immediately return error conditions to the WebRTC user of this 226 // We cannot immediately return error conditions to the WebRTC user of this
248 // class, as there is no error callback in the webrtc::VideoEncoder interface. 227 // class, as there is no error callback in the webrtc::VideoEncoder interface.
249 // Instead, we cache an error status here and return it the next time an 228 // Instead, we cache an error status here and return it the next time an
250 // interface entry point is called. This is protected by |status_lock_|. 229 // interface entry point is called. This is protected by |status_lock_|.
251 int32_t status_; 230 int32_t status_;
252 231
253 DISALLOW_COPY_AND_ASSIGN(Impl); 232 DISALLOW_COPY_AND_ASSIGN(Impl);
254 }; 233 };
255 234
256 RTCVideoEncoder::Impl::Impl(media::GpuVideoAcceleratorFactories* gpu_factories, 235 RTCVideoEncoder::Impl::Impl(
257 webrtc::VideoCodecType video_codec_type) 236 media::GpuVideoAcceleratorFactories* gpu_factories,
237 const media::VideoCodecProfile& profile)
258 : gpu_factories_(gpu_factories), 238 : gpu_factories_(gpu_factories),
259 async_waiter_(NULL), 239 async_waiter_(NULL),
260 async_retval_(NULL), 240 async_retval_(NULL),
261 input_next_frame_(NULL), 241 input_next_frame_(NULL),
262 input_next_frame_keyframe_(false), 242 input_next_frame_keyframe_(false),
263 output_buffers_free_count_(0), 243 output_buffers_free_count_(0),
264 encoded_image_callback_(nullptr), 244 encoded_image_callback_(nullptr),
265 video_codec_type_(video_codec_type), 245 profile_(profile),
266 status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) { 246 status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) {
267 thread_checker_.DetachFromThread(); 247 thread_checker_.DetachFromThread();
268 // Picture ID should start on a random number. 248 // Picture ID should start on a random number.
269 picture_id_ = static_cast<uint16_t>(base::RandInt(0, 0x7FFF)); 249 picture_id_ = static_cast<uint16_t>(base::RandInt(0, 0x7FFF));
270 } 250 }
271 251
272 void RTCVideoEncoder::Impl::CreateAndInitializeVEA( 252 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
273 const gfx::Size& input_visible_size, 253 const gfx::Size& input_visible_size,
274 uint32_t bitrate, 254 uint32_t bitrate,
275 media::VideoCodecProfile profile, 255 media::VideoCodecProfile profile,
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 int32_t bitstream_buffer_id, 654 int32_t bitstream_buffer_id,
675 uint16_t picture_id) { 655 uint16_t picture_id) {
676 DCHECK(thread_checker_.CalledOnValidThread()); 656 DCHECK(thread_checker_.CalledOnValidThread());
677 DVLOG(3) << "ReturnEncodedImage(): " 657 DVLOG(3) << "ReturnEncodedImage(): "
678 << "bitstream_buffer_id=" << bitstream_buffer_id 658 << "bitstream_buffer_id=" << bitstream_buffer_id
679 << ", picture_id=" << picture_id; 659 << ", picture_id=" << picture_id;
680 660
681 if (!encoded_image_callback_) 661 if (!encoded_image_callback_)
682 return; 662 return;
683 663
664 webrtc::CodecSpecificInfo info;
684 webrtc::RTPFragmentationHeader header; 665 webrtc::RTPFragmentationHeader header;
666 memset(&info, 0, sizeof(info));
685 memset(&header, 0, sizeof(header)); 667 memset(&header, 0, sizeof(header));
686 switch (video_codec_type_) { 668 if (profile_ >= media::VP8PROFILE_MIN && profile_ <= media::VP8PROFILE_MAX) {
Pawel Osciak 2016/11/17 07:30:05 I think we can store just media::VideoCodec in Imp
magjed_chromium 2016/11/17 13:08:03 Done. I kept it as a webrtc::VideoCodecType in Imp
687 case webrtc::kVideoCodecVP8: 669 // Generate a header describing a single fragment.
688 // Generate a header describing a single fragment. 670 header.VerifyAndAllocateFragmentationHeader(1);
689 header.VerifyAndAllocateFragmentationHeader(1); 671 header.fragmentationOffset[0] = 0;
690 header.fragmentationOffset[0] = 0; 672 header.fragmentationLength[0] = image._length;
691 header.fragmentationLength[0] = image._length; 673 header.fragmentationPlType[0] = 0;
692 header.fragmentationPlType[0] = 0; 674 header.fragmentationTimeDiff[0] = 0;
693 header.fragmentationTimeDiff[0] = 0;
694 break;
695 case webrtc::kVideoCodecH264:
696 if (!GetRTPFragmentationHeaderH264(&header, image._buffer,
697 image._length)) {
698 DLOG(ERROR) << "Failed to get RTP fragmentation header for H264";
699 NotifyError(
700 (media::VideoEncodeAccelerator::Error)WEBRTC_VIDEO_CODEC_ERROR);
701 return;
702 }
703 break;
704 default:
705 NOTREACHED() << "Invalid video codec type";
706 return;
707 }
708 675
709 webrtc::CodecSpecificInfo info; 676 info.codecType = webrtc::kVideoCodecVP8;
710 memset(&info, 0, sizeof(info));
711 info.codecType = video_codec_type_;
712 if (video_codec_type_ == webrtc::kVideoCodecVP8) {
713 info.codecSpecific.VP8.pictureId = picture_id; 677 info.codecSpecific.VP8.pictureId = picture_id;
714 info.codecSpecific.VP8.tl0PicIdx = -1; 678 info.codecSpecific.VP8.tl0PicIdx = -1;
715 info.codecSpecific.VP8.keyIdx = -1; 679 info.codecSpecific.VP8.keyIdx = -1;
680 } else if (profile_ >= media::H264PROFILE_MIN &&
681 profile_ <= media::H264PROFILE_MAX) {
682 info.codecType = webrtc::kVideoCodecH264;
683 if (!GetRTPFragmentationHeaderH264(&header, image._buffer, image._length)) {
684 DLOG(ERROR) << "Failed to get RTP fragmentation header for H264";
685 NotifyError(
686 (media::VideoEncodeAccelerator::Error)WEBRTC_VIDEO_CODEC_ERROR);
687 return;
688 }
689 } else {
690 NOTREACHED() << "Invalid video codec type";
691 return;
716 } 692 }
717 693
718 const auto result = 694 const auto result =
719 encoded_image_callback_->OnEncodedImage(image, &info, &header); 695 encoded_image_callback_->OnEncodedImage(image, &info, &header);
720 if (result.error != webrtc::EncodedImageCallback::Result::OK) { 696 if (result.error != webrtc::EncodedImageCallback::Result::OK) {
721 DVLOG(2) 697 DVLOG(2)
722 << "ReturnEncodedImage(): webrtc::EncodedImageCallback::Result.error = " 698 << "ReturnEncodedImage(): webrtc::EncodedImageCallback::Result.error = "
723 << result.error; 699 << result.error;
724 } 700 }
725 701
726 UseOutputBitstreamBufferId(bitstream_buffer_id); 702 UseOutputBitstreamBufferId(bitstream_buffer_id);
727 } 703 }
728 704
729 RTCVideoEncoder::RTCVideoEncoder( 705 RTCVideoEncoder::RTCVideoEncoder(
730 webrtc::VideoCodecType type, 706 const media::VideoCodecProfile& profile,
731 media::GpuVideoAcceleratorFactories* gpu_factories) 707 media::GpuVideoAcceleratorFactories* gpu_factories)
732 : video_codec_type_(type), 708 : profile_(profile),
733 gpu_factories_(gpu_factories), 709 gpu_factories_(gpu_factories),
734 gpu_task_runner_(gpu_factories->GetTaskRunner()) { 710 gpu_task_runner_(gpu_factories->GetTaskRunner()) {
735 DVLOG(1) << "RTCVideoEncoder(): codec type=" << type; 711 DVLOG(1) << "RTCVideoEncoder(): profile=" << GetProfileName(profile);
736 } 712 }
737 713
738 RTCVideoEncoder::~RTCVideoEncoder() { 714 RTCVideoEncoder::~RTCVideoEncoder() {
739 DVLOG(3) << "~RTCVideoEncoder"; 715 DVLOG(3) << "~RTCVideoEncoder";
740 Release(); 716 Release();
741 DCHECK(!impl_.get()); 717 DCHECK(!impl_.get());
742 } 718 }
743 719
744 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, 720 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
745 int32_t number_of_cores, 721 int32_t number_of_cores,
746 size_t max_payload_size) { 722 size_t max_payload_size) {
747 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType 723 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
748 << ", width=" << codec_settings->width 724 << ", width=" << codec_settings->width
749 << ", height=" << codec_settings->height 725 << ", height=" << codec_settings->height
750 << ", startBitrate=" << codec_settings->startBitrate; 726 << ", startBitrate=" << codec_settings->startBitrate;
751 if (impl_) { 727 if (impl_) {
752 DVLOG(1) << "Release because of reinitialization"; 728 DVLOG(1) << "Release because of reinitialization";
753 Release(); 729 Release();
754 } 730 }
755 731
756 impl_ = new Impl(gpu_factories_, video_codec_type_); 732 impl_ = new Impl(gpu_factories_, profile_);
757 const media::VideoCodecProfile profile = WebRTCVideoCodecToVideoCodecProfile(
758 impl_->video_codec_type(), codec_settings);
759 733
760 base::WaitableEvent initialization_waiter( 734 base::WaitableEvent initialization_waiter(
761 base::WaitableEvent::ResetPolicy::MANUAL, 735 base::WaitableEvent::ResetPolicy::MANUAL,
762 base::WaitableEvent::InitialState::NOT_SIGNALED); 736 base::WaitableEvent::InitialState::NOT_SIGNALED);
763 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; 737 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
764 gpu_task_runner_->PostTask( 738 gpu_task_runner_->PostTask(
765 FROM_HERE, 739 FROM_HERE,
766 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, 740 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
767 impl_, 741 impl_,
768 gfx::Size(codec_settings->width, codec_settings->height), 742 gfx::Size(codec_settings->width, codec_settings->height),
769 codec_settings->startBitrate, 743 codec_settings->startBitrate,
770 profile, 744 profile_,
771 &initialization_waiter, 745 &initialization_waiter,
772 &initialization_retval)); 746 &initialization_retval));
773 747
774 // webrtc::VideoEncoder expects this call to be synchronous. 748 // webrtc::VideoEncoder expects this call to be synchronous.
775 initialization_waiter.Wait(); 749 initialization_waiter.Wait();
776 RecordInitEncodeUMA(initialization_retval, profile); 750 RecordInitEncodeUMA(initialization_retval, profile_);
777 return initialization_retval; 751 return initialization_retval;
778 } 752 }
779 753
780 int32_t RTCVideoEncoder::Encode( 754 int32_t RTCVideoEncoder::Encode(
781 const webrtc::VideoFrame& input_image, 755 const webrtc::VideoFrame& input_image,
782 const webrtc::CodecSpecificInfo* codec_specific_info, 756 const webrtc::CodecSpecificInfo* codec_specific_info,
783 const std::vector<webrtc::FrameType>* frame_types) { 757 const std::vector<webrtc::FrameType>* frame_types) {
784 DVLOG(3) << "Encode()"; 758 DVLOG(3) << "Encode()";
785 if (!impl_.get()) { 759 if (!impl_.get()) {
786 DVLOG(3) << "Encoder is not initialized"; 760 DVLOG(3) << "Encoder is not initialized";
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
880 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess", 854 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess",
881 init_retval == WEBRTC_VIDEO_CODEC_OK); 855 init_retval == WEBRTC_VIDEO_CODEC_OK);
882 if (init_retval == WEBRTC_VIDEO_CODEC_OK) { 856 if (init_retval == WEBRTC_VIDEO_CODEC_OK) {
883 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile", 857 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile",
884 profile, 858 profile,
885 media::VIDEO_CODEC_PROFILE_MAX + 1); 859 media::VIDEO_CODEC_PROFILE_MAX + 1);
886 } 860 }
887 } 861 }
888 862
889 } // namespace content 863 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698