Chromium Code Reviews| 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 |