OLD | NEW |
| (Empty) |
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 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 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 | |
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 | |
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 | |
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 | |
113 void ReferencePictureSelection::EncodedKeyFrame(int picture_id) { | |
114 last_sent_ref_picture_id_ = picture_id; | |
115 received_ack_ = false; | |
116 } | |
117 | |
118 void ReferencePictureSelection::SetRtt(int64_t rtt) { | |
119 // Convert from milliseconds to timestamp frequency. | |
120 rtt_ = 90 * rtt; | |
121 } | |
122 | |
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 | |
OLD | NEW |