Line data Source code
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 :
19 0 : 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 0 : rtt_(0) {}
29 :
30 0 : void ReferencePictureSelection::Init() {
31 0 : update_golden_next_ = true;
32 0 : established_golden_ = false;
33 0 : received_ack_ = false;
34 0 : last_sent_ref_picture_id_ = 0;
35 0 : last_sent_ref_update_time_ = 0;
36 0 : established_ref_picture_id_ = 0;
37 0 : last_refresh_time_ = 0;
38 0 : rtt_ = 0;
39 0 : }
40 :
41 0 : void ReferencePictureSelection::ReceivedRPSI(int rpsi_picture_id) {
42 : // Assume RPSI is signaled with 14 bits.
43 0 : if ((rpsi_picture_id & 0x3fff) == (last_sent_ref_picture_id_ & 0x3fff)) {
44 : // Remote peer has received our last reference frame, switch frame type.
45 0 : received_ack_ = true;
46 0 : established_golden_ = update_golden_next_;
47 0 : update_golden_next_ = !update_golden_next_;
48 0 : established_ref_picture_id_ = last_sent_ref_picture_id_;
49 : }
50 0 : }
51 :
52 0 : bool ReferencePictureSelection::ReceivedSLI(uint32_t now_ts) {
53 0 : 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 0 : if (TimestampDiff(now_ts, last_refresh_time_) > rtt_) {
58 0 : send_refresh = true;
59 0 : last_refresh_time_ = now_ts;
60 : }
61 0 : return send_refresh;
62 : }
63 :
64 0 : int ReferencePictureSelection::EncodeFlags(int picture_id,
65 : bool send_refresh,
66 : uint32_t now_ts) {
67 0 : int flags = 0;
68 : // We can't refresh the decoder until we have established the key frame.
69 0 : if (send_refresh && received_ack_) {
70 0 : flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame
71 0 : if (established_golden_)
72 0 : flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame.
73 : else
74 0 : 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 0 : int64_t update_interval = static_cast<int64_t>(kRttConfidence * rtt_);
82 0 : const int64_t kMinUpdateInterval = 90 * 10; // Timestamp frequency
83 0 : if (update_interval < kMinUpdateInterval)
84 0 : update_interval = kMinUpdateInterval;
85 : // Don't send reference frame updates until we have an established reference.
86 0 : if (TimestampDiff(now_ts, last_sent_ref_update_time_) > update_interval &&
87 0 : received_ack_) {
88 0 : flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame.
89 0 : if (update_golden_next_) {
90 0 : flags |= VP8_EFLAG_FORCE_GF; // Update the golden reference.
91 0 : flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update alt-ref.
92 0 : flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame.
93 : } else {
94 0 : flags |= VP8_EFLAG_FORCE_ARF; // Update the alt-ref reference.
95 0 : flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame.
96 0 : flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame.
97 : }
98 0 : last_sent_ref_picture_id_ = picture_id;
99 0 : 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 0 : if (established_golden_)
104 0 : flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame.
105 : else
106 0 : flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame.
107 0 : flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame.
108 0 : flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update the alt-ref frame.
109 : }
110 0 : return flags;
111 : }
112 :
113 0 : void ReferencePictureSelection::EncodedKeyFrame(int picture_id) {
114 0 : last_sent_ref_picture_id_ = picture_id;
115 0 : received_ack_ = false;
116 0 : }
117 :
118 0 : void ReferencePictureSelection::SetRtt(int64_t rtt) {
119 : // Convert from milliseconds to timestamp frequency.
120 0 : rtt_ = 90 * rtt;
121 0 : }
122 :
123 0 : int64_t ReferencePictureSelection::TimestampDiff(uint32_t new_ts,
124 : uint32_t old_ts) {
125 0 : if (old_ts > new_ts) {
126 : // Assuming this is a wrap, doing a compensated subtraction.
127 0 : return (new_ts + (static_cast<int64_t>(1) << 32)) - old_ts;
128 : }
129 0 : return new_ts - old_ts;
130 : }
131 :
132 : } // namespace webrtc
|