1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
/*
* 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 "webrtc/modules/video_coding/codecs/vp8/reference_picture_selection.h"
#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
#include "webrtc/typedefs.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
|