| 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 |