Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / media / cast / sender / vp8_encoder.cc
blob97139e8d84d6609f23402033de96edef7c4d368c
1 // Copyright 2014 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 "media/cast/sender/vp8_encoder.h"
7 #include "base/logging.h"
8 #include "media/base/video_frame.h"
9 #include "media/cast/cast_defines.h"
10 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
12 namespace media {
13 namespace cast {
15 namespace {
17 // After a pause in the video stream, what is the maximum duration amount to
18 // pass to the encoder for the next frame (in terms of 1/max_fps sized periods)?
19 // This essentially controls the encoded size of the first frame that follows a
20 // pause in the video stream.
21 const int kRestartFramePeriods = 3;
23 } // namespace
25 Vp8Encoder::Vp8Encoder(const VideoSenderConfig& video_config)
26 : cast_config_(video_config),
27 use_multiple_video_buffers_(
28 cast_config_.max_number_of_video_buffers_used ==
29 kNumberOfVp8VideoBuffers),
30 key_frame_requested_(true),
31 bitrate_kbit_(cast_config_.start_bitrate / 1000),
32 last_encoded_frame_id_(kStartFrameId),
33 last_acked_frame_id_(kStartFrameId),
34 undroppable_frames_(0) {
35 config_.g_timebase.den = 0; // Not initialized.
37 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
38 buffer_state_[i].frame_id = last_encoded_frame_id_;
39 buffer_state_[i].state = kBufferStartState;
42 // VP8 have 3 buffers available for prediction, with
43 // max_number_of_video_buffers_used set to 1 we maximize the coding efficiency
44 // however in this mode we can not skip frames in the receiver to catch up
45 // after a temporary network outage; with max_number_of_video_buffers_used
46 // set to 3 we allow 2 frames to be skipped by the receiver without error
47 // propagation.
48 DCHECK(cast_config_.max_number_of_video_buffers_used == 1 ||
49 cast_config_.max_number_of_video_buffers_used ==
50 kNumberOfVp8VideoBuffers)
51 << "Invalid argument";
53 thread_checker_.DetachFromThread();
56 Vp8Encoder::~Vp8Encoder() {
57 DCHECK(thread_checker_.CalledOnValidThread());
58 if (is_initialized())
59 vpx_codec_destroy(&encoder_);
62 void Vp8Encoder::Initialize() {
63 DCHECK(thread_checker_.CalledOnValidThread());
64 DCHECK(!is_initialized());
65 // The encoder will be created/configured when the first frame encode is
66 // requested.
69 void Vp8Encoder::ConfigureForNewFrameSize(const gfx::Size& frame_size) {
70 if (is_initialized()) {
71 // Workaround for VP8 bug: If the new size is strictly less-than-or-equal to
72 // the old size, in terms of area, the existing encoder instance can
73 // continue. Otherwise, completely tear-down and re-create a new encoder to
74 // avoid a shutdown crash.
75 if (frame_size.GetArea() <= gfx::Size(config_.g_w, config_.g_h).GetArea() &&
76 !use_multiple_video_buffers_) {
77 DVLOG(1) << "Continuing to use existing encoder at smaller frame size: "
78 << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> "
79 << frame_size.ToString();
80 config_.g_w = frame_size.width();
81 config_.g_h = frame_size.height();
82 if (vpx_codec_enc_config_set(&encoder_, &config_) == VPX_CODEC_OK)
83 return;
84 DVLOG(1) << "libvpx rejected the attempt to use a smaller frame size in "
85 "the current instance.";
88 DVLOG(1) << "Destroying/Re-Creating encoder for larger frame size: "
89 << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> "
90 << frame_size.ToString();
91 vpx_codec_destroy(&encoder_);
92 } else {
93 DVLOG(1) << "Creating encoder for the first frame; size: "
94 << frame_size.ToString();
97 // Reset multi-buffer mode state.
98 last_acked_frame_id_ = last_encoded_frame_id_;
99 undroppable_frames_ = 0;
100 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
101 buffer_state_[i].frame_id = last_encoded_frame_id_;
102 buffer_state_[i].state = kBufferStartState;
105 // Populate encoder configuration with default values.
106 CHECK_EQ(vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0),
107 VPX_CODEC_OK);
109 config_.g_threads = cast_config_.number_of_encode_threads;
110 config_.g_w = frame_size.width();
111 config_.g_h = frame_size.height();
112 // Set the timebase to match that of base::TimeDelta.
113 config_.g_timebase.num = 1;
114 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond;
115 if (use_multiple_video_buffers_) {
116 // We must enable error resilience when we use multiple buffers, due to
117 // codec requirements.
118 config_.g_error_resilient = 1;
120 // |g_pass| and |g_lag_in_frames| must be "one pass" and zero, respectively,
121 // in order for VP8 to support changing frame sizes during encoding:
122 config_.g_pass = VPX_RC_ONE_PASS;
123 config_.g_lag_in_frames = 0; // Immediate data output for each frame.
125 // Rate control settings.
126 config_.rc_dropframe_thresh = 0; // The encoder may not drop any frames.
127 config_.rc_resize_allowed = 0; // TODO(miu): Why not? Investigate this.
128 config_.rc_end_usage = VPX_CBR;
129 config_.rc_target_bitrate = bitrate_kbit_;
130 config_.rc_min_quantizer = cast_config_.min_qp;
131 config_.rc_max_quantizer = cast_config_.max_qp;
132 // TODO(miu): Revisit these now that the encoder is being successfully
133 // micro-managed.
134 config_.rc_undershoot_pct = 100;
135 config_.rc_overshoot_pct = 15;
136 // TODO(miu): Document why these rc_buf_*_sz values were chosen and/or
137 // research for better values. Should they be computed from the target
138 // playout delay?
139 config_.rc_buf_initial_sz = 500;
140 config_.rc_buf_optimal_sz = 600;
141 config_.rc_buf_sz = 1000;
143 config_.kf_mode = VPX_KF_DISABLED;
145 vpx_codec_flags_t flags = 0;
146 CHECK_EQ(vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags),
147 VPX_CODEC_OK);
149 // Raise the threshold for considering macroblocks as static. The default is
150 // zero, so this setting makes the encoder less sensitive to motion. This
151 // lowers the probability of needing to utilize more CPU to search for motion
152 // vectors.
153 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_STATIC_THRESHOLD, 1),
154 VPX_CODEC_OK);
156 // Improve quality by enabling sets of codec features that utilize more CPU.
157 // The default is zero, with increasingly more CPU to be used as the value is
158 // more negative.
159 // TODO(miu): Document why this value was chosen and expected behaviors.
160 // Should this be dynamic w.r.t. hardware performance?
161 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK);
164 void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame,
165 const base::TimeTicks& reference_time,
166 SenderEncodedFrame* encoded_frame) {
167 DCHECK(thread_checker_.CalledOnValidThread());
168 DCHECK(encoded_frame);
170 // Note: This is used to compute the |deadline_utilization| and so it uses the
171 // real-world clock instead of the CastEnvironment clock, the latter of which
172 // might be simulated.
173 const base::TimeTicks start_time = base::TimeTicks::Now();
175 // Initialize on-demand. Later, if the video frame size has changed, update
176 // the encoder configuration.
177 const gfx::Size frame_size = video_frame->visible_rect().size();
178 if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size)
179 ConfigureForNewFrameSize(frame_size);
181 uint32 latest_frame_id_to_reference;
182 Vp8Buffers buffer_to_update;
183 vpx_codec_flags_t flags = 0;
184 if (key_frame_requested_) {
185 flags = VPX_EFLAG_FORCE_KF;
186 // Self reference.
187 latest_frame_id_to_reference = last_encoded_frame_id_ + 1;
188 // We can pick any buffer as buffer_to_update since we update
189 // them all.
190 buffer_to_update = kLastBuffer;
191 } else {
192 // Reference all acked frames (buffers).
193 latest_frame_id_to_reference = GetCodecReferenceFlags(&flags);
194 buffer_to_update = GetNextBufferToUpdate();
195 GetCodecUpdateFlags(buffer_to_update, &flags);
198 // Wrapper for vpx_codec_encode() to access the YUV data in the |video_frame|.
199 // Only the VISIBLE rectangle within |video_frame| is exposed to the codec.
200 vpx_image_t vpx_image;
201 vpx_image_t* const result = vpx_img_wrap(
202 &vpx_image,
203 VPX_IMG_FMT_I420,
204 frame_size.width(),
205 frame_size.height(),
207 video_frame->data(VideoFrame::kYPlane));
208 DCHECK_EQ(result, &vpx_image);
209 vpx_image.planes[VPX_PLANE_Y] =
210 video_frame->visible_data(VideoFrame::kYPlane);
211 vpx_image.planes[VPX_PLANE_U] =
212 video_frame->visible_data(VideoFrame::kUPlane);
213 vpx_image.planes[VPX_PLANE_V] =
214 video_frame->visible_data(VideoFrame::kVPlane);
215 vpx_image.stride[VPX_PLANE_Y] = video_frame->stride(VideoFrame::kYPlane);
216 vpx_image.stride[VPX_PLANE_U] = video_frame->stride(VideoFrame::kUPlane);
217 vpx_image.stride[VPX_PLANE_V] = video_frame->stride(VideoFrame::kVPlane);
219 // The frame duration given to the VP8 codec affects a number of important
220 // behaviors, including: per-frame bandwidth, CPU time spent encoding,
221 // temporal quality trade-offs, and key/golden/alt-ref frame generation
222 // intervals. Bound the prediction to account for the fact that the frame
223 // rate can be highly variable, including long pauses in the video stream.
224 const base::TimeDelta minimum_frame_duration =
225 base::TimeDelta::FromSecondsD(1.0 / cast_config_.max_frame_rate);
226 const base::TimeDelta maximum_frame_duration =
227 base::TimeDelta::FromSecondsD(static_cast<double>(kRestartFramePeriods) /
228 cast_config_.max_frame_rate);
229 base::TimeDelta predicted_frame_duration;
230 if (!video_frame->metadata()->GetTimeDelta(
231 media::VideoFrameMetadata::FRAME_DURATION,
232 &predicted_frame_duration) ||
233 predicted_frame_duration <= base::TimeDelta()) {
234 // The source of the video frame did not provide the frame duration. Use
235 // the actual amount of time between the current and previous frame as a
236 // prediction for the next frame's duration.
237 predicted_frame_duration = video_frame->timestamp() - last_frame_timestamp_;
239 predicted_frame_duration =
240 std::max(minimum_frame_duration,
241 std::min(maximum_frame_duration, predicted_frame_duration));
242 last_frame_timestamp_ = video_frame->timestamp();
244 // Encode the frame. The presentation time stamp argument here is fixed to
245 // zero to force the encoder to base its single-frame bandwidth calculations
246 // entirely on |predicted_frame_duration| and the target bitrate setting being
247 // micro-managed via calls to UpdateRates().
248 CHECK_EQ(vpx_codec_encode(&encoder_,
249 &vpx_image,
251 predicted_frame_duration.InMicroseconds(),
252 flags,
253 VPX_DL_REALTIME),
254 VPX_CODEC_OK)
255 << "BUG: Invalid arguments passed to vpx_codec_encode().";
257 // Pull data from the encoder, populating a new EncodedFrame.
258 encoded_frame->frame_id = ++last_encoded_frame_id_;
259 const vpx_codec_cx_pkt_t* pkt = NULL;
260 vpx_codec_iter_t iter = NULL;
261 while ((pkt = vpx_codec_get_cx_data(&encoder_, &iter)) != NULL) {
262 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
263 continue;
264 if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
265 // TODO(hubbe): Replace "dependency" with a "bool is_key_frame".
266 encoded_frame->dependency = EncodedFrame::KEY;
267 encoded_frame->referenced_frame_id = encoded_frame->frame_id;
268 } else {
269 encoded_frame->dependency = EncodedFrame::DEPENDENT;
270 // Frame dependencies could theoretically be relaxed by looking for the
271 // VPX_FRAME_IS_DROPPABLE flag, but in recent testing (Oct 2014), this
272 // flag never seems to be set.
273 encoded_frame->referenced_frame_id = latest_frame_id_to_reference;
275 encoded_frame->rtp_timestamp =
276 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency);
277 encoded_frame->reference_time = reference_time;
278 encoded_frame->data.assign(
279 static_cast<const uint8*>(pkt->data.frame.buf),
280 static_cast<const uint8*>(pkt->data.frame.buf) + pkt->data.frame.sz);
281 break; // Done, since all data is provided in one CX_FRAME_PKT packet.
283 DCHECK(!encoded_frame->data.empty())
284 << "BUG: Encoder must provide data since lagged encoding is disabled.";
286 // Compute deadline utilization as the real-world time elapsed divided by the
287 // frame duration.
288 const base::TimeDelta processing_time = base::TimeTicks::Now() - start_time;
289 encoded_frame->deadline_utilization =
290 processing_time.InSecondsF() / predicted_frame_duration.InSecondsF();
292 // Compute lossy utilization. The VP8 encoder took an estimated guess at what
293 // quantizer value would produce an encoded frame size as close to the target
294 // as possible. Now that the frame has been encoded and the number of bytes
295 // is known, the perfect quantizer value (i.e., the one that should have been
296 // used) can be determined. This perfect quantizer is then normalized and
297 // used as the lossy utilization.
298 const double actual_bitrate =
299 encoded_frame->data.size() * 8.0 / predicted_frame_duration.InSecondsF();
300 const double target_bitrate = 1000.0 * config_.rc_target_bitrate;
301 DCHECK_GT(target_bitrate, 0.0);
302 const double bitrate_utilization = actual_bitrate / target_bitrate;
303 int quantizer = -1;
304 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_GET_LAST_QUANTIZER_64, &quantizer),
305 VPX_CODEC_OK);
306 const double perfect_quantizer = bitrate_utilization * std::max(0, quantizer);
307 // Side note: If it was possible for the encoder to encode within the target
308 // number of bytes, the |perfect_quantizer| will be in the range [0.0,63.0].
309 // If it was never possible, the value will be greater than 63.0.
310 encoded_frame->lossy_utilization = perfect_quantizer / 63.0;
312 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame->frame_id
313 << ", sized: " << encoded_frame->data.size()
314 << ", deadline_utilization: " << encoded_frame->deadline_utilization
315 << ", lossy_utilization: " << encoded_frame->lossy_utilization
316 << " (quantizer chosen by the encoder was " << quantizer << ')';
318 if (encoded_frame->dependency == EncodedFrame::KEY) {
319 key_frame_requested_ = false;
321 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
322 buffer_state_[i].state = kBufferSent;
323 buffer_state_[i].frame_id = encoded_frame->frame_id;
325 } else {
326 if (buffer_to_update != kNoBuffer) {
327 buffer_state_[buffer_to_update].state = kBufferSent;
328 buffer_state_[buffer_to_update].frame_id = encoded_frame->frame_id;
333 uint32 Vp8Encoder::GetCodecReferenceFlags(vpx_codec_flags_t* flags) {
334 if (!use_multiple_video_buffers_)
335 return last_encoded_frame_id_;
337 const uint32 kMagicFrameOffset = 512;
338 // We set latest_frame_to_reference to an old frame so that
339 // IsNewerFrameId will work correctly.
340 uint32 latest_frame_to_reference =
341 last_encoded_frame_id_ - kMagicFrameOffset;
343 // Reference all acked frames.
344 // TODO(hubbe): We may also want to allow references to the
345 // last encoded frame, if that frame was assigned to a buffer.
346 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
347 if (buffer_state_[i].state == kBufferAcked) {
348 if (IsNewerFrameId(buffer_state_[i].frame_id,
349 latest_frame_to_reference)) {
350 latest_frame_to_reference = buffer_state_[i].frame_id;
352 } else {
353 switch (i) {
354 case kAltRefBuffer:
355 *flags |= VP8_EFLAG_NO_REF_ARF;
356 break;
357 case kGoldenBuffer:
358 *flags |= VP8_EFLAG_NO_REF_GF;
359 break;
360 case kLastBuffer:
361 *flags |= VP8_EFLAG_NO_REF_LAST;
362 break;
367 if (latest_frame_to_reference ==
368 last_encoded_frame_id_ - kMagicFrameOffset) {
369 // We have nothing to reference, it's kind of like a key frame,
370 // but doesn't reset buffers.
371 latest_frame_to_reference = last_encoded_frame_id_ + 1;
374 return latest_frame_to_reference;
377 Vp8Encoder::Vp8Buffers Vp8Encoder::GetNextBufferToUpdate() {
378 if (!use_multiple_video_buffers_)
379 return kNoBuffer;
381 // The goal here is to make sure that we always keep one ACKed
382 // buffer while trying to get an ACK for a newer buffer as we go.
383 // Here are the rules for which buffer to select for update:
384 // 1. If there is a buffer in state kStartState, use it.
385 // 2. If there is a buffer other than the oldest buffer
386 // which is Acked, use the oldest buffer.
387 // 3. If there are Sent buffers which are older than
388 // latest_acked_frame_, use the oldest one.
389 // 4. If all else fails, just overwrite the newest buffer,
390 // but no more than 3 times in a row.
391 // TODO(hubbe): Figure out if 3 is optimal.
392 // Note, rule 1-3 describe cases where there is a "free" buffer
393 // that we can use. Rule 4 describes what happens when there is
394 // no free buffer available.
396 // Buffers, sorted from oldest frame to newest.
397 Vp8Encoder::Vp8Buffers buffers[kNumberOfVp8VideoBuffers];
399 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
400 Vp8Encoder::Vp8Buffers buffer = static_cast<Vp8Encoder::Vp8Buffers>(i);
402 // Rule 1
403 if (buffer_state_[buffer].state == kBufferStartState) {
404 undroppable_frames_ = 0;
405 return buffer;
407 buffers[buffer] = buffer;
410 // Sorting three elements with selection sort.
411 for (int i = 0; i < kNumberOfVp8VideoBuffers - 1; i++) {
412 for (int j = i + 1; j < kNumberOfVp8VideoBuffers; j++) {
413 if (IsOlderFrameId(buffer_state_[buffers[j]].frame_id,
414 buffer_state_[buffers[i]].frame_id)) {
415 std::swap(buffers[i], buffers[j]);
420 // Rule 2
421 if (buffer_state_[buffers[1]].state == kBufferAcked ||
422 buffer_state_[buffers[2]].state == kBufferAcked) {
423 undroppable_frames_ = 0;
424 return buffers[0];
427 // Rule 3
428 for (int i = 0; i < kNumberOfVp8VideoBuffers; i++) {
429 if (buffer_state_[buffers[i]].state == kBufferSent &&
430 IsOlderFrameId(buffer_state_[buffers[i]].frame_id,
431 last_acked_frame_id_)) {
432 undroppable_frames_ = 0;
433 return buffers[i];
437 // Rule 4
438 if (undroppable_frames_ >= 3) {
439 undroppable_frames_ = 0;
440 return kNoBuffer;
441 } else {
442 undroppable_frames_++;
443 return buffers[kNumberOfVp8VideoBuffers - 1];
447 void Vp8Encoder::GetCodecUpdateFlags(Vp8Buffers buffer_to_update,
448 vpx_codec_flags_t* flags) {
449 if (!use_multiple_video_buffers_)
450 return;
452 // Update at most one buffer, except for key-frames.
453 switch (buffer_to_update) {
454 case kAltRefBuffer:
455 *flags |= VP8_EFLAG_NO_UPD_GF;
456 *flags |= VP8_EFLAG_NO_UPD_LAST;
457 break;
458 case kLastBuffer:
459 *flags |= VP8_EFLAG_NO_UPD_GF;
460 *flags |= VP8_EFLAG_NO_UPD_ARF;
461 break;
462 case kGoldenBuffer:
463 *flags |= VP8_EFLAG_NO_UPD_ARF;
464 *flags |= VP8_EFLAG_NO_UPD_LAST;
465 break;
466 case kNoBuffer:
467 *flags |= VP8_EFLAG_NO_UPD_ARF;
468 *flags |= VP8_EFLAG_NO_UPD_GF;
469 *flags |= VP8_EFLAG_NO_UPD_LAST;
470 *flags |= VP8_EFLAG_NO_UPD_ENTROPY;
471 break;
475 void Vp8Encoder::UpdateRates(uint32 new_bitrate) {
476 DCHECK(thread_checker_.CalledOnValidThread());
478 if (!is_initialized())
479 return;
481 uint32 new_bitrate_kbit = new_bitrate / 1000;
482 if (config_.rc_target_bitrate == new_bitrate_kbit)
483 return;
485 config_.rc_target_bitrate = bitrate_kbit_ = new_bitrate_kbit;
487 // Update encoder context.
488 if (vpx_codec_enc_config_set(&encoder_, &config_)) {
489 NOTREACHED() << "Invalid return value";
492 VLOG(1) << "VP8 new rc_target_bitrate: " << new_bitrate_kbit << " kbps";
495 void Vp8Encoder::LatestFrameIdToReference(uint32 frame_id) {
496 DCHECK(thread_checker_.CalledOnValidThread());
497 if (!use_multiple_video_buffers_)
498 return;
500 VLOG(2) << "VP8 ok to reference frame:" << static_cast<int>(frame_id);
501 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
502 if (frame_id == buffer_state_[i].frame_id) {
503 buffer_state_[i].state = kBufferAcked;
504 break;
507 if (IsOlderFrameId(last_acked_frame_id_, frame_id)) {
508 last_acked_frame_id_ = frame_id;
512 void Vp8Encoder::GenerateKeyFrame() {
513 DCHECK(thread_checker_.CalledOnValidThread());
514 key_frame_requested_ = true;
517 } // namespace cast
518 } // namespace media