| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "reference_picture_selection.h" |
| |
| #include "typedefs.h" |
| #include "vpx/vpx_encoder.h" |
| #include "vpx/vp8cx.h" |
| |
| namespace webrtc { |
| |
| ReferencePictureSelection::ReferencePictureSelection() |
| : kRttConfidence(1.33), |
| update_golden_next_(true), |
| established_golden_(false), |
| received_ack_(false), |
| last_sent_ref_picture_id_(0), |
| last_sent_ref_update_time_(0), |
| established_ref_picture_id_(0), |
| last_refresh_time_(0), |
| rtt_(0) { |
| } |
| |
| void ReferencePictureSelection::Init() { |
| update_golden_next_ = true; |
| established_golden_ = false; |
| received_ack_ = false; |
| last_sent_ref_picture_id_ = 0; |
| last_sent_ref_update_time_ = 0; |
| established_ref_picture_id_ = 0; |
| last_refresh_time_ = 0; |
| rtt_ = 0; |
| } |
| |
| void ReferencePictureSelection::ReceivedRPSI(int rpsi_picture_id) { |
| // Assume RPSI is signaled with 14 bits. |
| if ((rpsi_picture_id & 0x3fff) == (last_sent_ref_picture_id_ & 0x3fff)) { |
| // Remote peer has received our last reference frame, switch frame type. |
| received_ack_ = true; |
| established_golden_ = update_golden_next_; |
| update_golden_next_ = !update_golden_next_; |
| established_ref_picture_id_ = last_sent_ref_picture_id_; |
| } |
| } |
| |
| bool ReferencePictureSelection::ReceivedSLI(uint32_t now_ts) { |
| bool send_refresh = false; |
| // Don't send a refresh more than once per round-trip time. |
| // This is to avoid too frequent refreshes, since the receiver |
| // will signal an SLI for every corrupt frame. |
| if (TimestampDiff(now_ts, last_refresh_time_) > rtt_) { |
| send_refresh = true; |
| last_refresh_time_ = now_ts; |
| } |
| return send_refresh; |
| } |
| |
| int ReferencePictureSelection::EncodeFlags(int picture_id, bool send_refresh, |
| uint32_t now_ts) { |
| int flags = 0; |
| // We can't refresh the decoder until we have established the key frame. |
| if (send_refresh && received_ack_) { |
| flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame |
| if (established_golden_) |
| flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame. |
| else |
| flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame |
| } |
| |
| // Make sure we don't update the reference frames too often. We must wait long |
| // enough for an RPSI to arrive after the decoder decoded the reference frame. |
| // Ideally that should happen after one round-trip time. |
| // Add a margin defined by |kRttConfidence|. |
| uint32_t update_interval = kRttConfidence * rtt_; |
| if (update_interval < kMinUpdateInterval) |
| update_interval = kMinUpdateInterval; |
| // Don't send reference frame updates until we have an established reference. |
| if (TimestampDiff(now_ts, last_sent_ref_update_time_) > update_interval && |
| received_ack_) { |
| flags |= VP8_EFLAG_NO_REF_LAST; // Don't reference the last frame. |
| if (update_golden_next_) { |
| flags |= VP8_EFLAG_FORCE_GF; // Update the golden reference. |
| flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update alt-ref. |
| flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame. |
| } else { |
| flags |= VP8_EFLAG_FORCE_ARF; // Update the alt-ref reference. |
| flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame. |
| flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame. |
| } |
| last_sent_ref_picture_id_ = picture_id; |
| last_sent_ref_update_time_ = now_ts; |
| } else { |
| // No update of golden or alt-ref. We can therefore freely reference the |
| // established reference frame and the last frame. |
| if (established_golden_) |
| flags |= VP8_EFLAG_NO_REF_ARF; // Don't reference the alt-ref frame. |
| else |
| flags |= VP8_EFLAG_NO_REF_GF; // Don't reference the golden frame. |
| flags |= VP8_EFLAG_NO_UPD_GF; // Don't update the golden frame. |
| flags |= VP8_EFLAG_NO_UPD_ARF; // Don't update the alt-ref frame. |
| } |
| return flags; |
| } |
| |
| void ReferencePictureSelection::EncodedKeyFrame(int picture_id) { |
| last_sent_ref_picture_id_ = picture_id; |
| received_ack_ = false; |
| } |
| |
| void ReferencePictureSelection::SetRtt(int rtt) { |
| // Convert from milliseconds to timestamp frequency. |
| rtt_ = 90 * rtt; |
| } |
| |
| uint32_t ReferencePictureSelection::TimestampDiff(uint32_t new_ts, |
| uint32_t old_ts) { |
| if (old_ts > new_ts) { |
| // Assuming this is a wrap, doing a compensated subtraction. |
| return (new_ts + (static_cast<int64_t>(1) << 32)) - old_ts; |
| } |
| return new_ts - old_ts; |
| } |
| |
| } // namespace webrtc |