Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(505)

Side by Side Diff: content/renderer/pepper/video_encoder_shim.cc

Issue 1132833002: pepper: add software vp9 encoder support to PPB_VideoEncoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Tune VP9 parameters Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 namespace {
40
41 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
42 public:
43 virtual ~CodecConfig() {}
44
45 bool InitializeEncoder(vpx_codec_ctx_t* encoder,
46 const gfx::Size& size,
47 uint32 initial_bitrate,
48 uint32* initial_framerate,
49 bool* encoder_initialized);
50
51 bool UpdateBitrate(vpx_codec_ctx_t* encoder, uint32 bitrate);
52
53 protected:
54 CodecConfig(vpx_codec_iface_t* vpx_codec,
55 int32_t cpu_used,
56 uint32_t min_quantizer,
57 uint32_t max_quantizer);
58
59 // A special initialization phase to be defined per codec.
60 virtual bool InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) = 0;
61
62 // Libvpx codec interface.
63 vpx_codec_iface_t* vpx_codec_;
64
65 // Libvpx configuration parameters of the codec.
66 vpx_codec_enc_cfg_t vpx_config_;
67
68 // Default speed for the encoder. Increases the CPU usage as the
69 // value is more negative (VP8 valid range: -16..16, VP9 valid
70 // range: -8..8).
71 int32_t cpu_used_;
72
73 // Default quantizer min/max values.
74 uint32_t min_quantizer_;
75 uint32_t max_quantizer_;
76 };
77
78 CodecConfig::CodecConfig(vpx_codec_iface_t* vpx_codec,
79 int32_t cpu_used,
80 uint32_t min_quantizer,
81 uint32_t max_quantizer)
82 : vpx_codec_(vpx_codec),
83 cpu_used_(cpu_used),
84 min_quantizer_(min_quantizer),
85 max_quantizer_(max_quantizer) {
86 vpx_codec_err_t err =
87 vpx_codec_enc_config_default(vpx_codec_, &vpx_config_, 0);
88 DCHECK_EQ(VPX_CODEC_OK, err);
89 }
90
91 bool CodecConfig::InitializeEncoder(vpx_codec_ctx_t* encoder,
92 const gfx::Size& size,
93 uint32 initial_bitrate,
94 uint32* initial_framerate,
95 bool* encoder_initialized) {
96 *initial_framerate = vpx_config_.g_timebase.den;
97
98 vpx_config_.g_w = size.width();
99 vpx_config_.g_h = size.height();
100
101 vpx_config_.g_lag_in_frames = 0;
102 vpx_config_.g_timebase.num = 1;
103 vpx_config_.g_timebase.den = base::Time::kMicrosecondsPerSecond;
104 vpx_config_.rc_target_bitrate = initial_bitrate / 1000;
105 vpx_config_.rc_min_quantizer = min_quantizer_;
106 vpx_config_.rc_max_quantizer = max_quantizer_;
107
108 vpx_codec_flags_t flags = 0;
109 if (vpx_codec_enc_init(encoder, vpx_codec_, &vpx_config_, flags) !=
110 VPX_CODEC_OK) {
111 return false;
112 }
113 *encoder_initialized = true;
114
115 if (vpx_codec_enc_config_set(encoder, &vpx_config_) != VPX_CODEC_OK)
116 return false;
117
118 if (vpx_codec_control(encoder, VP8E_SET_CPUUSED, cpu_used_) != VPX_CODEC_OK) {
119 return false;
120 }
121
122 return InitializeEncoderForCodec(encoder);
123 }
124
125 bool CodecConfig::UpdateBitrate(vpx_codec_ctx_t* encoder, uint32 bitrate) {
126 uint32 bitrate_kbit = bitrate / 1000;
127 if (vpx_config_.rc_target_bitrate == bitrate_kbit)
128 return true;
129
130 vpx_config_.rc_target_bitrate = bitrate_kbit;
131 return vpx_codec_enc_config_set(encoder, &vpx_config_) == VPX_CODEC_OK;
132 }
133
134 // VP8 configuration.
135 class Vp8CodecConfig : public CodecConfig {
136 public:
137 Vp8CodecConfig() : CodecConfig(vpx_codec_vp8_cx(), -6, 2, 52) {}
138 ~Vp8CodecConfig() override {}
139
140 private:
141 bool InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) override {
142 return true;
143 }
144 };
145
146 // VP9 configuration.
147 class Vp9CodecConfig : public CodecConfig {
148 public:
149 Vp9CodecConfig() : CodecConfig(vpx_codec_vp9_cx(), 6, 20, 30) {}
150 ~Vp9CodecConfig() override {}
151
152 private:
153 bool InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) override;
154 };
155
156 bool Vp9CodecConfig::InitializeEncoderForCodec(vpx_codec_ctx_t* encoder) {
157 return vpx_codec_control(encoder, VP9E_SET_AQ_MODE, 3) == VPX_CODEC_OK;
158 }
159
160 scoped_ptr<CodecConfig> PP_ToVpxVideoCodecIface(
161 media::VideoCodecProfile codec) {
162 switch (codec) {
163 case media::VP8PROFILE_ANY:
164 // Using same parameters as WebRTC (see media/cast/sender).
165 return make_scoped_ptr(new Vp8CodecConfig());
166 case media::VP9PROFILE_ANY:
167 return make_scoped_ptr(new Vp9CodecConfig());
168 ;
169 default:
170 return scoped_ptr<CodecConfig>();
171 }
172 }
173
174 } // namespace
175
47 class VideoEncoderShim::EncoderImpl { 176 class VideoEncoderShim::EncoderImpl {
48 public: 177 public:
49 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim); 178 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim);
50 ~EncoderImpl(); 179 ~EncoderImpl();
51 180
52 void Initialize(media::VideoPixelFormat input_format, 181 void Initialize(media::VideoPixelFormat input_format,
53 const gfx::Size& input_visible_size, 182 const gfx::Size& input_visible_size,
54 media::VideoCodecProfile output_profile, 183 CodecConfig* codec_config,
55 uint32 initial_bitrate); 184 uint32 initial_bitrate);
56 void Encode(const scoped_refptr<media::VideoFrame>& frame, 185 void Encode(const scoped_refptr<media::VideoFrame>& frame,
57 bool force_keyframe); 186 bool force_keyframe);
58 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer, 187 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer,
59 uint8_t* mem); 188 uint8_t* mem);
60 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate); 189 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
61 void Stop(); 190 void Stop();
62 191
63 private: 192 private:
64 struct PendingEncode { 193 struct PendingEncode {
(...skipping 14 matching lines...) Expand all
79 media::BitstreamBuffer buffer; 208 media::BitstreamBuffer buffer;
80 uint8_t* mem; 209 uint8_t* mem;
81 }; 210 };
82 211
83 void DoEncode(); 212 void DoEncode();
84 void NotifyError(media::VideoEncodeAccelerator::Error error); 213 void NotifyError(media::VideoEncodeAccelerator::Error error);
85 214
86 base::WeakPtr<VideoEncoderShim> shim_; 215 base::WeakPtr<VideoEncoderShim> shim_;
87 scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_; 216 scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
88 217
89 bool initialized_; 218 // Libvpx internal objects. Only valid if |codec_config_| is not null.
219 vpx_codec_ctx_t encoder_;
90 220
91 // Libvpx internal objects. Only valid if |initialized_| is true. 221 scoped_ptr<CodecConfig> codec_config_;
92 vpx_codec_enc_cfg_t config_;
93 vpx_codec_ctx_t encoder_;
94 222
95 uint32 framerate_; 223 uint32 framerate_;
96 224
97 std::deque<PendingEncode> frames_; 225 std::deque<PendingEncode> frames_;
98 std::deque<BitstreamBuffer> buffers_; 226 std::deque<BitstreamBuffer> buffers_;
99 }; 227 };
100 228
101 VideoEncoderShim::EncoderImpl::EncoderImpl( 229 VideoEncoderShim::EncoderImpl::EncoderImpl(
102 const base::WeakPtr<VideoEncoderShim>& shim) 230 const base::WeakPtr<VideoEncoderShim>& shim)
103 : shim_(shim), 231 : shim_(shim), renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
104 renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()),
105 initialized_(false) {
106 }
107 232
108 VideoEncoderShim::EncoderImpl::~EncoderImpl() { 233 VideoEncoderShim::EncoderImpl::~EncoderImpl() {
109 if (initialized_) 234 if (codec_config_)
110 vpx_codec_destroy(&encoder_); 235 vpx_codec_destroy(&encoder_);
111 } 236 }
112 237
113 void VideoEncoderShim::EncoderImpl::Initialize( 238 void VideoEncoderShim::EncoderImpl::Initialize(
114 media::VideoPixelFormat input_format, 239 media::VideoPixelFormat input_format,
115 const gfx::Size& input_visible_size, 240 const gfx::Size& input_visible_size,
116 media::VideoCodecProfile output_profile, 241 CodecConfig* codec_config,
117 uint32 initial_bitrate) { 242 uint32 initial_bitrate) {
243 DCHECK(codec_config);
118 gfx::Size coded_size = 244 gfx::Size coded_size =
119 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size); 245 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size);
120 246
121 // Populate encoder configuration with default values. 247 codec_config_.reset(codec_config);
122 if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0) != 248
123 VPX_CODEC_OK) { 249 bool encoder_initialized = false;
250 if (!codec_config_->InitializeEncoder(&encoder_, coded_size, initial_bitrate,
251 &framerate_, &encoder_initialized)) {
252 if (!encoder_initialized)
253 codec_config_.reset();
124 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); 254 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
125 return; 255 return;
126 } 256 }
127
128 config_.g_threads = 1;
129 config_.g_w = input_visible_size.width();
130 config_.g_h = input_visible_size.height();
131
132 framerate_ = config_.g_timebase.den;
133
134 config_.g_lag_in_frames = 0;
135 config_.g_timebase.num = 1;
136 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond;
137 config_.rc_target_bitrate = initial_bitrate / 1000;
138 config_.rc_min_quantizer = kDefaultMinQuantizer;
139 config_.rc_max_quantizer = kDefaultMaxQuantizer;
140
141 vpx_codec_flags_t flags = 0;
142 if (vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags) !=
143 VPX_CODEC_OK) {
144 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
145 return;
146 }
147 initialized_ = true;
148
149 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) {
150 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
151 return;
152 }
153
154 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, kDefaultCpuUsed) !=
155 VPX_CODEC_OK) {
156 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
157 return;
158 }
159 257
160 renderer_task_runner_->PostTask( 258 renderer_task_runner_->PostTask(
161 FROM_HERE, 259 FROM_HERE,
162 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, 260 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_,
163 kInputFrameCount, coded_size, kBitstreamBufferSize)); 261 kInputFrameCount, coded_size, kBitstreamBufferSize));
164 } 262 }
165 263
166 void VideoEncoderShim::EncoderImpl::Encode( 264 void VideoEncoderShim::EncoderImpl::Encode(
167 const scoped_refptr<media::VideoFrame>& frame, 265 const scoped_refptr<media::VideoFrame>& frame,
168 bool force_keyframe) { 266 bool force_keyframe) {
169 frames_.push_back(PendingEncode(frame, force_keyframe)); 267 frames_.push_back(PendingEncode(frame, force_keyframe));
170 DoEncode(); 268 DoEncode();
171 } 269 }
172 270
173 void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer( 271 void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer(
174 const media::BitstreamBuffer& buffer, 272 const media::BitstreamBuffer& buffer,
175 uint8_t* mem) { 273 uint8_t* mem) {
176 buffers_.push_back(BitstreamBuffer(buffer, mem)); 274 buffers_.push_back(BitstreamBuffer(buffer, mem));
177 DoEncode(); 275 DoEncode();
178 } 276 }
179 277
180 void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange( 278 void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange(
181 uint32 bitrate, 279 uint32 bitrate,
182 uint32 framerate) { 280 uint32 framerate) {
183 framerate_ = framerate; 281 framerate_ = framerate;
184 282
185 uint32 bitrate_kbit = bitrate / 1000; 283 if (!codec_config_->UpdateBitrate(&encoder_, bitrate))
186 if (config_.rc_target_bitrate == bitrate_kbit)
187 return;
188
189 config_.rc_target_bitrate = bitrate_kbit;
190 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK)
191 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); 284 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
192 } 285 }
193 286
194 void VideoEncoderShim::EncoderImpl::Stop() { 287 void VideoEncoderShim::EncoderImpl::Stop() {
195 // Release frames on the renderer thread. 288 // Release frames on the renderer thread.
196 while (!frames_.empty()) { 289 while (!frames_.empty()) {
197 PendingEncode frame = frames_.front(); 290 PendingEncode frame = frames_.front();
198 frames_.pop_front(); 291 frames_.pop_front();
199 292
200 frame.frame->AddRef(); 293 frame.frame->AddRef();
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 media::VideoEncodeAccelerator::SupportedProfile profile; 398 media::VideoEncodeAccelerator::SupportedProfile profile;
306 profile.profile = media::VP8PROFILE_ANY; 399 profile.profile = media::VP8PROFILE_ANY;
307 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight); 400 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight);
308 // Libvpx and media::VideoEncodeAccelerator are using opposite 401 // Libvpx and media::VideoEncodeAccelerator are using opposite
309 // notions of denominator/numerator. 402 // notions of denominator/numerator.
310 profile.max_framerate_numerator = config.g_timebase.den; 403 profile.max_framerate_numerator = config.g_timebase.den;
311 profile.max_framerate_denominator = config.g_timebase.num; 404 profile.max_framerate_denominator = config.g_timebase.num;
312 profiles.push_back(profile); 405 profiles.push_back(profile);
313 } 406 }
314 407
408 ret = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &config, 0);
409 if (ret == VPX_CODEC_OK) {
410 media::VideoEncodeAccelerator::SupportedProfile profile;
411 profile.profile = media::VP9PROFILE_ANY;
412 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight);
413 profile.max_framerate_numerator = config.g_timebase.den;
414 profile.max_framerate_denominator = config.g_timebase.num;
415 profiles.push_back(profile);
416 }
417
315 return profiles; 418 return profiles;
316 } 419 }
317 420
318 bool VideoEncoderShim::Initialize( 421 bool VideoEncoderShim::Initialize(
319 media::VideoPixelFormat input_format, 422 media::VideoPixelFormat input_format,
320 const gfx::Size& input_visible_size, 423 const gfx::Size& input_visible_size,
321 media::VideoCodecProfile output_profile, 424 media::VideoCodecProfile output_profile,
322 uint32 initial_bitrate, 425 uint32 initial_bitrate,
323 media::VideoEncodeAccelerator::Client* client) { 426 media::VideoEncodeAccelerator::Client* client) {
324 DCHECK(RenderThreadImpl::current()); 427 DCHECK(RenderThreadImpl::current());
325 DCHECK_EQ(client, host_); 428 DCHECK_EQ(client, host_);
326 429
327 if (input_format != media::PIXEL_FORMAT_I420) 430 if (input_format != media::PIXEL_FORMAT_I420)
328 return false; 431 return false;
329 432
433 scoped_ptr<CodecConfig> codec_desc = PP_ToVpxVideoCodecIface(output_profile);
434 if (!codec_desc)
435 return false;
436
330 media_task_runner_->PostTask( 437 media_task_runner_->PostTask(
331 FROM_HERE, 438 FROM_HERE,
332 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, 439 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize,
333 base::Unretained(encoder_impl_.get()), input_format, 440 base::Unretained(encoder_impl_.get()), input_format,
334 input_visible_size, output_profile, initial_bitrate)); 441 input_visible_size, codec_desc.release(), initial_bitrate));
335 442
336 return true; 443 return true;
337 } 444 }
338 445
339 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, 446 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame,
340 bool force_keyframe) { 447 bool force_keyframe) {
341 DCHECK(RenderThreadImpl::current()); 448 DCHECK(RenderThreadImpl::current());
342 449
343 media_task_runner_->PostTask( 450 media_task_runner_->PostTask(
344 FROM_HERE, 451 FROM_HERE,
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 } 502 }
396 503
397 void VideoEncoderShim::OnNotifyError( 504 void VideoEncoderShim::OnNotifyError(
398 media::VideoEncodeAccelerator::Error error) { 505 media::VideoEncodeAccelerator::Error error) {
399 DCHECK(RenderThreadImpl::current()); 506 DCHECK(RenderThreadImpl::current());
400 507
401 host_->NotifyError(error); 508 host_->NotifyError(error);
402 } 509 }
403 510
404 } // namespace content 511 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | native_client_sdk/src/examples/api/video_encode/video_encode.cc » ('j') | ppapi/tests/test_video_encoder.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698