| /* | 
 |  *  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 "webrtc/modules/video_coding/codecs/vp8/reference_picture_selection.h" | 
 |  | 
 | #include "vpx/vpx_encoder.h" | 
 | #include "vpx/vp8cx.h" | 
 | #include "webrtc/typedefs.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|. | 
 |   int64_t update_interval = static_cast<int64_t>(kRttConfidence * rtt_); | 
 |   const int64_t kMinUpdateInterval = 90 * 10;  // Timestamp frequency | 
 |   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(int64_t rtt) { | 
 |   // Convert from milliseconds to timestamp frequency. | 
 |   rtt_ = 90 * rtt; | 
 | } | 
 |  | 
 | int64_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 |