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
17 namespace webrtc {
18
ReferencePictureSelection()19 ReferencePictureSelection::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
Init()31 void 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
ReceivedRPSI(int rpsi_picture_id)42 void 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
ReceivedSLI(uint32_t now_ts)53 bool 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
EncodeFlags(int picture_id,bool send_refresh,uint32_t now_ts)65 int 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
EncodedKeyFrame(int picture_id)112 void ReferencePictureSelection::EncodedKeyFrame(int picture_id) {
113 last_sent_ref_picture_id_ = picture_id;
114 received_ack_ = false;
115 }
116
SetRtt(int rtt)117 void ReferencePictureSelection::SetRtt(int rtt) {
118 // Convert from milliseconds to timestamp frequency.
119 rtt_ = 90 * rtt;
120 }
121
TimestampDiff(uint32_t new_ts,uint32_t old_ts)122 uint32_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