1/* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/modules/video_coding/codecs/vp8/reference_picture_selection.h" 12 13#include "vpx/vpx_encoder.h" 14#include "vpx/vp8cx.h" 15#include "webrtc/typedefs.h" 16 17namespace webrtc { 18 19ReferencePictureSelection::ReferencePictureSelection() 20 : kRttConfidence(1.33), 21 update_golden_next_(true), 22 established_golden_(false), 23 received_ack_(false), 24 last_sent_ref_picture_id_(0), 25 last_sent_ref_update_time_(0), 26 established_ref_picture_id_(0), 27 last_refresh_time_(0), 28 rtt_(0) { 29} 30 31void ReferencePictureSelection::Init() { 32 update_golden_next_ = true; 33 established_golden_ = false; 34 received_ack_ = false; 35 last_sent_ref_picture_id_ = 0; 36 last_sent_ref_update_time_ = 0; 37 established_ref_picture_id_ = 0; 38 last_refresh_time_ = 0; 39 rtt_ = 0; 40} 41 42void ReferencePictureSelection::ReceivedRPSI(int rpsi_picture_id) { 43 // Assume RPSI is signaled with 14 bits. 44 if ((rpsi_picture_id & 0x3fff) == (last_sent_ref_picture_id_ & 0x3fff)) { 45 // Remote peer has received our last reference frame, switch frame type. 46 received_ack_ = true; 47 established_golden_ = update_golden_next_; 48 update_golden_next_ = !update_golden_next_; 49 established_ref_picture_id_ = last_sent_ref_picture_id_; 50 } 51} 52 53bool ReferencePictureSelection::ReceivedSLI(uint32_t now_ts) { 54 bool send_refresh = false; 55 // Don't send a refresh more than once per round-trip time. 56 // This is to avoid too frequent refreshes, since the receiver 57 // will signal an SLI for every corrupt frame. 58 if (TimestampDiff(now_ts, last_refresh_time_) > rtt_) { 59 send_refresh = true; 60 last_refresh_time_ = now_ts; 61 } 62 return send_refresh; 63} 64 65int ReferencePictureSelection::EncodeFlags(int picture_id, bool send_refresh, 66 uint32_t now_ts) { 67 int flags = 0; 68 // We can't refresh the decoder until we have established the key frame. 69 if (send_refresh && received_ack_) { 70 flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame 71 if (established_golden_) 72 flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame. 73 else 74 flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame 75 } 76 77 // Make sure we don't update the reference frames too often. We must wait long 78 // enough for an RPSI to arrive after the decoder decoded the reference frame. 79 // Ideally that should happen after one round-trip time. 80 // Add a margin defined by |kRttConfidence|. 81 uint32_t update_interval = kRttConfidence * rtt_; 82 if (update_interval < kMinUpdateInterval) 83 update_interval = kMinUpdateInterval; 84 // Don't send reference frame updates until we have an established reference. 85 if (TimestampDiff(now_ts, last_sent_ref_update_time_) > update_interval && 86 received_ack_) { 87 flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame. 88 if (update_golden_next_) { 89 flags |= VP8_EFLAG_FORCE_GF; // Update the golden reference. 90 flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update alt-ref. 91 flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame. 92 } else { 93 flags |= VP8_EFLAG_FORCE_ARF; // Update the alt-ref reference. 94 flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame. 95 flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame. 96 } 97 last_sent_ref_picture_id_ = picture_id; 98 last_sent_ref_update_time_ = now_ts; 99 } else { 100 // No update of golden or alt-ref. We can therefore freely reference the 101 // established reference frame and the last frame. 102 if (established_golden_) 103 flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame. 104 else 105 flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame. 106 flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame. 107 flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update the alt-ref frame. 108 } 109 return flags; 110} 111 112void ReferencePictureSelection::EncodedKeyFrame(int picture_id) { 113 last_sent_ref_picture_id_ = picture_id; 114 received_ack_ = false; 115} 116 117void ReferencePictureSelection::SetRtt(int rtt) { 118 // Convert from milliseconds to timestamp frequency. 119 rtt_ = 90 * rtt; 120} 121 122uint32_t ReferencePictureSelection::TimestampDiff(uint32_t new_ts, 123 uint32_t old_ts) { 124 if (old_ts > new_ts) { 125 // Assuming this is a wrap, doing a compensated subtraction. 126 return (new_ts + (static_cast<int64_t>(1) << 32)) - old_ts; 127 } 128 return new_ts - old_ts; 129} 130 131} // namespace webrtc 132