OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/pepper/video_encoder_shim.h" | 5 #include "content/renderer/pepper/video_encoder_shim.h" |
6 | 6 |
7 #include <inttypes.h> | 7 #include <inttypes.h> |
8 | 8 |
9 #include <deque> | 9 #include <deque> |
10 | 10 |
(...skipping 12 matching lines...) Expand all Loading... | |
23 | 23 |
24 namespace content { | 24 namespace content { |
25 | 25 |
26 // TODO(llandwerlin): Libvpx doesn't seem to have a maximum frame size | 26 // TODO(llandwerlin): Libvpx doesn't seem to have a maximum frame size |
27 // limitation. We currently limit the size of the frames to encode at | 27 // limitation. We currently limit the size of the frames to encode at |
28 // 1080p (%64 pixels blocks), this seems like a reasonable limit for | 28 // 1080p (%64 pixels blocks), this seems like a reasonable limit for |
29 // software encoding. | 29 // software encoding. |
30 const int32_t kMaxWidth = 1920; | 30 const int32_t kMaxWidth = 1920; |
31 const int32_t kMaxHeight = 1088; | 31 const int32_t kMaxHeight = 1088; |
32 | 32 |
33 // Default speed for the encoder (same as WebRTC). Increases the CPU | |
34 // usage as the value is more negative (VP8 valid range: -16..16). | |
35 const int32_t kDefaultCpuUsed = -6; | |
36 | |
37 // Default quantizer min/max values. | |
38 const int32_t kDefaultMinQuantizer = 2; | |
39 const int32_t kDefaultMaxQuantizer = 52; | |
40 | |
41 // Bitstream buffer size. | 33 // Bitstream buffer size. |
42 const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024; | 34 const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024; |
43 | 35 |
44 // Number of frames needs at any given time. | 36 // Number of frames needs at any given time. |
45 const uint32_t kInputFrameCount = 1; | 37 const uint32_t kInputFrameCount = 1; |
46 | 38 |
39 // Magic encoder constants for VP9 adaptive quantization strategy. | |
bbudge
2015/08/05 17:04:41
nit: s/constants/constant
Or do you want to move m
llandwerlin-old
2015/08/05 17:35:55
Done.
| |
40 const int kVp9AqModeCyclicRefresh = 3; | |
41 | |
42 namespace { | |
43 | |
44 struct CodecDescription { | |
bbudge
2015/08/05 17:04:41
This class just holds parameter values, and some s
llandwerlin-old
2015/08/05 17:35:55
Replaced with a function that does the switch on r
| |
45 CodecDescription() | |
46 : codec(media::VIDEO_CODEC_PROFILE_UNKNOWN), | |
47 vpx_codec(nullptr), | |
48 cpu_used(0), | |
49 min_quantizer(0), | |
50 max_quantizer(0) {} | |
51 CodecDescription(media::VideoCodecProfile codec, | |
52 vpx_codec_iface_t* vpx_codec, | |
53 int32_t cpu_used, | |
54 uint32_t min_quantizer, | |
55 uint32_t max_quantizer) | |
56 : codec(codec), | |
57 vpx_codec(vpx_codec), | |
58 cpu_used(cpu_used), | |
59 min_quantizer(min_quantizer), | |
60 max_quantizer(max_quantizer) {} | |
61 ~CodecDescription() {} | |
62 | |
63 bool IsValid() { return vpx_codec != nullptr; } | |
64 | |
65 media::VideoCodecProfile codec; | |
66 | |
67 // Libvpx codec interface. | |
68 vpx_codec_iface_t* vpx_codec; | |
69 | |
70 // Default speed for the encoder. Increases the CPU usage as the | |
71 // value is more negative (VP8 valid range: -16..16, VP9 valid | |
72 // range: -8..8). | |
73 int32_t cpu_used; | |
74 | |
75 // Default quantizer min/max values. | |
76 uint32_t min_quantizer; | |
77 uint32_t max_quantizer; | |
78 }; | |
79 | |
80 CodecDescription PP_ToVpxVideoCodecIface(media::VideoCodecProfile codec) { | |
81 switch (codec) { | |
82 case media::VP8PROFILE_ANY: | |
83 // Using same parameters as WebRTC (see media/cast/sender). | |
84 return CodecDescription(codec, vpx_codec_vp8_cx(), -6, 2, 52); | |
85 case media::VP9PROFILE_ANY: | |
86 return CodecDescription(codec, vpx_codec_vp9_cx(), 6, 20, 30); | |
87 default: | |
88 return CodecDescription(); | |
89 } | |
90 } | |
91 | |
92 } // namespace | |
93 | |
47 class VideoEncoderShim::EncoderImpl { | 94 class VideoEncoderShim::EncoderImpl { |
48 public: | 95 public: |
49 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); | 96 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); |
50 ~EncoderImpl(); | 97 ~EncoderImpl(); |
51 | 98 |
52 void Initialize(media::VideoPixelFormat input_format, | 99 void Initialize(media::VideoPixelFormat input_format, |
53 const gfx::Size& input_visible_size, | 100 const gfx::Size& input_visible_size, |
54 media::VideoCodecProfile output_profile, | 101 const CodecDescription& codec_descr, |
55 uint32 initial_bitrate); | 102 uint32 initial_bitrate); |
56 void Encode(const scoped_refptr<media::VideoFrame>& frame, | 103 void Encode(const scoped_refptr<media::VideoFrame>& frame, |
57 bool force_keyframe); | 104 bool force_keyframe); |
58 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer, | 105 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer, |
59 uint8_t* mem); | 106 uint8_t* mem); |
60 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate); | 107 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate); |
61 void Stop(); | 108 void Stop(); |
62 | 109 |
63 private: | 110 private: |
64 struct PendingEncode { | 111 struct PendingEncode { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
106 } | 153 } |
107 | 154 |
108 VideoEncoderShim::EncoderImpl::~EncoderImpl() { | 155 VideoEncoderShim::EncoderImpl::~EncoderImpl() { |
109 if (initialized_) | 156 if (initialized_) |
110 vpx_codec_destroy(&encoder_); | 157 vpx_codec_destroy(&encoder_); |
111 } | 158 } |
112 | 159 |
113 void VideoEncoderShim::EncoderImpl::Initialize( | 160 void VideoEncoderShim::EncoderImpl::Initialize( |
114 media::VideoPixelFormat input_format, | 161 media::VideoPixelFormat input_format, |
115 const gfx::Size& input_visible_size, | 162 const gfx::Size& input_visible_size, |
116 media::VideoCodecProfile output_profile, | 163 const CodecDescription& codec_descr, |
bbudge
2015/08/05 17:04:41
nit: desc is a more common abbreviation for descri
llandwerlin-old
2015/08/05 17:35:55
Done.
| |
117 uint32 initial_bitrate) { | 164 uint32 initial_bitrate) { |
118 gfx::Size coded_size = | 165 gfx::Size coded_size = |
119 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); | 166 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); |
120 | 167 |
121 // Populate encoder configuration with default values. | 168 // Populate encoder configuration with default values. |
122 if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0) != | 169 if (vpx_codec_enc_config_default(codec_descr.vpx_codec, &config_, 0) != |
123 VPX_CODEC_OK) { | 170 VPX_CODEC_OK) { |
124 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 171 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
125 return; | 172 return; |
126 } | 173 } |
127 | 174 |
128 config_.g_threads = 1; | |
129 config_.g_w = input_visible_size.width(); | 175 config_.g_w = input_visible_size.width(); |
130 config_.g_h = input_visible_size.height(); | 176 config_.g_h = input_visible_size.height(); |
131 | 177 |
132 framerate_ = config_.g_timebase.den; | 178 framerate_ = config_.g_timebase.den; |
133 | 179 |
134 config_.g_lag_in_frames = 0; | 180 config_.g_lag_in_frames = 0; |
135 config_.g_timebase.num = 1; | 181 config_.g_timebase.num = 1; |
136 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; | 182 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; |
137 config_.rc_target_bitrate = initial_bitrate / 1000; | 183 config_.rc_target_bitrate = initial_bitrate / 1000; |
138 config_.rc_min_quantizer = kDefaultMinQuantizer; | 184 config_.rc_min_quantizer = codec_descr.min_quantizer; |
139 config_.rc_max_quantizer = kDefaultMaxQuantizer; | 185 config_.rc_max_quantizer = codec_descr.max_quantizer; |
140 | 186 |
141 vpx_codec_flags_t flags = 0; | 187 vpx_codec_flags_t flags = 0; |
142 if (vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags) != | 188 if (vpx_codec_enc_init(&encoder_, codec_descr.vpx_codec, &config_, flags) != |
143 VPX_CODEC_OK) { | 189 VPX_CODEC_OK) { |
144 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 190 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
145 return; | 191 return; |
146 } | 192 } |
147 initialized_ = true; | 193 initialized_ = true; |
148 | 194 |
149 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) { | 195 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) { |
150 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 196 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
151 return; | 197 return; |
152 } | 198 } |
153 | 199 |
154 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, kDefaultCpuUsed) != | 200 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, codec_descr.cpu_used) != |
155 VPX_CODEC_OK) { | 201 VPX_CODEC_OK) { |
156 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 202 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
157 return; | 203 return; |
158 } | 204 } |
159 | 205 |
206 if (codec_descr.codec == media::VP9PROFILE_ANY) { | |
207 if (vpx_codec_control(&encoder_, VP9E_SET_AQ_MODE, | |
208 kVp9AqModeCyclicRefresh) != VPX_CODEC_OK) { | |
209 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
210 return; | |
211 } | |
212 } | |
213 | |
160 renderer_task_runner_->PostTask( | 214 renderer_task_runner_->PostTask( |
161 FROM_HERE, | 215 FROM_HERE, |
162 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, | 216 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, |
163 kInputFrameCount, coded_size, kBitstreamBufferSize)); | 217 kInputFrameCount, coded_size, kBitstreamBufferSize)); |
164 } | 218 } |
165 | 219 |
166 void VideoEncoderShim::EncoderImpl::Encode( | 220 void VideoEncoderShim::EncoderImpl::Encode( |
167 const scoped_refptr<media::VideoFrame>& frame, | 221 const scoped_refptr<media::VideoFrame>& frame, |
168 bool force_keyframe) { | 222 bool force_keyframe) { |
169 frames_.push_back(PendingEncode(frame, force_keyframe)); | 223 frames_.push_back(PendingEncode(frame, force_keyframe)); |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 media::VideoEncodeAccelerator::SupportedProfile profile; | 359 media::VideoEncodeAccelerator::SupportedProfile profile; |
306 profile.profile = media::VP8PROFILE_ANY; | 360 profile.profile = media::VP8PROFILE_ANY; |
307 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); | 361 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); |
308 // Libvpx and media::VideoEncodeAccelerator are using opposite | 362 // Libvpx and media::VideoEncodeAccelerator are using opposite |
309 // notions of denominator/numerator. | 363 // notions of denominator/numerator. |
310 profile.max_framerate_numerator = config.g_timebase.den; | 364 profile.max_framerate_numerator = config.g_timebase.den; |
311 profile.max_framerate_denominator = config.g_timebase.num; | 365 profile.max_framerate_denominator = config.g_timebase.num; |
312 profiles.push_back(profile); | 366 profiles.push_back(profile); |
313 } | 367 } |
314 | 368 |
369 ret = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &config, 0); | |
370 if (ret == VPX_CODEC_OK) { | |
371 media::VideoEncodeAccelerator::SupportedProfile profile; | |
372 profile.profile = media::VP9PROFILE_ANY; | |
373 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); | |
374 profile.max_framerate_numerator = config.g_timebase.den; | |
375 profile.max_framerate_denominator = config.g_timebase.num; | |
376 profiles.push_back(profile); | |
377 } | |
378 | |
315 return profiles; | 379 return profiles; |
316 } | 380 } |
317 | 381 |
318 bool VideoEncoderShim::Initialize( | 382 bool VideoEncoderShim::Initialize( |
319 media::VideoPixelFormat input_format, | 383 media::VideoPixelFormat input_format, |
320 const gfx::Size& input_visible_size, | 384 const gfx::Size& input_visible_size, |
321 media::VideoCodecProfile output_profile, | 385 media::VideoCodecProfile output_profile, |
322 uint32 initial_bitrate, | 386 uint32 initial_bitrate, |
323 media::VideoEncodeAccelerator::Client* client) { | 387 media::VideoEncodeAccelerator::Client* client) { |
324 DCHECK(RenderThreadImpl::current()); | 388 DCHECK(RenderThreadImpl::current()); |
325 DCHECK_EQ(client, host_); | 389 DCHECK_EQ(client, host_); |
326 | 390 |
327 if (input_format != media::PIXEL_FORMAT_I420) | 391 if (input_format != media::PIXEL_FORMAT_I420) |
328 return false; | 392 return false; |
329 | 393 |
394 CodecDescription codec_desc = PP_ToVpxVideoCodecIface(output_profile); | |
395 if (!codec_desc.IsValid()) | |
396 return false; | |
397 | |
330 media_task_runner_->PostTask( | 398 media_task_runner_->PostTask( |
331 FROM_HERE, | 399 FROM_HERE, base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, |
332 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, | 400 base::Unretained(encoder_impl_.get()), input_format, |
333 base::Unretained(encoder_impl_.get()), input_format, | 401 input_visible_size, codec_desc, initial_bitrate)); |
334 input_visible_size, output_profile, initial_bitrate)); | |
335 | 402 |
336 return true; | 403 return true; |
337 } | 404 } |
338 | 405 |
339 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, | 406 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, |
340 bool force_keyframe) { | 407 bool force_keyframe) { |
341 DCHECK(RenderThreadImpl::current()); | 408 DCHECK(RenderThreadImpl::current()); |
342 | 409 |
343 media_task_runner_->PostTask( | 410 media_task_runner_->PostTask( |
344 FROM_HERE, | 411 FROM_HERE, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 } | 462 } |
396 | 463 |
397 void VideoEncoderShim::OnNotifyError( | 464 void VideoEncoderShim::OnNotifyError( |
398 media::VideoEncodeAccelerator::Error error) { | 465 media::VideoEncodeAccelerator::Error error) { |
399 DCHECK(RenderThreadImpl::current()); | 466 DCHECK(RenderThreadImpl::current()); |
400 | 467 |
401 host_->NotifyError(error); | 468 host_->NotifyError(error); |
402 } | 469 } |
403 | 470 |
404 } // namespace content | 471 } // namespace content |
OLD | NEW |