blob: 3ae6f19bce38797f40454345381e7c05965af9b3 [file] [log] [blame]
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "reference_picture_selection.h"
#include "typedefs.h"
#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
namespace webrtc {
ReferencePictureSelection::ReferencePictureSelection()
: kRttConfidence(1.33),
update_golden_next_(true),
established_golden_(false),
received_ack_(false),
last_sent_ref_picture_id_(0),
last_sent_ref_update_time_(0),
established_ref_picture_id_(0),
last_refresh_time_(0),
rtt_(0) {
}
void ReferencePictureSelection::Init() {
update_golden_next_ = true;
established_golden_ = false;
received_ack_ = false;
last_sent_ref_picture_id_ = 0;
last_sent_ref_update_time_ = 0;
established_ref_picture_id_ = 0;
last_refresh_time_ = 0;
rtt_ = 0;
}
void ReferencePictureSelection::ReceivedRPSI(int rpsi_picture_id) {
// Assume RPSI is signaled with 14 bits.
if ((rpsi_picture_id & 0x3fff) == (last_sent_ref_picture_id_ & 0x3fff)) {
// Remote peer has received our last reference frame, switch frame type.
received_ack_ = true;
established_golden_ = update_golden_next_;
update_golden_next_ = !update_golden_next_;
established_ref_picture_id_ = last_sent_ref_picture_id_;
}
}
bool ReferencePictureSelection::ReceivedSLI(uint32_t now_ts) {
bool send_refresh = false;
// Don't send a refresh more than once per round-trip time.
// This is to avoid too frequent refreshes, since the receiver
// will signal an SLI for every corrupt frame.
if (TimestampDiff(now_ts, last_refresh_time_) > rtt_) {
send_refresh = true;
last_refresh_time_ = now_ts;
}
return send_refresh;
}
int ReferencePictureSelection::EncodeFlags(int picture_id, bool send_refresh,
uint32_t now_ts) {
int flags = 0;
// We can't refresh the decoder until we have established the key frame.
if (send_refresh && received_ack_) {
flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame
if (established_golden_)
flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame.
else
flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame
}
// Make sure we don't update the reference frames too often. We must wait long
// enough for an RPSI to arrive after the decoder decoded the reference frame.
// Ideally that should happen after one round-trip time.
// Add a margin defined by |kRttConfidence|.
uint32_t update_interval = kRttConfidence * rtt_;
if (update_interval < kMinUpdateInterval)
update_interval = kMinUpdateInterval;
// Don't send reference frame updates until we have an established reference.
if (TimestampDiff(now_ts, last_sent_ref_update_time_) > update_interval &&
received_ack_) {
flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame.
if (update_golden_next_) {
flags |= VP8_EFLAG_FORCE_GF; // Update the golden reference.
flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update alt-ref.
flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame.
} else {
flags |= VP8_EFLAG_FORCE_ARF; // Update the alt-ref reference.
flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame.
flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame.
}
last_sent_ref_picture_id_ = picture_id;
last_sent_ref_update_time_ = now_ts;
} else {
// No update of golden or alt-ref. We can therefore freely reference the
// established reference frame and the last frame.
if (established_golden_)
flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame.
else
flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame.
flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame.
flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update the alt-ref frame.
}
return flags;
}
void ReferencePictureSelection::EncodedKeyFrame(int picture_id) {
last_sent_ref_picture_id_ = picture_id;
received_ack_ = false;
}
void ReferencePictureSelection::SetRtt(int rtt) {
// Convert from milliseconds to timestamp frequency.
rtt_ = 90 * rtt;
}
uint32_t ReferencePictureSelection::TimestampDiff(uint32_t new_ts,
uint32_t old_ts) {
if (old_ts > new_ts) {
// Assuming this is a wrap, doing a compensated subtraction.
return (new_ts + (static_cast<int64_t>(1) << 32)) - old_ts;
}
return new_ts - old_ts;
}
} // namespace webrtc