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