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 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |