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/main/source/timing.h"
12
13#include "webrtc/modules/video_coding/main/source/internal_defines.h"
14#include "webrtc/modules/video_coding/main/source/jitter_buffer_common.h"
15#include "webrtc/system_wrappers/interface/clock.h"
16#include "webrtc/system_wrappers/interface/timestamp_extrapolator.h"
17
18
19namespace webrtc {
20
21VCMTiming::VCMTiming(Clock* clock,
22                     VCMTiming* master_timing)
23    : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
24      clock_(clock),
25      master_(false),
26      ts_extrapolator_(),
27      codec_timer_(),
28      render_delay_ms_(kDefaultRenderDelayMs),
29      min_playout_delay_ms_(0),
30      jitter_delay_ms_(0),
31      current_delay_ms_(0),
32      last_decode_ms_(0),
33      prev_frame_timestamp_(0) {
34  if (master_timing == NULL) {
35    master_ = true;
36    ts_extrapolator_ = new TimestampExtrapolator(clock_->TimeInMilliseconds());
37  } else {
38    ts_extrapolator_ = master_timing->ts_extrapolator_;
39  }
40}
41
42VCMTiming::~VCMTiming() {
43  if (master_) {
44    delete ts_extrapolator_;
45  }
46  delete crit_sect_;
47}
48
49void VCMTiming::Reset() {
50  CriticalSectionScoped cs(crit_sect_);
51  ts_extrapolator_->Reset(clock_->TimeInMilliseconds());
52  codec_timer_.Reset();
53  render_delay_ms_ = kDefaultRenderDelayMs;
54  min_playout_delay_ms_ = 0;
55  jitter_delay_ms_ = 0;
56  current_delay_ms_ = 0;
57  prev_frame_timestamp_ = 0;
58}
59
60void VCMTiming::ResetDecodeTime() {
61  CriticalSectionScoped lock(crit_sect_);
62  codec_timer_.Reset();
63}
64
65void VCMTiming::set_render_delay(uint32_t render_delay_ms) {
66  CriticalSectionScoped cs(crit_sect_);
67  render_delay_ms_ = render_delay_ms;
68}
69
70void VCMTiming::set_min_playout_delay(uint32_t min_playout_delay_ms) {
71  CriticalSectionScoped cs(crit_sect_);
72  min_playout_delay_ms_ = min_playout_delay_ms;
73}
74
75void VCMTiming::SetJitterDelay(uint32_t jitter_delay_ms) {
76  CriticalSectionScoped cs(crit_sect_);
77  if (jitter_delay_ms != jitter_delay_ms_) {
78    jitter_delay_ms_ = jitter_delay_ms;
79    // When in initial state, set current delay to minimum delay.
80    if (current_delay_ms_ == 0) {
81      current_delay_ms_ = jitter_delay_ms_;
82    }
83  }
84}
85
86void VCMTiming::UpdateCurrentDelay(uint32_t frame_timestamp) {
87  CriticalSectionScoped cs(crit_sect_);
88  uint32_t target_delay_ms = TargetDelayInternal();
89
90  if (current_delay_ms_ == 0) {
91    // Not initialized, set current delay to target.
92    current_delay_ms_ = target_delay_ms;
93  } else if (target_delay_ms != current_delay_ms_) {
94    int64_t delay_diff_ms = static_cast<int64_t>(target_delay_ms) -
95        current_delay_ms_;
96    // Never change the delay with more than 100 ms every second. If we're
97    // changing the delay in too large steps we will get noticeable freezes. By
98    // limiting the change we can increase the delay in smaller steps, which
99    // will be experienced as the video is played in slow motion. When lowering
100    // the delay the video will be played at a faster pace.
101    int64_t max_change_ms = 0;
102    if (frame_timestamp < 0x0000ffff && prev_frame_timestamp_ > 0xffff0000) {
103      // wrap
104      max_change_ms = kDelayMaxChangeMsPerS * (frame_timestamp +
105          (static_cast<int64_t>(1) << 32) - prev_frame_timestamp_) / 90000;
106    } else {
107      max_change_ms = kDelayMaxChangeMsPerS *
108          (frame_timestamp - prev_frame_timestamp_) / 90000;
109    }
110    if (max_change_ms <= 0) {
111      // Any changes less than 1 ms are truncated and
112      // will be postponed. Negative change will be due
113      // to reordering and should be ignored.
114      return;
115    }
116    delay_diff_ms = std::max(delay_diff_ms, -max_change_ms);
117    delay_diff_ms = std::min(delay_diff_ms, max_change_ms);
118
119    current_delay_ms_ = current_delay_ms_ + static_cast<int32_t>(delay_diff_ms);
120  }
121  prev_frame_timestamp_ = frame_timestamp;
122}
123
124void VCMTiming::UpdateCurrentDelay(int64_t render_time_ms,
125                                   int64_t actual_decode_time_ms) {
126  CriticalSectionScoped cs(crit_sect_);
127  uint32_t target_delay_ms = TargetDelayInternal();
128  int64_t delayed_ms = actual_decode_time_ms -
129      (render_time_ms - MaxDecodeTimeMs() - render_delay_ms_);
130  if (delayed_ms < 0) {
131    return;
132  }
133  if (current_delay_ms_ + delayed_ms <= target_delay_ms) {
134    current_delay_ms_ += static_cast<uint32_t>(delayed_ms);
135  } else {
136    current_delay_ms_ = target_delay_ms;
137  }
138}
139
140int32_t VCMTiming::StopDecodeTimer(uint32_t time_stamp,
141                                   int64_t start_time_ms,
142                                   int64_t now_ms) {
143  CriticalSectionScoped cs(crit_sect_);
144  int32_t time_diff_ms = codec_timer_.StopTimer(start_time_ms, now_ms);
145  assert(time_diff_ms >= 0);
146  last_decode_ms_ = time_diff_ms;
147  return 0;
148}
149
150void VCMTiming::IncomingTimestamp(uint32_t time_stamp, int64_t now_ms) {
151  CriticalSectionScoped cs(crit_sect_);
152  ts_extrapolator_->Update(now_ms, time_stamp);
153}
154
155int64_t VCMTiming::RenderTimeMs(uint32_t frame_timestamp, int64_t now_ms)
156    const {
157  CriticalSectionScoped cs(crit_sect_);
158  const int64_t render_time_ms = RenderTimeMsInternal(frame_timestamp, now_ms);
159  return render_time_ms;
160}
161
162int64_t VCMTiming::RenderTimeMsInternal(uint32_t frame_timestamp,
163                                        int64_t now_ms) const {
164  int64_t estimated_complete_time_ms =
165    ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp);
166  if (estimated_complete_time_ms == -1) {
167    estimated_complete_time_ms = now_ms;
168  }
169
170  // Make sure that we have at least the playout delay.
171  uint32_t actual_delay = std::max(current_delay_ms_, min_playout_delay_ms_);
172  return estimated_complete_time_ms + actual_delay;
173}
174
175// Must be called from inside a critical section.
176int32_t VCMTiming::MaxDecodeTimeMs(FrameType frame_type /*= kVideoFrameDelta*/)
177    const {
178  const int32_t decode_time_ms = codec_timer_.RequiredDecodeTimeMs(frame_type);
179  assert(decode_time_ms >= 0);
180  return decode_time_ms;
181}
182
183uint32_t VCMTiming::MaxWaitingTime(int64_t render_time_ms, int64_t now_ms)
184    const {
185  CriticalSectionScoped cs(crit_sect_);
186
187  const int64_t max_wait_time_ms = render_time_ms - now_ms -
188      MaxDecodeTimeMs() - render_delay_ms_;
189
190  if (max_wait_time_ms < 0) {
191    return 0;
192  }
193  return static_cast<uint32_t>(max_wait_time_ms);
194}
195
196bool VCMTiming::EnoughTimeToDecode(uint32_t available_processing_time_ms)
197    const {
198  CriticalSectionScoped cs(crit_sect_);
199  int32_t max_decode_time_ms = MaxDecodeTimeMs();
200  if (max_decode_time_ms < 0) {
201    // Haven't decoded any frames yet, try decoding one to get an estimate
202    // of the decode time.
203    return true;
204  } else if (max_decode_time_ms == 0) {
205    // Decode time is less than 1, set to 1 for now since
206    // we don't have any better precision. Count ticks later?
207    max_decode_time_ms = 1;
208  }
209  return static_cast<int32_t>(available_processing_time_ms) -
210      max_decode_time_ms > 0;
211}
212
213uint32_t VCMTiming::TargetVideoDelay() const {
214  CriticalSectionScoped cs(crit_sect_);
215  return TargetDelayInternal();
216}
217
218uint32_t VCMTiming::TargetDelayInternal() const {
219  return std::max(min_playout_delay_ms_,
220      jitter_delay_ms_ + MaxDecodeTimeMs() + render_delay_ms_);
221}
222
223void VCMTiming::GetTimings(int* decode_ms,
224                           int* max_decode_ms,
225                           int* current_delay_ms,
226                           int* target_delay_ms,
227                           int* jitter_buffer_ms,
228                           int* min_playout_delay_ms,
229                           int* render_delay_ms) const {
230  CriticalSectionScoped cs(crit_sect_);
231  *decode_ms = last_decode_ms_;
232  *max_decode_ms = MaxDecodeTimeMs();
233  *current_delay_ms = current_delay_ms_;
234  *target_delay_ms = TargetDelayInternal();
235  *jitter_buffer_ms = jitter_delay_ms_;
236  *min_playout_delay_ms = min_playout_delay_ms_;
237  *render_delay_ms = render_delay_ms_;
238}
239
240}  // namespace webrtc
241