 Chromium Code Reviews
 Chromium Code Reviews Issue 1132833002:
  pepper: add software vp9 encoder support to PPB_VideoEncoder  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1132833002:
  pepper: add software vp9 encoder support to PPB_VideoEncoder  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| Index: content/renderer/pepper/video_encoder_shim.cc | 
| diff --git a/content/renderer/pepper/video_encoder_shim.cc b/content/renderer/pepper/video_encoder_shim.cc | 
| index d28744fd76fdced6433c43cea3315bb3aacaaf20..5e75c29d2e5dde4874716d4fa6570b6b3ae507c0 100644 | 
| --- a/content/renderer/pepper/video_encoder_shim.cc | 
| +++ b/content/renderer/pepper/video_encoder_shim.cc | 
| @@ -30,20 +30,149 @@ namespace content { | 
| const int32_t kMaxWidth = 1920; | 
| const int32_t kMaxHeight = 1088; | 
| -// Default speed for the encoder (same as WebRTC). Increases the CPU | 
| -// usage as the value is more negative (VP8 valid range: -16..16). | 
| -const int32_t kDefaultCpuUsed = -6; | 
| - | 
| -// Default quantizer min/max values. | 
| -const int32_t kDefaultMinQuantizer = 2; | 
| -const int32_t kDefaultMaxQuantizer = 52; | 
| - | 
| // Bitstream buffer size. | 
| const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024; | 
| // Number of frames needs at any given time. | 
| const uint32_t kInputFrameCount = 1; | 
| +namespace { | 
| + | 
| +class CodecConfig { | 
| 
bbudge
2015/08/05 02:07:45
This seems like an awful lot of machinery just to
 
llandwerlin-old
2015/08/05 14:55:17
Went back to the previous iteration just holding i
 | 
| + public: | 
| + virtual ~CodecConfig() {} | 
| + | 
| + bool InitializeEncoder(vpx_codec_ctx_t* encoder, | 
| + const gfx::Size& size, | 
| + uint32 initial_bitrate, | 
| + uint32* initial_framerate, | 
| + bool* encoder_initialized); | 
| + | 
| + bool UpdateBitrate(vpx_codec_ctx_t* encoder, uint32 bitrate); | 
| + | 
| + protected: | 
| + CodecConfig(vpx_codec_iface_t* vpx_codec, | 
| + int32_t cpu_used, | 
| + uint32_t min_quantizer, | 
| + uint32_t max_quantizer); | 
| + | 
| + // A special initialization phase to be defined per codec. | 
| + virtual bool InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) = 0; | 
| + | 
| + // Libvpx codec interface. | 
| + vpx_codec_iface_t* vpx_codec_; | 
| + | 
| + // Libvpx configuration parameters of the codec. | 
| + vpx_codec_enc_cfg_t vpx_config_; | 
| + | 
| + // Default speed for the encoder. Increases the CPU usage as the | 
| + // value is more negative (VP8 valid range: -16..16, VP9 valid | 
| + // range: -8..8). | 
| + int32_t cpu_used_; | 
| + | 
| + // Default quantizer min/max values. | 
| + uint32_t min_quantizer_; | 
| + uint32_t max_quantizer_; | 
| +}; | 
| + | 
| +CodecConfig::CodecConfig(vpx_codec_iface_t* vpx_codec, | 
| + int32_t cpu_used, | 
| + uint32_t min_quantizer, | 
| + uint32_t max_quantizer) | 
| + : vpx_codec_(vpx_codec), | 
| + cpu_used_(cpu_used), | 
| + min_quantizer_(min_quantizer), | 
| + max_quantizer_(max_quantizer) { | 
| + vpx_codec_err_t err = | 
| + vpx_codec_enc_config_default(vpx_codec_, &vpx_config_, 0); | 
| + DCHECK_EQ(VPX_CODEC_OK, err); | 
| +} | 
| + | 
| +bool CodecConfig::InitializeEncoder(vpx_codec_ctx_t* encoder, | 
| + const gfx::Size& size, | 
| + uint32 initial_bitrate, | 
| + uint32* initial_framerate, | 
| + bool* encoder_initialized) { | 
| + *initial_framerate = vpx_config_.g_timebase.den; | 
| + | 
| + vpx_config_.g_w = size.width(); | 
| + vpx_config_.g_h = size.height(); | 
| + | 
| + vpx_config_.g_lag_in_frames = 0; | 
| + vpx_config_.g_timebase.num = 1; | 
| + vpx_config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; | 
| + vpx_config_.rc_target_bitrate = initial_bitrate / 1000; | 
| + vpx_config_.rc_min_quantizer = min_quantizer_; | 
| + vpx_config_.rc_max_quantizer = max_quantizer_; | 
| + | 
| + vpx_codec_flags_t flags = 0; | 
| + if (vpx_codec_enc_init(encoder, vpx_codec_, &vpx_config_, flags) != | 
| + VPX_CODEC_OK) { | 
| + return false; | 
| + } | 
| + *encoder_initialized = true; | 
| + | 
| + if (vpx_codec_enc_config_set(encoder, &vpx_config_) != VPX_CODEC_OK) | 
| + return false; | 
| + | 
| + if (vpx_codec_control(encoder, VP8E_SET_CPUUSED, cpu_used_) != VPX_CODEC_OK) { | 
| + return false; | 
| + } | 
| + | 
| + return InitializeEncoderForCodec(encoder); | 
| +} | 
| + | 
| +bool CodecConfig::UpdateBitrate(vpx_codec_ctx_t* encoder, uint32 bitrate) { | 
| + uint32 bitrate_kbit = bitrate / 1000; | 
| + if (vpx_config_.rc_target_bitrate == bitrate_kbit) | 
| + return true; | 
| + | 
| + vpx_config_.rc_target_bitrate = bitrate_kbit; | 
| + return vpx_codec_enc_config_set(encoder, &vpx_config_) == VPX_CODEC_OK; | 
| +} | 
| + | 
| +// VP8 configuration. | 
| +class Vp8CodecConfig : public CodecConfig { | 
| + public: | 
| + Vp8CodecConfig() : CodecConfig(vpx_codec_vp8_cx(), -6, 2, 52) {} | 
| + ~Vp8CodecConfig() override {} | 
| + | 
| + private: | 
| + bool InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) override { | 
| + return true; | 
| + } | 
| +}; | 
| + | 
| +// VP9 configuration. | 
| +class Vp9CodecConfig : public CodecConfig { | 
| + public: | 
| + Vp9CodecConfig() : CodecConfig(vpx_codec_vp9_cx(), 6, 20, 30) {} | 
| + ~Vp9CodecConfig() override {} | 
| + | 
| + private: | 
| + bool InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) override; | 
| +}; | 
| + | 
| +bool Vp9CodecConfig::InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) { | 
| + return vpx_codec_control(encoder, VP9E_SET_AQ_MODE, 3) == VPX_CODEC_OK; | 
| +} | 
| + | 
| +scoped_ptr<CodecConfig> PP_ToVpxVideoCodecIface( | 
| + media::VideoCodecProfile codec) { | 
| + switch (codec) { | 
| + case media::VP8PROFILE_ANY: | 
| + // Using same parameters as WebRTC (see media/cast/sender). | 
| + return make_scoped_ptr(new Vp8CodecConfig()); | 
| + case media::VP9PROFILE_ANY: | 
| + return make_scoped_ptr(new Vp9CodecConfig()); | 
| + ; | 
| + default: | 
| + return scoped_ptr<CodecConfig>(); | 
| + } | 
| +} | 
| + | 
| +} // namespace | 
| + | 
| class VideoEncoderShim::EncoderImpl { | 
| public: | 
| explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); | 
| @@ -51,7 +180,7 @@ class VideoEncoderShim::EncoderImpl { | 
| void Initialize(media::VideoPixelFormat input_format, | 
| const gfx::Size& input_visible_size, | 
| - media::VideoCodecProfile output_profile, | 
| + CodecConfig* codec_config, | 
| uint32 initial_bitrate); | 
| void Encode(const scoped_refptr<media::VideoFrame>& frame, | 
| bool force_keyframe); | 
| @@ -86,12 +215,11 @@ class VideoEncoderShim::EncoderImpl { | 
| base::WeakPtr<VideoEncoderShim> shim_; | 
| scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_; | 
| - bool initialized_; | 
| - | 
| - // Libvpx internal objects. Only valid if |initialized_| is true. | 
| - vpx_codec_enc_cfg_t config_; | 
| + // Libvpx internal objects. Only valid if |codec_config_| is not null. | 
| vpx_codec_ctx_t encoder_; | 
| + scoped_ptr<CodecConfig> codec_config_; | 
| + | 
| uint32 framerate_; | 
| std::deque<PendingEncode> frames_; | 
| @@ -100,59 +228,29 @@ class VideoEncoderShim::EncoderImpl { | 
| VideoEncoderShim::EncoderImpl::EncoderImpl( | 
| const base::WeakPtr<VideoEncoderShim>& shim) | 
| - : shim_(shim), | 
| - renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 
| - initialized_(false) { | 
| -} | 
| + : shim_(shim), renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} | 
| VideoEncoderShim::EncoderImpl::~EncoderImpl() { | 
| - if (initialized_) | 
| + if (codec_config_) | 
| vpx_codec_destroy(&encoder_); | 
| } | 
| void VideoEncoderShim::EncoderImpl::Initialize( | 
| media::VideoPixelFormat input_format, | 
| const gfx::Size& input_visible_size, | 
| - media::VideoCodecProfile output_profile, | 
| + CodecConfig* codec_config, | 
| uint32 initial_bitrate) { | 
| + DCHECK(codec_config); | 
| gfx::Size coded_size = | 
| media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); | 
| - // Populate encoder configuration with default values. | 
| - if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0) != | 
| - VPX_CODEC_OK) { | 
| - NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 
| - return; | 
| - } | 
| - | 
| - config_.g_threads = 1; | 
| - config_.g_w = input_visible_size.width(); | 
| - config_.g_h = input_visible_size.height(); | 
| + codec_config_.reset(codec_config); | 
| - framerate_ = config_.g_timebase.den; | 
| - | 
| - config_.g_lag_in_frames = 0; | 
| - config_.g_timebase.num = 1; | 
| - config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; | 
| - config_.rc_target_bitrate = initial_bitrate / 1000; | 
| - config_.rc_min_quantizer = kDefaultMinQuantizer; | 
| - config_.rc_max_quantizer = kDefaultMaxQuantizer; | 
| - | 
| - vpx_codec_flags_t flags = 0; | 
| - if (vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags) != | 
| - VPX_CODEC_OK) { | 
| - NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 
| - return; | 
| - } | 
| - initialized_ = true; | 
| - | 
| - if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) { | 
| - NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 
| - return; | 
| - } | 
| - | 
| - if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, kDefaultCpuUsed) != | 
| - VPX_CODEC_OK) { | 
| + bool encoder_initialized = false; | 
| + if (!codec_config_->InitializeEncoder(&encoder_, coded_size, initial_bitrate, | 
| + &framerate_, &encoder_initialized)) { | 
| + if (!encoder_initialized) | 
| + codec_config_.reset(); | 
| NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 
| return; | 
| } | 
| @@ -182,12 +280,7 @@ void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange( | 
| uint32 framerate) { | 
| framerate_ = framerate; | 
| - uint32 bitrate_kbit = bitrate / 1000; | 
| - if (config_.rc_target_bitrate == bitrate_kbit) | 
| - return; | 
| - | 
| - config_.rc_target_bitrate = bitrate_kbit; | 
| - if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) | 
| + if (!codec_config_->UpdateBitrate(&encoder_, bitrate)) | 
| NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | 
| } | 
| @@ -312,6 +405,16 @@ VideoEncoderShim::GetSupportedProfiles() { | 
| profiles.push_back(profile); | 
| } | 
| + ret = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &config, 0); | 
| + if (ret == VPX_CODEC_OK) { | 
| + media::VideoEncodeAccelerator::SupportedProfile profile; | 
| + profile.profile = media::VP9PROFILE_ANY; | 
| + profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); | 
| + profile.max_framerate_numerator = config.g_timebase.den; | 
| + profile.max_framerate_denominator = config.g_timebase.num; | 
| + profiles.push_back(profile); | 
| + } | 
| + | 
| return profiles; | 
| } | 
| @@ -327,11 +430,15 @@ bool VideoEncoderShim::Initialize( | 
| if (input_format != media::PIXEL_FORMAT_I420) | 
| return false; | 
| + scoped_ptr<CodecConfig> codec_desc = PP_ToVpxVideoCodecIface(output_profile); | 
| + if (!codec_desc) | 
| + return false; | 
| + | 
| media_task_runner_->PostTask( | 
| FROM_HERE, | 
| base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, | 
| base::Unretained(encoder_impl_.get()), input_format, | 
| - input_visible_size, output_profile, initial_bitrate)); | 
| + input_visible_size, codec_desc.release(), initial_bitrate)); | 
| return true; | 
| } |