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