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 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/memory/scoped_vector.h" | 14 #include "base/memory/scoped_vector.h" |
15 #include "base/memory/shared_memory.h" | 15 #include "base/memory/shared_memory.h" |
16 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
17 #include "base/thread_task_runner_handle.h" | 17 #include "base/thread_task_runner_handle.h" |
18 #include "content/renderer/pepper/pepper_video_encoder_host.h" | 18 #include "content/renderer/pepper/pepper_video_encoder_host.h" |
19 #include "content/renderer/render_thread_impl.h" | 19 #include "content/renderer/render_thread_impl.h" |
20 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" | 20 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" |
21 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" | 21 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" |
22 #include "ui/gfx/geometry/size.h" | 22 #include "ui/gfx/geometry/size.h" |
23 | 23 |
24 namespace content { | 24 namespace content { |
25 | 25 |
26 namespace { | |
27 | |
26 // TODO(llandwerlin): Libvpx doesn't seem to have a maximum frame size | 28 // 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 | 29 // limitation. We currently limit the size of the frames to encode at |
28 // 1080p (%64 pixels blocks), this seems like a reasonable limit for | 30 // 1080p (%64 pixels blocks), this seems like a reasonable limit for |
29 // software encoding. | 31 // software encoding. |
30 const int32_t kMaxWidth = 1920; | 32 const int32_t kMaxWidth = 1920; |
31 const int32_t kMaxHeight = 1088; | 33 const int32_t kMaxHeight = 1088; |
32 | 34 |
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. | 35 // Bitstream buffer size. |
42 const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024; | 36 const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024; |
43 | 37 |
44 // Number of frames needs at any given time. | 38 // Number of frames needs at any given time. |
45 const uint32_t kInputFrameCount = 1; | 39 const uint32_t kInputFrameCount = 1; |
46 | 40 |
41 // Default speed for the encoder. Increases the CPU usage as the value | |
42 // is more negative (VP8 valid range: -16..16, VP9 valid range: | |
43 // -8..8). | |
bbudge
2015/08/05 17:42:57
If you can, explain why how these values were chos
llandwerlin-old
2015/08/05 18:20:12
Essentially same a WebRTC.
| |
44 const int32_t kVp8DefaultCpuUsed = -6; | |
45 const int32_t kVp9DefaultCpuUsed = 6; | |
46 | |
47 // Default quantizer min/max values. | |
bbudge
2015/08/05 17:42:57
Ditto. The comment doesn't add anything.
llandwerlin-old
2015/08/05 18:20:12
Done.
| |
48 const int32_t kVp8DefaultMinQuantizer = 2; | |
49 const int32_t kVp8DefaultMaxQuantizer = 52; | |
50 const int32_t kVp9DefaultMinQuantizer = 20; | |
51 const int32_t kVp9DefaultMaxQuantizer = 30; | |
52 | |
53 // VP9 adaptive quantization strategy (live video conferencing). | |
bbudge
2015/08/05 17:42:57
This comment is good.
llandwerlin-old
2015/08/05 18:20:12
Done.
| |
54 const int kVp9AqModeCyclicRefresh = 3; | |
55 | |
56 void GetVpxCodecParameters(media::VideoCodecProfile codec, | |
57 vpx_codec_iface_t** vpx_codec, | |
58 int32_t* min_quantizer, | |
59 int32_t* max_quantizer, | |
60 int32_t* cpu_used) { | |
61 switch (codec) { | |
62 case media::VP8PROFILE_ANY: | |
63 *vpx_codec = vpx_codec_vp8_cx(); | |
64 *min_quantizer = kVp8DefaultMinQuantizer; | |
65 *max_quantizer = kVp8DefaultMaxQuantizer; | |
66 *cpu_used = kVp8DefaultCpuUsed; | |
67 break; | |
68 case media::VP9PROFILE_ANY: | |
69 *vpx_codec = vpx_codec_vp9_cx(); | |
70 *min_quantizer = kVp9DefaultMinQuantizer; | |
71 *max_quantizer = kVp9DefaultMaxQuantizer; | |
72 *cpu_used = kVp9DefaultCpuUsed; | |
73 break; | |
74 default: | |
bbudge
2015/08/05 17:44:20
zero vpx_codec for sanity.
llandwerlin-old
2015/08/05 18:20:12
Done.
| |
75 NOTREACHED(); | |
76 } | |
77 } | |
78 | |
79 } // namespace | |
80 | |
47 class VideoEncoderShim::EncoderImpl { | 81 class VideoEncoderShim::EncoderImpl { |
48 public: | 82 public: |
49 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); | 83 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); |
50 ~EncoderImpl(); | 84 ~EncoderImpl(); |
51 | 85 |
52 void Initialize(media::VideoPixelFormat input_format, | 86 void Initialize(media::VideoPixelFormat input_format, |
53 const gfx::Size& input_visible_size, | 87 const gfx::Size& input_visible_size, |
54 media::VideoCodecProfile output_profile, | 88 media::VideoCodecProfile output_profile, |
55 uint32 initial_bitrate); | 89 uint32 initial_bitrate); |
56 void Encode(const scoped_refptr<media::VideoFrame>& frame, | 90 void Encode(const scoped_refptr<media::VideoFrame>& frame, |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
111 } | 145 } |
112 | 146 |
113 void VideoEncoderShim::EncoderImpl::Initialize( | 147 void VideoEncoderShim::EncoderImpl::Initialize( |
114 media::VideoPixelFormat input_format, | 148 media::VideoPixelFormat input_format, |
115 const gfx::Size& input_visible_size, | 149 const gfx::Size& input_visible_size, |
116 media::VideoCodecProfile output_profile, | 150 media::VideoCodecProfile output_profile, |
117 uint32 initial_bitrate) { | 151 uint32 initial_bitrate) { |
118 gfx::Size coded_size = | 152 gfx::Size coded_size = |
119 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); | 153 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); |
120 | 154 |
155 vpx_codec_iface_t* vpx_codec; | |
156 int32_t min_quantizer, max_quantizer, cpu_used; | |
157 GetVpxCodecParameters(output_profile, &vpx_codec, &min_quantizer, | |
158 &max_quantizer, &cpu_used); | |
159 | |
121 // Populate encoder configuration with default values. | 160 // Populate encoder configuration with default values. |
122 if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0) != | 161 if (vpx_codec_enc_config_default(vpx_codec, &config_, 0) != VPX_CODEC_OK) { |
123 VPX_CODEC_OK) { | |
124 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 162 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
125 return; | 163 return; |
126 } | 164 } |
127 | 165 |
128 config_.g_threads = 1; | |
129 config_.g_w = input_visible_size.width(); | 166 config_.g_w = input_visible_size.width(); |
130 config_.g_h = input_visible_size.height(); | 167 config_.g_h = input_visible_size.height(); |
131 | 168 |
132 framerate_ = config_.g_timebase.den; | 169 framerate_ = config_.g_timebase.den; |
133 | 170 |
134 config_.g_lag_in_frames = 0; | 171 config_.g_lag_in_frames = 0; |
135 config_.g_timebase.num = 1; | 172 config_.g_timebase.num = 1; |
136 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; | 173 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; |
137 config_.rc_target_bitrate = initial_bitrate / 1000; | 174 config_.rc_target_bitrate = initial_bitrate / 1000; |
138 config_.rc_min_quantizer = kDefaultMinQuantizer; | 175 config_.rc_min_quantizer = min_quantizer; |
139 config_.rc_max_quantizer = kDefaultMaxQuantizer; | 176 config_.rc_max_quantizer = max_quantizer; |
140 | 177 |
141 vpx_codec_flags_t flags = 0; | 178 vpx_codec_flags_t flags = 0; |
142 if (vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags) != | 179 if (vpx_codec_enc_init(&encoder_, vpx_codec, &config_, flags) != |
143 VPX_CODEC_OK) { | 180 VPX_CODEC_OK) { |
144 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 181 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
145 return; | 182 return; |
146 } | 183 } |
147 initialized_ = true; | 184 initialized_ = true; |
148 | 185 |
149 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) { | 186 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) { |
150 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 187 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
151 return; | 188 return; |
152 } | 189 } |
153 | 190 |
154 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, kDefaultCpuUsed) != | 191 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, cpu_used) != |
155 VPX_CODEC_OK) { | 192 VPX_CODEC_OK) { |
156 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 193 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
157 return; | 194 return; |
158 } | 195 } |
159 | 196 |
197 if (output_profile == media::VP9PROFILE_ANY) { | |
198 if (vpx_codec_control(&encoder_, VP9E_SET_AQ_MODE, | |
199 kVp9AqModeCyclicRefresh) != VPX_CODEC_OK) { | |
200 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
201 return; | |
202 } | |
203 } | |
204 | |
160 renderer_task_runner_->PostTask( | 205 renderer_task_runner_->PostTask( |
161 FROM_HERE, | 206 FROM_HERE, |
162 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, | 207 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, |
163 kInputFrameCount, coded_size, kBitstreamBufferSize)); | 208 kInputFrameCount, coded_size, kBitstreamBufferSize)); |
164 } | 209 } |
165 | 210 |
166 void VideoEncoderShim::EncoderImpl::Encode( | 211 void VideoEncoderShim::EncoderImpl::Encode( |
167 const scoped_refptr<media::VideoFrame>& frame, | 212 const scoped_refptr<media::VideoFrame>& frame, |
168 bool force_keyframe) { | 213 bool force_keyframe) { |
169 frames_.push_back(PendingEncode(frame, force_keyframe)); | 214 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; | 350 media::VideoEncodeAccelerator::SupportedProfile profile; |
306 profile.profile = media::VP8PROFILE_ANY; | 351 profile.profile = media::VP8PROFILE_ANY; |
307 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); | 352 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); |
308 // Libvpx and media::VideoEncodeAccelerator are using opposite | 353 // Libvpx and media::VideoEncodeAccelerator are using opposite |
309 // notions of denominator/numerator. | 354 // notions of denominator/numerator. |
310 profile.max_framerate_numerator = config.g_timebase.den; | 355 profile.max_framerate_numerator = config.g_timebase.den; |
311 profile.max_framerate_denominator = config.g_timebase.num; | 356 profile.max_framerate_denominator = config.g_timebase.num; |
312 profiles.push_back(profile); | 357 profiles.push_back(profile); |
313 } | 358 } |
314 | 359 |
360 ret = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &config, 0); | |
361 if (ret == VPX_CODEC_OK) { | |
362 media::VideoEncodeAccelerator::SupportedProfile profile; | |
363 profile.profile = media::VP9PROFILE_ANY; | |
364 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); | |
365 profile.max_framerate_numerator = config.g_timebase.den; | |
366 profile.max_framerate_denominator = config.g_timebase.num; | |
367 profiles.push_back(profile); | |
368 } | |
369 | |
315 return profiles; | 370 return profiles; |
316 } | 371 } |
317 | 372 |
318 bool VideoEncoderShim::Initialize( | 373 bool VideoEncoderShim::Initialize( |
319 media::VideoPixelFormat input_format, | 374 media::VideoPixelFormat input_format, |
320 const gfx::Size& input_visible_size, | 375 const gfx::Size& input_visible_size, |
321 media::VideoCodecProfile output_profile, | 376 media::VideoCodecProfile output_profile, |
322 uint32 initial_bitrate, | 377 uint32 initial_bitrate, |
323 media::VideoEncodeAccelerator::Client* client) { | 378 media::VideoEncodeAccelerator::Client* client) { |
324 DCHECK(RenderThreadImpl::current()); | 379 DCHECK(RenderThreadImpl::current()); |
325 DCHECK_EQ(client, host_); | 380 DCHECK_EQ(client, host_); |
326 | 381 |
327 if (input_format != media::PIXEL_FORMAT_I420) | 382 if (input_format != media::PIXEL_FORMAT_I420) |
328 return false; | 383 return false; |
329 | 384 |
385 if (output_profile != media::VP8PROFILE_ANY && | |
386 output_profile != media::VP9PROFILE_ANY) | |
387 return false; | |
388 | |
330 media_task_runner_->PostTask( | 389 media_task_runner_->PostTask( |
331 FROM_HERE, | 390 FROM_HERE, |
332 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, | 391 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, |
333 base::Unretained(encoder_impl_.get()), input_format, | 392 base::Unretained(encoder_impl_.get()), input_format, |
334 input_visible_size, output_profile, initial_bitrate)); | 393 input_visible_size, output_profile, initial_bitrate)); |
335 | 394 |
336 return true; | 395 return true; |
337 } | 396 } |
338 | 397 |
339 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, | 398 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 } | 454 } |
396 | 455 |
397 void VideoEncoderShim::OnNotifyError( | 456 void VideoEncoderShim::OnNotifyError( |
398 media::VideoEncodeAccelerator::Error error) { | 457 media::VideoEncodeAccelerator::Error error) { |
399 DCHECK(RenderThreadImpl::current()); | 458 DCHECK(RenderThreadImpl::current()); |
400 | 459 |
401 host_->NotifyError(error); | 460 host_->NotifyError(error); |
402 } | 461 } |
403 | 462 |
404 } // namespace content | 463 } // namespace content |
OLD | NEW |