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
),
32 key_frame_requested_(true),
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 // VP8 have 3 buffers available for prediction, with
39 // max_number_of_video_buffers_used set to 1 we maximize the coding efficiency
40 // however in this mode we can not skip frames in the receiver to catch up
41 // after a temporary network outage; with max_number_of_video_buffers_used
42 // set to 3 we allow 2 frames to be skipped by the receiver without error
44 DCHECK(cast_config_
.max_number_of_video_buffers_used
== 1 ||
45 cast_config_
.max_number_of_video_buffers_used
==
46 kNumberOfVp8VideoBuffers
)
47 << "Invalid argument";
49 thread_checker_
.DetachFromThread();
52 Vp8Encoder::~Vp8Encoder() {
53 DCHECK(thread_checker_
.CalledOnValidThread());
55 vpx_codec_destroy(&encoder_
);
56 vpx_img_free(raw_image_
);
59 void Vp8Encoder::Initialize() {
60 DCHECK(thread_checker_
.CalledOnValidThread());
61 DCHECK(!is_initialized());
63 // Creating a wrapper to the image - setting image data to NULL. Actual
64 // pointer will be set during encode. Setting align to 1, as it is
65 // meaningless (actual memory is not allocated).
66 raw_image_
= vpx_img_wrap(
67 NULL
, VPX_IMG_FMT_I420
, cast_config_
.width
, cast_config_
.height
, 1, NULL
);
69 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
70 buffer_state_
[i
].frame_id
= kStartFrameId
;
71 buffer_state_
[i
].state
= kBufferStartState
;
74 // Populate encoder configuration with default values.
75 if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_
, 0)) {
76 NOTREACHED() << "Invalid return value";
77 config_
.g_timebase
.den
= 0; // Do not call vpx_codec_destroy() in dtor.
81 config_
.g_threads
= cast_config_
.number_of_encode_threads
;
82 config_
.g_w
= cast_config_
.width
;
83 config_
.g_h
= cast_config_
.height
;
84 // Set the timebase to match that of base::TimeDelta.
85 config_
.g_timebase
.num
= 1;
86 config_
.g_timebase
.den
= base::Time::kMicrosecondsPerSecond
;
87 if (use_multiple_video_buffers_
) {
88 // We must enable error resilience when we use multiple buffers, due to
89 // codec requirements.
90 config_
.g_error_resilient
= 1;
92 config_
.g_pass
= VPX_RC_ONE_PASS
;
93 config_
.g_lag_in_frames
= 0; // Immediate data output for each frame.
95 // Rate control settings.
96 config_
.rc_dropframe_thresh
= 0; // The encoder may not drop any frames.
97 config_
.rc_resize_allowed
= 0; // TODO(miu): Why not? Investigate this.
98 config_
.rc_end_usage
= VPX_CBR
;
99 config_
.rc_target_bitrate
= cast_config_
.start_bitrate
/ 1000; // In kbit/s.
100 config_
.rc_min_quantizer
= cast_config_
.min_qp
;
101 config_
.rc_max_quantizer
= cast_config_
.max_qp
;
102 // TODO(miu): Revisit these now that the encoder is being successfully
104 config_
.rc_undershoot_pct
= 100;
105 config_
.rc_overshoot_pct
= 15;
106 // TODO(miu): Document why these rc_buf_*_sz values were chosen and/or
107 // research for better values. Should they be computed from the target
109 config_
.rc_buf_initial_sz
= 500;
110 config_
.rc_buf_optimal_sz
= 600;
111 config_
.rc_buf_sz
= 1000;
113 config_
.kf_mode
= VPX_KF_DISABLED
;
115 vpx_codec_flags_t flags
= 0;
116 if (vpx_codec_enc_init(&encoder_
, vpx_codec_vp8_cx(), &config_
, flags
)) {
117 NOTREACHED() << "vpx_codec_enc_init() failed.";
118 config_
.g_timebase
.den
= 0; // Do not call vpx_codec_destroy() in dtor.
122 // Raise the threshold for considering macroblocks as static. The default is
123 // zero, so this setting makes the encoder less sensitive to motion. This
124 // lowers the probability of needing to utilize more CPU to search for motion
126 vpx_codec_control(&encoder_
, VP8E_SET_STATIC_THRESHOLD
, 1);
128 // Improve quality by enabling sets of codec features that utilize more CPU.
129 // The default is zero, with increasingly more CPU to be used as the value is
131 // TODO(miu): Document why this value was chosen and expected behaviors.
132 // Should this be dynamic w.r.t. hardware performance?
133 vpx_codec_control(&encoder_
, VP8E_SET_CPUUSED
, -6);
136 void Vp8Encoder::Encode(const scoped_refptr
<media::VideoFrame
>& video_frame
,
137 const base::TimeTicks
& reference_time
,
138 EncodedFrame
* encoded_frame
) {
139 DCHECK(thread_checker_
.CalledOnValidThread());
140 DCHECK(encoded_frame
);
142 CHECK(is_initialized()); // No illegal reference to |config_| or |encoder_|.
144 // Image in vpx_image_t format.
145 // Input image is const. VP8's raw image is not defined as const.
146 raw_image_
->planes
[VPX_PLANE_Y
] =
147 const_cast<uint8
*>(video_frame
->data(VideoFrame::kYPlane
));
148 raw_image_
->planes
[VPX_PLANE_U
] =
149 const_cast<uint8
*>(video_frame
->data(VideoFrame::kUPlane
));
150 raw_image_
->planes
[VPX_PLANE_V
] =
151 const_cast<uint8
*>(video_frame
->data(VideoFrame::kVPlane
));
153 raw_image_
->stride
[VPX_PLANE_Y
] = video_frame
->stride(VideoFrame::kYPlane
);
154 raw_image_
->stride
[VPX_PLANE_U
] = video_frame
->stride(VideoFrame::kUPlane
);
155 raw_image_
->stride
[VPX_PLANE_V
] = video_frame
->stride(VideoFrame::kVPlane
);
157 uint32 latest_frame_id_to_reference
;
158 Vp8Buffers buffer_to_update
;
159 vpx_codec_flags_t flags
= 0;
160 if (key_frame_requested_
) {
161 flags
= VPX_EFLAG_FORCE_KF
;
163 latest_frame_id_to_reference
= last_encoded_frame_id_
+ 1;
164 // We can pick any buffer as buffer_to_update since we update
166 buffer_to_update
= kLastBuffer
;
168 // Reference all acked frames (buffers).
169 latest_frame_id_to_reference
= GetCodecReferenceFlags(&flags
);
170 buffer_to_update
= GetNextBufferToUpdate();
171 GetCodecUpdateFlags(buffer_to_update
, &flags
);
174 // The frame duration given to the VP8 codec affects a number of important
175 // behaviors, including: per-frame bandwidth, CPU time spent encoding,
176 // temporal quality trade-offs, and key/golden/alt-ref frame generation
177 // intervals. Use the actual amount of time between the current and previous
178 // frames as a prediction for the next frame's duration, but bound the
179 // prediction to account for the fact that the frame rate can be highly
180 // variable, including long pauses in the video stream.
181 const base::TimeDelta minimum_frame_duration
=
182 base::TimeDelta::FromSecondsD(1.0 / cast_config_
.max_frame_rate
);
183 const base::TimeDelta maximum_frame_duration
=
184 base::TimeDelta::FromSecondsD(static_cast<double>(kRestartFramePeriods
) /
185 cast_config_
.max_frame_rate
);
186 const base::TimeDelta last_frame_duration
=
187 video_frame
->timestamp() - last_frame_timestamp_
;
188 const base::TimeDelta predicted_frame_duration
=
189 std::max(minimum_frame_duration
,
190 std::min(maximum_frame_duration
, last_frame_duration
));
191 last_frame_timestamp_
= video_frame
->timestamp();
193 // Encode the frame. The presentation time stamp argument here is fixed to
194 // zero to force the encoder to base its single-frame bandwidth calculations
195 // entirely on |predicted_frame_duration| and the target bitrate setting being
196 // micro-managed via calls to UpdateRates().
197 CHECK_EQ(vpx_codec_encode(&encoder_
,
200 predicted_frame_duration
.InMicroseconds(),
204 << "BUG: Invalid arguments passed to vpx_codec_encode().";
206 // Pull data from the encoder, populating a new EncodedFrame.
207 encoded_frame
->frame_id
= ++last_encoded_frame_id_
;
208 const vpx_codec_cx_pkt_t
* pkt
= NULL
;
209 vpx_codec_iter_t iter
= NULL
;
210 while ((pkt
= vpx_codec_get_cx_data(&encoder_
, &iter
)) != NULL
) {
211 if (pkt
->kind
!= VPX_CODEC_CX_FRAME_PKT
)
213 if (pkt
->data
.frame
.flags
& VPX_FRAME_IS_KEY
) {
214 // TODO(hubbe): Replace "dependency" with a "bool is_key_frame".
215 encoded_frame
->dependency
= EncodedFrame::KEY
;
216 encoded_frame
->referenced_frame_id
= encoded_frame
->frame_id
;
218 encoded_frame
->dependency
= EncodedFrame::DEPENDENT
;
219 // Frame dependencies could theoretically be relaxed by looking for the
220 // VPX_FRAME_IS_DROPPABLE flag, but in recent testing (Oct 2014), this
221 // flag never seems to be set.
222 encoded_frame
->referenced_frame_id
= latest_frame_id_to_reference
;
224 encoded_frame
->rtp_timestamp
=
225 TimeDeltaToRtpDelta(video_frame
->timestamp(), kVideoFrequency
);
226 encoded_frame
->reference_time
= reference_time
;
227 encoded_frame
->data
.assign(
228 static_cast<const uint8
*>(pkt
->data
.frame
.buf
),
229 static_cast<const uint8
*>(pkt
->data
.frame
.buf
) + pkt
->data
.frame
.sz
);
230 break; // Done, since all data is provided in one CX_FRAME_PKT packet.
232 DCHECK(!encoded_frame
->data
.empty())
233 << "BUG: Encoder must provide data since lagged encoding is disabled.";
235 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame
->frame_id
236 << ", sized:" << encoded_frame
->data
.size();
238 if (encoded_frame
->dependency
== EncodedFrame::KEY
) {
239 key_frame_requested_
= false;
241 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
242 buffer_state_
[i
].state
= kBufferSent
;
243 buffer_state_
[i
].frame_id
= encoded_frame
->frame_id
;
246 if (buffer_to_update
!= kNoBuffer
) {
247 buffer_state_
[buffer_to_update
].state
= kBufferSent
;
248 buffer_state_
[buffer_to_update
].frame_id
= encoded_frame
->frame_id
;
253 uint32
Vp8Encoder::GetCodecReferenceFlags(vpx_codec_flags_t
* flags
) {
254 if (!use_multiple_video_buffers_
)
255 return last_encoded_frame_id_
;
257 const uint32 kMagicFrameOffset
= 512;
258 // We set latest_frame_to_reference to an old frame so that
259 // IsNewerFrameId will work correctly.
260 uint32 latest_frame_to_reference
=
261 last_encoded_frame_id_
- kMagicFrameOffset
;
263 // Reference all acked frames.
264 // TODO(hubbe): We may also want to allow references to the
265 // last encoded frame, if that frame was assigned to a buffer.
266 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
267 if (buffer_state_
[i
].state
== kBufferAcked
) {
268 if (IsNewerFrameId(buffer_state_
[i
].frame_id
,
269 latest_frame_to_reference
)) {
270 latest_frame_to_reference
= buffer_state_
[i
].frame_id
;
275 *flags
|= VP8_EFLAG_NO_REF_ARF
;
278 *flags
|= VP8_EFLAG_NO_REF_GF
;
281 *flags
|= VP8_EFLAG_NO_REF_LAST
;
287 if (latest_frame_to_reference
==
288 last_encoded_frame_id_
- kMagicFrameOffset
) {
289 // We have nothing to reference, it's kind of like a key frame,
290 // but doesn't reset buffers.
291 latest_frame_to_reference
= last_encoded_frame_id_
+ 1;
294 return latest_frame_to_reference
;
297 Vp8Encoder::Vp8Buffers
Vp8Encoder::GetNextBufferToUpdate() {
298 if (!use_multiple_video_buffers_
)
301 // The goal here is to make sure that we always keep one ACKed
302 // buffer while trying to get an ACK for a newer buffer as we go.
303 // Here are the rules for which buffer to select for update:
304 // 1. If there is a buffer in state kStartState, use it.
305 // 2. If there is a buffer other than the oldest buffer
306 // which is Acked, use the oldest buffer.
307 // 3. If there are Sent buffers which are older than
308 // latest_acked_frame_, use the oldest one.
309 // 4. If all else fails, just overwrite the newest buffer,
310 // but no more than 3 times in a row.
311 // TODO(hubbe): Figure out if 3 is optimal.
312 // Note, rule 1-3 describe cases where there is a "free" buffer
313 // that we can use. Rule 4 describes what happens when there is
314 // no free buffer available.
316 // Buffers, sorted from oldest frame to newest.
317 Vp8Encoder::Vp8Buffers buffers
[kNumberOfVp8VideoBuffers
];
319 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
320 Vp8Encoder::Vp8Buffers buffer
= static_cast<Vp8Encoder::Vp8Buffers
>(i
);
323 if (buffer_state_
[buffer
].state
== kBufferStartState
) {
324 undroppable_frames_
= 0;
327 buffers
[buffer
] = buffer
;
330 // Sorting three elements with selection sort.
331 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
- 1; i
++) {
332 for (int j
= i
+ 1; j
< kNumberOfVp8VideoBuffers
; j
++) {
333 if (IsOlderFrameId(buffer_state_
[buffers
[j
]].frame_id
,
334 buffer_state_
[buffers
[i
]].frame_id
)) {
335 std::swap(buffers
[i
], buffers
[j
]);
341 if (buffer_state_
[buffers
[1]].state
== kBufferAcked
||
342 buffer_state_
[buffers
[2]].state
== kBufferAcked
) {
343 undroppable_frames_
= 0;
348 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; i
++) {
349 if (buffer_state_
[buffers
[i
]].state
== kBufferSent
&&
350 IsOlderFrameId(buffer_state_
[buffers
[i
]].frame_id
,
351 last_acked_frame_id_
)) {
352 undroppable_frames_
= 0;
358 if (undroppable_frames_
>= 3) {
359 undroppable_frames_
= 0;
362 undroppable_frames_
++;
363 return buffers
[kNumberOfVp8VideoBuffers
- 1];
367 void Vp8Encoder::GetCodecUpdateFlags(Vp8Buffers buffer_to_update
,
368 vpx_codec_flags_t
* flags
) {
369 if (!use_multiple_video_buffers_
)
372 // Update at most one buffer, except for key-frames.
373 switch (buffer_to_update
) {
375 *flags
|= VP8_EFLAG_NO_UPD_GF
;
376 *flags
|= VP8_EFLAG_NO_UPD_LAST
;
379 *flags
|= VP8_EFLAG_NO_UPD_GF
;
380 *flags
|= VP8_EFLAG_NO_UPD_ARF
;
383 *flags
|= VP8_EFLAG_NO_UPD_ARF
;
384 *flags
|= VP8_EFLAG_NO_UPD_LAST
;
387 *flags
|= VP8_EFLAG_NO_UPD_ARF
;
388 *flags
|= VP8_EFLAG_NO_UPD_GF
;
389 *flags
|= VP8_EFLAG_NO_UPD_LAST
;
390 *flags
|= VP8_EFLAG_NO_UPD_ENTROPY
;
395 void Vp8Encoder::UpdateRates(uint32 new_bitrate
) {
396 DCHECK(thread_checker_
.CalledOnValidThread());
398 if (!is_initialized())
401 uint32 new_bitrate_kbit
= new_bitrate
/ 1000;
402 if (config_
.rc_target_bitrate
== new_bitrate_kbit
)
405 config_
.rc_target_bitrate
= new_bitrate_kbit
;
407 // Update encoder context.
408 if (vpx_codec_enc_config_set(&encoder_
, &config_
)) {
409 NOTREACHED() << "Invalid return value";
412 VLOG(1) << "VP8 new rc_target_bitrate: " << new_bitrate_kbit
<< " kbps";
415 void Vp8Encoder::LatestFrameIdToReference(uint32 frame_id
) {
416 DCHECK(thread_checker_
.CalledOnValidThread());
417 if (!use_multiple_video_buffers_
)
420 VLOG(2) << "VP8 ok to reference frame:" << static_cast<int>(frame_id
);
421 for (int i
= 0; i
< kNumberOfVp8VideoBuffers
; ++i
) {
422 if (frame_id
== buffer_state_
[i
].frame_id
) {
423 buffer_state_
[i
].state
= kBufferAcked
;
427 if (IsOlderFrameId(last_acked_frame_id_
, frame_id
)) {
428 last_acked_frame_id_
= frame_id
;
432 void Vp8Encoder::GenerateKeyFrame() {
433 DCHECK(thread_checker_
.CalledOnValidThread());
434 key_frame_requested_
= true;