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