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 "media/cast/net/cast_transport_config.h"
11 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
18 // After a pause in the video stream, what is the maximum duration amount to
19 // pass to the encoder for the next frame (in terms of 1/max_fps sized periods)?
20 // This essentially controls the encoded size of the first frame that follows a
21 // pause in the video stream.
22 const int kRestartFramePeriods
= 3;
26 Vp8Encoder::Vp8Encoder(const VideoSenderConfig
& video_config
)
27 : cast_config_(video_config
),
28 use_multiple_video_buffers_(
29 cast_config_
.max_number_of_video_buffers_used
==
30 kNumberOfVp8VideoBuffers
),
31 key_frame_requested_(true),
32 bitrate_kbit_(cast_config_
.start_bitrate
/ 1000),
33 last_encoded_frame_id_(kStartFrameId
),
34 last_acked_frame_id_(kStartFrameId
),
35 undroppable_frames_(0) {
36 config_
.g_timebase
.den
= 0; // Not initialized.
38 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
39 buffer_state_
[i
].frame_id
= last_encoded_frame_id_
;
40 buffer_state_
[i
].state
= kBufferStartState
;
43 // VP8 have 3 buffers available for prediction, with
44 // max_number_of_video_buffers_used set to 1 we maximize the coding efficiency
45 // however in this mode we can not skip frames in the receiver to catch up
46 // after a temporary network outage; with max_number_of_video_buffers_used
47 // set to 3 we allow 2 frames to be skipped by the receiver without error
49 DCHECK(cast_config_
.max_number_of_video_buffers_used
== 1 ||
50 cast_config_
.max_number_of_video_buffers_used
==
51 kNumberOfVp8VideoBuffers
)
52 << "Invalid argument";
54 thread_checker_
.DetachFromThread();
57 Vp8Encoder::~Vp8Encoder() {
58 DCHECK(thread_checker_
.CalledOnValidThread());
60 vpx_codec_destroy(&encoder_
);
63 void Vp8Encoder::Initialize() {
64 DCHECK(thread_checker_
.CalledOnValidThread());
65 DCHECK(!is_initialized());
66 // The encoder will be created/configured when the first frame encode is
70 void Vp8Encoder::ConfigureForNewFrameSize(const gfx::Size
& frame_size
) {
71 if (is_initialized()) {
72 // Workaround for VP8 bug: If the new size is strictly less-than-or-equal to
73 // the old size, in terms of area, the existing encoder instance can
74 // continue. Otherwise, completely tear-down and re-create a new encoder to
75 // avoid a shutdown crash.
76 if (frame_size
.GetArea() <= gfx::Size(config_
.g_w
, config_
.g_h
).GetArea() &&
77 !use_multiple_video_buffers_
) {
78 DVLOG(1) << "Continuing to use existing encoder at smaller frame size: "
79 << gfx::Size(config_
.g_w
, config_
.g_h
).ToString() << " --> "
80 << frame_size
.ToString();
81 config_
.g_w
= frame_size
.width();
82 config_
.g_h
= frame_size
.height();
83 CHECK_EQ(vpx_codec_enc_config_set(&encoder_
, &config_
), VPX_CODEC_OK
)
84 << "Failed to update frame size in encoder config.";
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_
);
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),
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
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
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
),
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
153 CHECK_EQ(vpx_codec_control(&encoder_
, VP8E_SET_STATIC_THRESHOLD
, 1),
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
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 EncodedFrame
* encoded_frame
) {
167 DCHECK(thread_checker_
.CalledOnValidThread());
168 DCHECK(encoded_frame
);
170 // Initialize on-demand. Later, if the video frame size has changed, update
171 // the encoder configuration.
172 const gfx::Size frame_size
= video_frame
->visible_rect().size();
173 if (!is_initialized() || gfx::Size(config_
.g_w
, config_
.g_h
) != frame_size
)
174 ConfigureForNewFrameSize(frame_size
);
176 uint32 latest_frame_id_to_reference
;
177 Vp8Buffers buffer_to_update
;
178 vpx_codec_flags_t flags
= 0;
179 if (key_frame_requested_
) {
180 flags
= VPX_EFLAG_FORCE_KF
;
182 latest_frame_id_to_reference
= last_encoded_frame_id_
+ 1;
183 // We can pick any buffer as buffer_to_update since we update
185 buffer_to_update
= kLastBuffer
;
187 // Reference all acked frames (buffers).
188 latest_frame_id_to_reference
= GetCodecReferenceFlags(&flags
);
189 buffer_to_update
= GetNextBufferToUpdate();
190 GetCodecUpdateFlags(buffer_to_update
, &flags
);
193 // Wrapper for vpx_codec_encode() to access the YUV data in the |video_frame|.
194 // Only the VISIBLE rectangle within |video_frame| is exposed to the codec.
195 vpx_image_t vpx_image
;
196 vpx_image_t
* const result
= vpx_img_wrap(
202 video_frame
->data(VideoFrame::kYPlane
));
203 DCHECK_EQ(result
, &vpx_image
);
204 vpx_image
.planes
[VPX_PLANE_Y
] =
205 video_frame
->visible_data(VideoFrame::kYPlane
);
206 vpx_image
.planes
[VPX_PLANE_U
] =
207 video_frame
->visible_data(VideoFrame::kUPlane
);
208 vpx_image
.planes
[VPX_PLANE_V
] =
209 video_frame
->visible_data(VideoFrame::kVPlane
);
210 vpx_image
.stride
[VPX_PLANE_Y
] = video_frame
->stride(VideoFrame::kYPlane
);
211 vpx_image
.stride
[VPX_PLANE_U
] = video_frame
->stride(VideoFrame::kUPlane
);
212 vpx_image
.stride
[VPX_PLANE_V
] = video_frame
->stride(VideoFrame::kVPlane
);
214 // The frame duration given to the VP8 codec affects a number of important
215 // behaviors, including: per-frame bandwidth, CPU time spent encoding,
216 // temporal quality trade-offs, and key/golden/alt-ref frame generation
217 // intervals. Use the actual amount of time between the current and previous
218 // frames as a prediction for the next frame's duration, but bound the
219 // prediction to account for the fact that the frame rate can be highly
220 // variable, including long pauses in the video stream.
221 const base::TimeDelta minimum_frame_duration
=
222 base::TimeDelta::FromSecondsD(1.0 / cast_config_
.max_frame_rate
);
223 const base::TimeDelta maximum_frame_duration
=
224 base::TimeDelta::FromSecondsD(static_cast<double>(kRestartFramePeriods
) /
225 cast_config_
.max_frame_rate
);
226 const base::TimeDelta last_frame_duration
=
227 video_frame
->timestamp() - last_frame_timestamp_
;
228 const base::TimeDelta predicted_frame_duration
=
229 std::max(minimum_frame_duration
,
230 std::min(maximum_frame_duration
, last_frame_duration
));
231 last_frame_timestamp_
= video_frame
->timestamp();
233 // Encode the frame. The presentation time stamp argument here is fixed to
234 // zero to force the encoder to base its single-frame bandwidth calculations
235 // entirely on |predicted_frame_duration| and the target bitrate setting being
236 // micro-managed via calls to UpdateRates().
237 CHECK_EQ(vpx_codec_encode(&encoder_
,
240 predicted_frame_duration
.InMicroseconds(),
244 << "BUG: Invalid arguments passed to vpx_codec_encode().";
246 // Pull data from the encoder, populating a new EncodedFrame.
247 encoded_frame
->frame_id
= ++last_encoded_frame_id_
;
248 const vpx_codec_cx_pkt_t
* pkt
= NULL
;
249 vpx_codec_iter_t iter
= NULL
;
250 while ((pkt
= vpx_codec_get_cx_data(&encoder_
, &iter
)) != NULL
) {
251 if (pkt
->kind
!= VPX_CODEC_CX_FRAME_PKT
)
253 if (pkt
->data
.frame
.flags
& VPX_FRAME_IS_KEY
) {
254 // TODO(hubbe): Replace "dependency" with a "bool is_key_frame".
255 encoded_frame
->dependency
= EncodedFrame::KEY
;
256 encoded_frame
->referenced_frame_id
= encoded_frame
->frame_id
;
258 encoded_frame
->dependency
= EncodedFrame::DEPENDENT
;
259 // Frame dependencies could theoretically be relaxed by looking for the
260 // VPX_FRAME_IS_DROPPABLE flag, but in recent testing (Oct 2014), this
261 // flag never seems to be set.
262 encoded_frame
->referenced_frame_id
= latest_frame_id_to_reference
;
264 encoded_frame
->rtp_timestamp
=
265 TimeDeltaToRtpDelta(video_frame
->timestamp(), kVideoFrequency
);
266 encoded_frame
->reference_time
= reference_time
;
267 encoded_frame
->data
.assign(
268 static_cast<const uint8
*>(pkt
->data
.frame
.buf
),
269 static_cast<const uint8
*>(pkt
->data
.frame
.buf
) + pkt
->data
.frame
.sz
);
270 break; // Done, since all data is provided in one CX_FRAME_PKT packet.
272 DCHECK(!encoded_frame
->data
.empty())
273 << "BUG: Encoder must provide data since lagged encoding is disabled.";
275 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame
->frame_id
276 << ", sized:" << encoded_frame
->data
.size();
278 if (encoded_frame
->dependency
== EncodedFrame::KEY
) {
279 key_frame_requested_
= false;
281 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
282 buffer_state_
[i
].state
= kBufferSent
;
283 buffer_state_
[i
].frame_id
= encoded_frame
->frame_id
;
286 if (buffer_to_update
!= kNoBuffer
) {
287 buffer_state_
[buffer_to_update
].state
= kBufferSent
;
288 buffer_state_
[buffer_to_update
].frame_id
= encoded_frame
->frame_id
;
293 uint32
Vp8Encoder::GetCodecReferenceFlags(vpx_codec_flags_t
* flags
) {
294 if (!use_multiple_video_buffers_
)
295 return last_encoded_frame_id_
;
297 const uint32 kMagicFrameOffset
= 512;
298 // We set latest_frame_to_reference to an old frame so that
299 // IsNewerFrameId will work correctly.
300 uint32 latest_frame_to_reference
=
301 last_encoded_frame_id_
- kMagicFrameOffset
;
303 // Reference all acked frames.
304 // TODO(hubbe): We may also want to allow references to the
305 // last encoded frame, if that frame was assigned to a buffer.
306 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
307 if (buffer_state_
[i
].state
== kBufferAcked
) {
308 if (IsNewerFrameId(buffer_state_
[i
].frame_id
,
309 latest_frame_to_reference
)) {
310 latest_frame_to_reference
= buffer_state_
[i
].frame_id
;
315 *flags
|= VP8_EFLAG_NO_REF_ARF
;
318 *flags
|= VP8_EFLAG_NO_REF_GF
;
321 *flags
|= VP8_EFLAG_NO_REF_LAST
;
327 if (latest_frame_to_reference
==
328 last_encoded_frame_id_
- kMagicFrameOffset
) {
329 // We have nothing to reference, it's kind of like a key frame,
330 // but doesn't reset buffers.
331 latest_frame_to_reference
= last_encoded_frame_id_
+ 1;
334 return latest_frame_to_reference
;
337 Vp8Encoder::Vp8Buffers
Vp8Encoder::GetNextBufferToUpdate() {
338 if (!use_multiple_video_buffers_
)
341 // The goal here is to make sure that we always keep one ACKed
342 // buffer while trying to get an ACK for a newer buffer as we go.
343 // Here are the rules for which buffer to select for update:
344 // 1. If there is a buffer in state kStartState, use it.
345 // 2. If there is a buffer other than the oldest buffer
346 // which is Acked, use the oldest buffer.
347 // 3. If there are Sent buffers which are older than
348 // latest_acked_frame_, use the oldest one.
349 // 4. If all else fails, just overwrite the newest buffer,
350 // but no more than 3 times in a row.
351 // TODO(hubbe): Figure out if 3 is optimal.
352 // Note, rule 1-3 describe cases where there is a "free" buffer
353 // that we can use. Rule 4 describes what happens when there is
354 // no free buffer available.
356 // Buffers, sorted from oldest frame to newest.
357 Vp8Encoder::Vp8Buffers buffers
[kNumberOfVp8VideoBuffers
];
359 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
360 Vp8Encoder::Vp8Buffers buffer
= static_cast<Vp8Encoder::Vp8Buffers
>(i
);
363 if (buffer_state_
[buffer
].state
== kBufferStartState
) {
364 undroppable_frames_
= 0;
367 buffers
[buffer
] = buffer
;
370 // Sorting three elements with selection sort.
371 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
- 1; i
++) {
372 for (int j
= i
+ 1; j
< kNumberOfVp8VideoBuffers
; j
++) {
373 if (IsOlderFrameId(buffer_state_
[buffers
[j
]].frame_id
,
374 buffer_state_
[buffers
[i
]].frame_id
)) {
375 std::swap(buffers
[i
], buffers
[j
]);
381 if (buffer_state_
[buffers
[1]].state
== kBufferAcked
||
382 buffer_state_
[buffers
[2]].state
== kBufferAcked
) {
383 undroppable_frames_
= 0;
388 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; i
++) {
389 if (buffer_state_
[buffers
[i
]].state
== kBufferSent
&&
390 IsOlderFrameId(buffer_state_
[buffers
[i
]].frame_id
,
391 last_acked_frame_id_
)) {
392 undroppable_frames_
= 0;
398 if (undroppable_frames_
>= 3) {
399 undroppable_frames_
= 0;
402 undroppable_frames_
++;
403 return buffers
[kNumberOfVp8VideoBuffers
- 1];
407 void Vp8Encoder::GetCodecUpdateFlags(Vp8Buffers buffer_to_update
,
408 vpx_codec_flags_t
* flags
) {
409 if (!use_multiple_video_buffers_
)
412 // Update at most one buffer, except for key-frames.
413 switch (buffer_to_update
) {
415 *flags
|= VP8_EFLAG_NO_UPD_GF
;
416 *flags
|= VP8_EFLAG_NO_UPD_LAST
;
419 *flags
|= VP8_EFLAG_NO_UPD_GF
;
420 *flags
|= VP8_EFLAG_NO_UPD_ARF
;
423 *flags
|= VP8_EFLAG_NO_UPD_ARF
;
424 *flags
|= VP8_EFLAG_NO_UPD_LAST
;
427 *flags
|= VP8_EFLAG_NO_UPD_ARF
;
428 *flags
|= VP8_EFLAG_NO_UPD_GF
;
429 *flags
|= VP8_EFLAG_NO_UPD_LAST
;
430 *flags
|= VP8_EFLAG_NO_UPD_ENTROPY
;
435 void Vp8Encoder::UpdateRates(uint32 new_bitrate
) {
436 DCHECK(thread_checker_
.CalledOnValidThread());
438 if (!is_initialized())
441 uint32 new_bitrate_kbit
= new_bitrate
/ 1000;
442 if (config_
.rc_target_bitrate
== new_bitrate_kbit
)
445 config_
.rc_target_bitrate
= bitrate_kbit_
= new_bitrate_kbit
;
447 // Update encoder context.
448 if (vpx_codec_enc_config_set(&encoder_
, &config_
)) {
449 NOTREACHED() << "Invalid return value";
452 VLOG(1) << "VP8 new rc_target_bitrate: " << new_bitrate_kbit
<< " kbps";
455 void Vp8Encoder::LatestFrameIdToReference(uint32 frame_id
) {
456 DCHECK(thread_checker_
.CalledOnValidThread());
457 if (!use_multiple_video_buffers_
)
460 VLOG(2) << "VP8 ok to reference frame:" << static_cast<int>(frame_id
);
461 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
462 if (frame_id
== buffer_state_
[i
].frame_id
) {
463 buffer_state_
[i
].state
= kBufferAcked
;
467 if (IsOlderFrameId(last_acked_frame_id_
, frame_id
)) {
468 last_acked_frame_id_
= frame_id
;
472 void Vp8Encoder::GenerateKeyFrame() {
473 DCHECK(thread_checker_
.CalledOnValidThread());
474 key_frame_requested_
= true;