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), using the same value as WebRTC. |
| 44 const int32_t kVp8DefaultCpuUsed = -6; |
| 45 |
| 46 // Default quantizer min/max values (same values as WebRTC). |
| 47 const int32_t kVp8DefaultMinQuantizer = 2; |
| 48 const int32_t kVp8DefaultMaxQuantizer = 52; |
| 49 |
| 50 // For VP9, the following 3 values are the same values as remoting. |
| 51 const int32_t kVp9DefaultCpuUsed = 6; |
| 52 |
| 53 const int32_t kVp9DefaultMinQuantizer = 20; |
| 54 const int32_t kVp9DefaultMaxQuantizer = 30; |
| 55 |
| 56 // VP9 adaptive quantization strategy (same as remoting (live video |
| 57 // conferencing)). |
| 58 const int kVp9AqModeCyclicRefresh = 3; |
| 59 |
| 60 void GetVpxCodecParameters(media::VideoCodecProfile codec, |
| 61 vpx_codec_iface_t** vpx_codec, |
| 62 int32_t* min_quantizer, |
| 63 int32_t* max_quantizer, |
| 64 int32_t* cpu_used) { |
| 65 switch (codec) { |
| 66 case media::VP8PROFILE_ANY: |
| 67 *vpx_codec = vpx_codec_vp8_cx(); |
| 68 *min_quantizer = kVp8DefaultMinQuantizer; |
| 69 *max_quantizer = kVp8DefaultMaxQuantizer; |
| 70 *cpu_used = kVp8DefaultCpuUsed; |
| 71 break; |
| 72 case media::VP9PROFILE_ANY: |
| 73 *vpx_codec = vpx_codec_vp9_cx(); |
| 74 *min_quantizer = kVp9DefaultMinQuantizer; |
| 75 *max_quantizer = kVp9DefaultMaxQuantizer; |
| 76 *cpu_used = kVp9DefaultCpuUsed; |
| 77 break; |
| 78 default: |
| 79 *vpx_codec = nullptr; |
| 80 NOTREACHED(); |
| 81 } |
| 82 } |
| 83 |
| 84 } // namespace |
| 85 |
47 class VideoEncoderShim::EncoderImpl { | 86 class VideoEncoderShim::EncoderImpl { |
48 public: | 87 public: |
49 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); | 88 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); |
50 ~EncoderImpl(); | 89 ~EncoderImpl(); |
51 | 90 |
52 void Initialize(media::VideoPixelFormat input_format, | 91 void Initialize(media::VideoPixelFormat input_format, |
53 const gfx::Size& input_visible_size, | 92 const gfx::Size& input_visible_size, |
54 media::VideoCodecProfile output_profile, | 93 media::VideoCodecProfile output_profile, |
55 uint32 initial_bitrate); | 94 uint32 initial_bitrate); |
56 void Encode(const scoped_refptr<media::VideoFrame>& frame, | 95 void Encode(const scoped_refptr<media::VideoFrame>& frame, |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 } | 150 } |
112 | 151 |
113 void VideoEncoderShim::EncoderImpl::Initialize( | 152 void VideoEncoderShim::EncoderImpl::Initialize( |
114 media::VideoPixelFormat input_format, | 153 media::VideoPixelFormat input_format, |
115 const gfx::Size& input_visible_size, | 154 const gfx::Size& input_visible_size, |
116 media::VideoCodecProfile output_profile, | 155 media::VideoCodecProfile output_profile, |
117 uint32 initial_bitrate) { | 156 uint32 initial_bitrate) { |
118 gfx::Size coded_size = | 157 gfx::Size coded_size = |
119 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); | 158 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); |
120 | 159 |
| 160 vpx_codec_iface_t* vpx_codec; |
| 161 int32_t min_quantizer, max_quantizer, cpu_used; |
| 162 GetVpxCodecParameters(output_profile, &vpx_codec, &min_quantizer, |
| 163 &max_quantizer, &cpu_used); |
| 164 |
121 // Populate encoder configuration with default values. | 165 // Populate encoder configuration with default values. |
122 if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0) != | 166 if (vpx_codec_enc_config_default(vpx_codec, &config_, 0) != VPX_CODEC_OK) { |
123 VPX_CODEC_OK) { | |
124 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 167 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
125 return; | 168 return; |
126 } | 169 } |
127 | 170 |
128 config_.g_threads = 1; | |
129 config_.g_w = input_visible_size.width(); | 171 config_.g_w = input_visible_size.width(); |
130 config_.g_h = input_visible_size.height(); | 172 config_.g_h = input_visible_size.height(); |
131 | 173 |
132 framerate_ = config_.g_timebase.den; | 174 framerate_ = config_.g_timebase.den; |
133 | 175 |
134 config_.g_lag_in_frames = 0; | 176 config_.g_lag_in_frames = 0; |
135 config_.g_timebase.num = 1; | 177 config_.g_timebase.num = 1; |
136 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; | 178 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; |
137 config_.rc_target_bitrate = initial_bitrate / 1000; | 179 config_.rc_target_bitrate = initial_bitrate / 1000; |
138 config_.rc_min_quantizer = kDefaultMinQuantizer; | 180 config_.rc_min_quantizer = min_quantizer; |
139 config_.rc_max_quantizer = kDefaultMaxQuantizer; | 181 config_.rc_max_quantizer = max_quantizer; |
140 | 182 |
141 vpx_codec_flags_t flags = 0; | 183 vpx_codec_flags_t flags = 0; |
142 if (vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags) != | 184 if (vpx_codec_enc_init(&encoder_, vpx_codec, &config_, flags) != |
143 VPX_CODEC_OK) { | 185 VPX_CODEC_OK) { |
144 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 186 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
145 return; | 187 return; |
146 } | 188 } |
147 initialized_ = true; | 189 initialized_ = true; |
148 | 190 |
149 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) { | 191 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) { |
150 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 192 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
151 return; | 193 return; |
152 } | 194 } |
153 | 195 |
154 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, kDefaultCpuUsed) != | 196 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, cpu_used) != |
155 VPX_CODEC_OK) { | 197 VPX_CODEC_OK) { |
156 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 198 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
157 return; | 199 return; |
158 } | 200 } |
159 | 201 |
| 202 if (output_profile == media::VP9PROFILE_ANY) { |
| 203 if (vpx_codec_control(&encoder_, VP9E_SET_AQ_MODE, |
| 204 kVp9AqModeCyclicRefresh) != VPX_CODEC_OK) { |
| 205 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 206 return; |
| 207 } |
| 208 } |
| 209 |
160 renderer_task_runner_->PostTask( | 210 renderer_task_runner_->PostTask( |
161 FROM_HERE, | 211 FROM_HERE, |
162 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, | 212 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, |
163 kInputFrameCount, coded_size, kBitstreamBufferSize)); | 213 kInputFrameCount, coded_size, kBitstreamBufferSize)); |
164 } | 214 } |
165 | 215 |
166 void VideoEncoderShim::EncoderImpl::Encode( | 216 void VideoEncoderShim::EncoderImpl::Encode( |
167 const scoped_refptr<media::VideoFrame>& frame, | 217 const scoped_refptr<media::VideoFrame>& frame, |
168 bool force_keyframe) { | 218 bool force_keyframe) { |
169 frames_.push_back(PendingEncode(frame, force_keyframe)); | 219 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; | 355 media::VideoEncodeAccelerator::SupportedProfile profile; |
306 profile.profile = media::VP8PROFILE_ANY; | 356 profile.profile = media::VP8PROFILE_ANY; |
307 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); | 357 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); |
308 // Libvpx and media::VideoEncodeAccelerator are using opposite | 358 // Libvpx and media::VideoEncodeAccelerator are using opposite |
309 // notions of denominator/numerator. | 359 // notions of denominator/numerator. |
310 profile.max_framerate_numerator = config.g_timebase.den; | 360 profile.max_framerate_numerator = config.g_timebase.den; |
311 profile.max_framerate_denominator = config.g_timebase.num; | 361 profile.max_framerate_denominator = config.g_timebase.num; |
312 profiles.push_back(profile); | 362 profiles.push_back(profile); |
313 } | 363 } |
314 | 364 |
| 365 ret = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &config, 0); |
| 366 if (ret == VPX_CODEC_OK) { |
| 367 media::VideoEncodeAccelerator::SupportedProfile profile; |
| 368 profile.profile = media::VP9PROFILE_ANY; |
| 369 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); |
| 370 profile.max_framerate_numerator = config.g_timebase.den; |
| 371 profile.max_framerate_denominator = config.g_timebase.num; |
| 372 profiles.push_back(profile); |
| 373 } |
| 374 |
315 return profiles; | 375 return profiles; |
316 } | 376 } |
317 | 377 |
318 bool VideoEncoderShim::Initialize( | 378 bool VideoEncoderShim::Initialize( |
319 media::VideoPixelFormat input_format, | 379 media::VideoPixelFormat input_format, |
320 const gfx::Size& input_visible_size, | 380 const gfx::Size& input_visible_size, |
321 media::VideoCodecProfile output_profile, | 381 media::VideoCodecProfile output_profile, |
322 uint32 initial_bitrate, | 382 uint32 initial_bitrate, |
323 media::VideoEncodeAccelerator::Client* client) { | 383 media::VideoEncodeAccelerator::Client* client) { |
324 DCHECK(RenderThreadImpl::current()); | 384 DCHECK(RenderThreadImpl::current()); |
325 DCHECK_EQ(client, host_); | 385 DCHECK_EQ(client, host_); |
326 | 386 |
327 if (input_format != media::PIXEL_FORMAT_I420) | 387 if (input_format != media::PIXEL_FORMAT_I420) |
328 return false; | 388 return false; |
329 | 389 |
| 390 if (output_profile != media::VP8PROFILE_ANY && |
| 391 output_profile != media::VP9PROFILE_ANY) |
| 392 return false; |
| 393 |
330 media_task_runner_->PostTask( | 394 media_task_runner_->PostTask( |
331 FROM_HERE, | 395 FROM_HERE, |
332 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, | 396 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, |
333 base::Unretained(encoder_impl_.get()), input_format, | 397 base::Unretained(encoder_impl_.get()), input_format, |
334 input_visible_size, output_profile, initial_bitrate)); | 398 input_visible_size, output_profile, initial_bitrate)); |
335 | 399 |
336 return true; | 400 return true; |
337 } | 401 } |
338 | 402 |
339 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, | 403 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 } | 459 } |
396 | 460 |
397 void VideoEncoderShim::OnNotifyError( | 461 void VideoEncoderShim::OnNotifyError( |
398 media::VideoEncodeAccelerator::Error error) { | 462 media::VideoEncodeAccelerator::Error error) { |
399 DCHECK(RenderThreadImpl::current()); | 463 DCHECK(RenderThreadImpl::current()); |
400 | 464 |
401 host_->NotifyError(error); | 465 host_->NotifyError(error); |
402 } | 466 } |
403 | 467 |
404 } // namespace content | 468 } // namespace content |
OLD | NEW |