Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / content / renderer / pepper / video_encoder_shim.cc
blob94c4ee7c2f157f23cf8a457c899086ccf3518e5b
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
3 // found in the LICENSE file.
5 #include "content/renderer/pepper/video_encoder_shim.h"
7 #include <inttypes.h>
9 #include <deque>
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/location.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "content/renderer/pepper/pepper_video_encoder_host.h"
17 #include "content/renderer/render_thread_impl.h"
18 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
19 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
20 #include "ui/gfx/geometry/size.h"
22 namespace content {
24 namespace {
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
28 // 1080p (%64 pixels blocks), this seems like a reasonable limit for
29 // software encoding.
30 const int32_t kMaxWidth = 1920;
31 const int32_t kMaxHeight = 1088;
33 // Bitstream buffer size.
34 const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024;
36 // Number of frames needs at any given time.
37 const uint32_t kInputFrameCount = 1;
39 // Default speed for the encoder. Increases the CPU usage as the value
40 // is more negative (VP8 valid range: -16..16, VP9 valid range:
41 // -8..8), using the same value as WebRTC.
42 const int32_t kVp8DefaultCpuUsed = -6;
44 // Default quantizer min/max values (same values as WebRTC).
45 const int32_t kVp8DefaultMinQuantizer = 2;
46 const int32_t kVp8DefaultMaxQuantizer = 52;
48 // For VP9, the following 3 values are the same values as remoting.
49 const int32_t kVp9DefaultCpuUsed = 6;
51 const int32_t kVp9DefaultMinQuantizer = 20;
52 const int32_t kVp9DefaultMaxQuantizer = 30;
54 // VP9 adaptive quantization strategy (same as remoting (live video
55 // conferencing)).
56 const int kVp9AqModeCyclicRefresh = 3;
58 void GetVpxCodecParameters(media::VideoCodecProfile codec,
59 vpx_codec_iface_t** vpx_codec,
60 int32_t* min_quantizer,
61 int32_t* max_quantizer,
62 int32_t* cpu_used) {
63 switch (codec) {
64 case media::VP8PROFILE_ANY:
65 *vpx_codec = vpx_codec_vp8_cx();
66 *min_quantizer = kVp8DefaultMinQuantizer;
67 *max_quantizer = kVp8DefaultMaxQuantizer;
68 *cpu_used = kVp8DefaultCpuUsed;
69 break;
70 case media::VP9PROFILE_ANY:
71 *vpx_codec = vpx_codec_vp9_cx();
72 *min_quantizer = kVp9DefaultMinQuantizer;
73 *max_quantizer = kVp9DefaultMaxQuantizer;
74 *cpu_used = kVp9DefaultCpuUsed;
75 break;
76 default:
77 *vpx_codec = nullptr;
78 *min_quantizer = 0;
79 *max_quantizer = 0;
80 *cpu_used = 0;
81 NOTREACHED();
85 } // namespace
87 class VideoEncoderShim::EncoderImpl {
88 public:
89 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim);
90 ~EncoderImpl();
92 void Initialize(media::VideoPixelFormat input_format,
93 const gfx::Size& input_visible_size,
94 media::VideoCodecProfile output_profile,
95 uint32 initial_bitrate);
96 void Encode(const scoped_refptr<media::VideoFrame>& frame,
97 bool force_keyframe);
98 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer,
99 uint8_t* mem);
100 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
101 void Stop();
103 private:
104 struct PendingEncode {
105 PendingEncode(const scoped_refptr<media::VideoFrame>& frame,
106 bool force_keyframe)
107 : frame(frame), force_keyframe(force_keyframe) {}
108 ~PendingEncode() {}
110 scoped_refptr<media::VideoFrame> frame;
111 bool force_keyframe;
114 struct BitstreamBuffer {
115 BitstreamBuffer(const media::BitstreamBuffer buffer, uint8_t* mem)
116 : buffer(buffer), mem(mem) {}
117 ~BitstreamBuffer() {}
119 media::BitstreamBuffer buffer;
120 uint8_t* mem;
123 void DoEncode();
124 void NotifyError(media::VideoEncodeAccelerator::Error error);
126 base::WeakPtr<VideoEncoderShim> shim_;
127 scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
129 bool initialized_;
131 // Libvpx internal objects. Only valid if |initialized_| is true.
132 vpx_codec_enc_cfg_t config_;
133 vpx_codec_ctx_t encoder_;
135 uint32 framerate_;
137 std::deque<PendingEncode> frames_;
138 std::deque<BitstreamBuffer> buffers_;
141 VideoEncoderShim::EncoderImpl::EncoderImpl(
142 const base::WeakPtr<VideoEncoderShim>& shim)
143 : shim_(shim),
144 renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()),
145 initialized_(false) {
148 VideoEncoderShim::EncoderImpl::~EncoderImpl() {
149 if (initialized_)
150 vpx_codec_destroy(&encoder_);
153 void VideoEncoderShim::EncoderImpl::Initialize(
154 media::VideoPixelFormat input_format,
155 const gfx::Size& input_visible_size,
156 media::VideoCodecProfile output_profile,
157 uint32 initial_bitrate) {
158 gfx::Size coded_size =
159 media::VideoFrame::PlaneSize(input_format, 0, input_visible_size);
161 vpx_codec_iface_t* vpx_codec;
162 int32_t min_quantizer, max_quantizer, cpu_used;
163 GetVpxCodecParameters(output_profile, &vpx_codec, &min_quantizer,
164 &max_quantizer, &cpu_used);
166 // Populate encoder configuration with default values.
167 if (vpx_codec_enc_config_default(vpx_codec, &config_, 0) != VPX_CODEC_OK) {
168 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
169 return;
172 config_.g_w = input_visible_size.width();
173 config_.g_h = input_visible_size.height();
175 framerate_ = config_.g_timebase.den;
177 config_.g_lag_in_frames = 0;
178 config_.g_timebase.num = 1;
179 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond;
180 config_.rc_target_bitrate = initial_bitrate / 1000;
181 config_.rc_min_quantizer = min_quantizer;
182 config_.rc_max_quantizer = max_quantizer;
184 vpx_codec_flags_t flags = 0;
185 if (vpx_codec_enc_init(&encoder_, vpx_codec, &config_, flags) !=
186 VPX_CODEC_OK) {
187 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
188 return;
190 initialized_ = true;
192 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK) {
193 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
194 return;
197 if (vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, cpu_used) !=
198 VPX_CODEC_OK) {
199 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
200 return;
203 if (output_profile == media::VP9PROFILE_ANY) {
204 if (vpx_codec_control(&encoder_, VP9E_SET_AQ_MODE,
205 kVp9AqModeCyclicRefresh) != VPX_CODEC_OK) {
206 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
207 return;
211 renderer_task_runner_->PostTask(
212 FROM_HERE,
213 base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_,
214 kInputFrameCount, coded_size, kBitstreamBufferSize));
217 void VideoEncoderShim::EncoderImpl::Encode(
218 const scoped_refptr<media::VideoFrame>& frame,
219 bool force_keyframe) {
220 frames_.push_back(PendingEncode(frame, force_keyframe));
221 DoEncode();
224 void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer(
225 const media::BitstreamBuffer& buffer,
226 uint8_t* mem) {
227 buffers_.push_back(BitstreamBuffer(buffer, mem));
228 DoEncode();
231 void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange(
232 uint32 bitrate,
233 uint32 framerate) {
234 framerate_ = framerate;
236 uint32 bitrate_kbit = bitrate / 1000;
237 if (config_.rc_target_bitrate == bitrate_kbit)
238 return;
240 config_.rc_target_bitrate = bitrate_kbit;
241 if (vpx_codec_enc_config_set(&encoder_, &config_) != VPX_CODEC_OK)
242 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
245 void VideoEncoderShim::EncoderImpl::Stop() {
246 // Release frames on the renderer thread.
247 while (!frames_.empty()) {
248 PendingEncode frame = frames_.front();
249 frames_.pop_front();
251 frame.frame->AddRef();
252 media::VideoFrame* raw_frame = frame.frame.get();
253 frame.frame = nullptr;
254 renderer_task_runner_->ReleaseSoon(FROM_HERE, raw_frame);
256 buffers_.clear();
259 void VideoEncoderShim::EncoderImpl::DoEncode() {
260 while (!frames_.empty() && !buffers_.empty()) {
261 PendingEncode frame = frames_.front();
262 frames_.pop_front();
264 // Wrapper for vpx_codec_encode() to access the YUV data in the
265 // |video_frame|. Only the VISIBLE rectangle within |video_frame|
266 // is exposed to the codec.
267 vpx_image_t vpx_image;
268 vpx_image_t* const result = vpx_img_wrap(
269 &vpx_image, VPX_IMG_FMT_I420, frame.frame->visible_rect().width(),
270 frame.frame->visible_rect().height(), 1,
271 frame.frame->data(media::VideoFrame::kYPlane));
272 DCHECK_EQ(result, &vpx_image);
273 vpx_image.planes[VPX_PLANE_Y] =
274 frame.frame->visible_data(media::VideoFrame::kYPlane);
275 vpx_image.planes[VPX_PLANE_U] =
276 frame.frame->visible_data(media::VideoFrame::kUPlane);
277 vpx_image.planes[VPX_PLANE_V] =
278 frame.frame->visible_data(media::VideoFrame::kVPlane);
279 vpx_image.stride[VPX_PLANE_Y] =
280 frame.frame->stride(media::VideoFrame::kYPlane);
281 vpx_image.stride[VPX_PLANE_U] =
282 frame.frame->stride(media::VideoFrame::kUPlane);
283 vpx_image.stride[VPX_PLANE_V] =
284 frame.frame->stride(media::VideoFrame::kVPlane);
286 vpx_codec_flags_t flags = 0;
287 if (frame.force_keyframe)
288 flags = VPX_EFLAG_FORCE_KF;
290 const base::TimeDelta frame_duration =
291 base::TimeDelta::FromSecondsD(1.0 / framerate_);
292 if (vpx_codec_encode(&encoder_, &vpx_image, 0,
293 frame_duration.InMicroseconds(), flags,
294 VPX_DL_REALTIME) != VPX_CODEC_OK) {
295 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
296 return;
299 const vpx_codec_cx_pkt_t* packet = nullptr;
300 vpx_codec_iter_t iter = nullptr;
301 while ((packet = vpx_codec_get_cx_data(&encoder_, &iter)) != nullptr) {
302 if (packet->kind != VPX_CODEC_CX_FRAME_PKT)
303 continue;
305 BitstreamBuffer buffer = buffers_.front();
306 buffers_.pop_front();
308 CHECK(buffer.buffer.size() >= packet->data.frame.sz);
309 memcpy(buffer.mem, packet->data.frame.buf, packet->data.frame.sz);
311 // Pass the media::VideoFrame back to the renderer thread so it's
312 // freed on the right thread.
313 renderer_task_runner_->PostTask(
314 FROM_HERE,
315 base::Bind(&VideoEncoderShim::OnBitstreamBufferReady, shim_,
316 frame.frame, buffer.buffer.id(),
317 base::checked_cast<size_t>(packet->data.frame.sz),
318 (packet->data.frame.flags & VPX_FRAME_IS_KEY) != 0));
319 break; // Done, since all data is provided in one CX_FRAME_PKT packet.
324 void VideoEncoderShim::EncoderImpl::NotifyError(
325 media::VideoEncodeAccelerator::Error error) {
326 renderer_task_runner_->PostTask(
327 FROM_HERE, base::Bind(&VideoEncoderShim::OnNotifyError, shim_, error));
328 Stop();
331 VideoEncoderShim::VideoEncoderShim(PepperVideoEncoderHost* host)
332 : host_(host),
333 media_task_runner_(
334 RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
335 weak_ptr_factory_(this) {
336 encoder_impl_.reset(new EncoderImpl(weak_ptr_factory_.GetWeakPtr()));
339 VideoEncoderShim::~VideoEncoderShim() {
340 DCHECK(RenderThreadImpl::current());
342 media_task_runner_->PostTask(
343 FROM_HERE, base::Bind(&VideoEncoderShim::EncoderImpl::Stop,
344 base::Owned(encoder_impl_.release())));
347 media::VideoEncodeAccelerator::SupportedProfiles
348 VideoEncoderShim::GetSupportedProfiles() {
349 media::VideoEncodeAccelerator::SupportedProfiles profiles;
351 // Get the default VP8 config from Libvpx.
352 vpx_codec_enc_cfg_t config;
353 vpx_codec_err_t ret =
354 vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config, 0);
355 if (ret == VPX_CODEC_OK) {
356 media::VideoEncodeAccelerator::SupportedProfile profile;
357 profile.profile = media::VP8PROFILE_ANY;
358 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight);
359 // Libvpx and media::VideoEncodeAccelerator are using opposite
360 // notions of denominator/numerator.
361 profile.max_framerate_numerator = config.g_timebase.den;
362 profile.max_framerate_denominator = config.g_timebase.num;
363 profiles.push_back(profile);
366 ret = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), &config, 0);
367 if (ret == VPX_CODEC_OK) {
368 media::VideoEncodeAccelerator::SupportedProfile profile;
369 profile.profile = media::VP9PROFILE_ANY;
370 profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight);
371 profile.max_framerate_numerator = config.g_timebase.den;
372 profile.max_framerate_denominator = config.g_timebase.num;
373 profiles.push_back(profile);
376 return profiles;
379 bool VideoEncoderShim::Initialize(
380 media::VideoPixelFormat input_format,
381 const gfx::Size& input_visible_size,
382 media::VideoCodecProfile output_profile,
383 uint32 initial_bitrate,
384 media::VideoEncodeAccelerator::Client* client) {
385 DCHECK(RenderThreadImpl::current());
386 DCHECK_EQ(client, host_);
388 if (input_format != media::PIXEL_FORMAT_I420)
389 return false;
391 if (output_profile != media::VP8PROFILE_ANY &&
392 output_profile != media::VP9PROFILE_ANY)
393 return false;
395 media_task_runner_->PostTask(
396 FROM_HERE,
397 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize,
398 base::Unretained(encoder_impl_.get()), input_format,
399 input_visible_size, output_profile, initial_bitrate));
401 return true;
404 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame,
405 bool force_keyframe) {
406 DCHECK(RenderThreadImpl::current());
408 media_task_runner_->PostTask(
409 FROM_HERE,
410 base::Bind(&VideoEncoderShim::EncoderImpl::Encode,
411 base::Unretained(encoder_impl_.get()), frame, force_keyframe));
414 void VideoEncoderShim::UseOutputBitstreamBuffer(
415 const media::BitstreamBuffer& buffer) {
416 DCHECK(RenderThreadImpl::current());
418 media_task_runner_->PostTask(
419 FROM_HERE,
420 base::Bind(&VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer,
421 base::Unretained(encoder_impl_.get()), buffer,
422 host_->ShmHandleToAddress(buffer.id())));
425 void VideoEncoderShim::RequestEncodingParametersChange(uint32 bitrate,
426 uint32 framerate) {
427 DCHECK(RenderThreadImpl::current());
429 media_task_runner_->PostTask(
430 FROM_HERE,
431 base::Bind(
432 &VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange,
433 base::Unretained(encoder_impl_.get()), bitrate, framerate));
436 void VideoEncoderShim::Destroy() {
437 DCHECK(RenderThreadImpl::current());
439 delete this;
442 void VideoEncoderShim::OnRequireBitstreamBuffers(
443 unsigned int input_count,
444 const gfx::Size& input_coded_size,
445 size_t output_buffer_size) {
446 DCHECK(RenderThreadImpl::current());
448 host_->RequireBitstreamBuffers(input_count, input_coded_size,
449 output_buffer_size);
452 void VideoEncoderShim::OnBitstreamBufferReady(
453 scoped_refptr<media::VideoFrame> frame,
454 int32 bitstream_buffer_id,
455 size_t payload_size,
456 bool key_frame) {
457 DCHECK(RenderThreadImpl::current());
459 host_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
462 void VideoEncoderShim::OnNotifyError(
463 media::VideoEncodeAccelerator::Error error) {
464 DCHECK(RenderThreadImpl::current());
466 host_->NotifyError(error);
469 } // namespace content