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 
Init()30 void ReferencePictureSelection::Init() {
31   update_golden_next_ = true;
32   established_golden_ = false;
33   received_ack_ = false;
34   last_sent_ref_picture_id_ = 0;
35   last_sent_ref_update_time_ = 0;
36   established_ref_picture_id_ = 0;
37   last_refresh_time_ = 0;
38   rtt_ = 0;
39 }
40 
ReceivedRPSI(int rpsi_picture_id)41 void ReferencePictureSelection::ReceivedRPSI(int rpsi_picture_id) {
42   // Assume RPSI is signaled with 14 bits.
43   if ((rpsi_picture_id & 0x3fff) == (last_sent_ref_picture_id_ & 0x3fff)) {
44     // Remote peer has received our last reference frame, switch frame type.
45     received_ack_ = true;
46     established_golden_ = update_golden_next_;
47     update_golden_next_ = !update_golden_next_;
48     established_ref_picture_id_ = last_sent_ref_picture_id_;
49   }
50 }
51 
ReceivedSLI(uint32_t now_ts)52 bool ReferencePictureSelection::ReceivedSLI(uint32_t now_ts) {
53   bool send_refresh = false;
54   // Don't send a refresh more than once per round-trip time.
55   // This is to avoid too frequent refreshes, since the receiver
56   // will signal an SLI for every corrupt frame.
57   if (TimestampDiff(now_ts, last_refresh_time_) > rtt_) {
58     send_refresh = true;
59     last_refresh_time_ = now_ts;
60   }
61   return send_refresh;
62 }
63 
EncodeFlags(int picture_id,bool send_refresh,uint32_t now_ts)64 int ReferencePictureSelection::EncodeFlags(int picture_id,
65                                            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   int64_t update_interval = static_cast<int64_t>(kRttConfidence * rtt_);
82   const int64_t kMinUpdateInterval = 90 * 10;  // Timestamp frequency
83   if (update_interval < kMinUpdateInterval)
84     update_interval = kMinUpdateInterval;
85   // Don't send reference frame updates until we have an established reference.
86   if (TimestampDiff(now_ts, last_sent_ref_update_time_) > update_interval &&
87       received_ack_) {
88     flags |= VP8_EFLAG_NO_REF_LAST;  // Don't reference the last frame.
89     if (update_golden_next_) {
90       flags |= VP8_EFLAG_FORCE_GF;    // Update the golden reference.
91       flags |= VP8_EFLAG_NO_UPD_ARF;  // Don't update alt-ref.
92       flags |= VP8_EFLAG_NO_REF_GF;   // Don't reference the golden frame.
93     } else {
94       flags |= VP8_EFLAG_FORCE_ARF;   // Update the alt-ref reference.
95       flags |= VP8_EFLAG_NO_UPD_GF;   // Don't update the golden frame.
96       flags |= VP8_EFLAG_NO_REF_ARF;  // Don't reference the alt-ref frame.
97     }
98     last_sent_ref_picture_id_ = picture_id;
99     last_sent_ref_update_time_ = now_ts;
100   } else {
101     // No update of golden or alt-ref. We can therefore freely reference the
102     // established reference frame and the last frame.
103     if (established_golden_)
104       flags |= VP8_EFLAG_NO_REF_ARF;  // Don't reference the alt-ref frame.
105     else
106       flags |= VP8_EFLAG_NO_REF_GF;  // Don't reference the golden frame.
107     flags |= VP8_EFLAG_NO_UPD_GF;    // Don't update the golden frame.
108     flags |= VP8_EFLAG_NO_UPD_ARF;   // Don't update the alt-ref frame.
109   }
110   return flags;
111 }
112 
EncodedKeyFrame(int picture_id)113 void ReferencePictureSelection::EncodedKeyFrame(int picture_id) {
114   last_sent_ref_picture_id_ = picture_id;
115   received_ack_ = false;
116 }
117 
SetRtt(int64_t rtt)118 void ReferencePictureSelection::SetRtt(int64_t rtt) {
119   // Convert from milliseconds to timestamp frequency.
120   rtt_ = 90 * rtt;
121 }
122 
TimestampDiff(uint32_t new_ts,uint32_t old_ts)123 int64_t ReferencePictureSelection::TimestampDiff(uint32_t new_ts,
124                                                  uint32_t old_ts) {
125   if (old_ts > new_ts) {
126     // Assuming this is a wrap, doing a compensated subtraction.
127     return (new_ts + (static_cast<int64_t>(1) << 32)) - old_ts;
128   }
129   return new_ts - old_ts;
130 }
131 
132 }  // namespace webrtc
133