blob: 6330913eb82800728627f76da2d6687a1ec1d9d0 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000011#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/modules/video_coding/main/source/timestamp_extrapolator.h"
16#include "webrtc/system_wrappers/interface/clock.h"
17#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018
19namespace webrtc {
20
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000021VCMTiming::VCMTiming(Clock* clock,
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000022 int32_t vcmId,
23 int32_t timingId,
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +000024 VCMTiming* masterTiming)
niklase@google.com470e71d2011-07-07 08:21:25 +000025:
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000026_critSect(CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +000027_vcmId(vcmId),
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +000028_clock(clock),
niklase@google.com470e71d2011-07-07 08:21:25 +000029_timingId(timingId),
30_master(false),
31_tsExtrapolator(),
32_codecTimer(),
33_renderDelayMs(kDefaultRenderDelayMs),
34_minTotalDelayMs(0),
35_requiredDelayMs(0),
36_currentDelayMs(0),
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +000037_prevFrameTimestamp(0),
38_maxVideoDelayMs(kMaxVideoDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000039{
40 if (masterTiming == NULL)
41 {
42 _master = true;
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +000043 _tsExtrapolator = new VCMTimestampExtrapolator(_clock, vcmId, timingId);
niklase@google.com470e71d2011-07-07 08:21:25 +000044 }
45 else
46 {
47 _tsExtrapolator = masterTiming->_tsExtrapolator;
48 }
49}
50
51VCMTiming::~VCMTiming()
52{
53 if (_master)
54 {
55 delete _tsExtrapolator;
56 }
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000057 delete _critSect;
niklase@google.com470e71d2011-07-07 08:21:25 +000058}
59
60void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000061VCMTiming::Reset(int64_t nowMs /* = -1 */)
niklase@google.com470e71d2011-07-07 08:21:25 +000062{
63 CriticalSectionScoped cs(_critSect);
64 if (nowMs > -1)
65 {
66 _tsExtrapolator->Reset(nowMs);
67 }
68 else
69 {
70 _tsExtrapolator->Reset();
71 }
72 _codecTimer.Reset();
73 _renderDelayMs = kDefaultRenderDelayMs;
74 _minTotalDelayMs = 0;
75 _requiredDelayMs = 0;
76 _currentDelayMs = 0;
77 _prevFrameTimestamp = 0;
78}
79
80void VCMTiming::ResetDecodeTime()
81{
82 _codecTimer.Reset();
83}
84
85void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000086VCMTiming::SetRenderDelay(uint32_t renderDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000087{
88 CriticalSectionScoped cs(_critSect);
89 _renderDelayMs = renderDelayMs;
90}
91
92void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000093VCMTiming::SetMinimumTotalDelay(uint32_t minTotalDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000094{
95 CriticalSectionScoped cs(_critSect);
96 _minTotalDelayMs = minTotalDelayMs;
97}
98
99void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000100VCMTiming::SetRequiredDelay(uint32_t requiredDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000101{
102 CriticalSectionScoped cs(_critSect);
103 if (requiredDelayMs != _requiredDelayMs)
104 {
105 if (_master)
106 {
107 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
108 "Desired jitter buffer level: %u ms", requiredDelayMs);
109 }
110 _requiredDelayMs = requiredDelayMs;
mikhal@webrtc.orgdbd6a6d2013-04-17 16:23:22 +0000111 // When in initial state, set current delay to minimum delay.
112 if (_currentDelayMs == 0) {
113 _currentDelayMs = _requiredDelayMs;
114 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000115 }
116}
117
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000118void VCMTiming::UpdateCurrentDelay(uint32_t frameTimestamp)
niklase@google.com470e71d2011-07-07 08:21:25 +0000119{
120 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000121 uint32_t targetDelayMs = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000122
niklase@google.com470e71d2011-07-07 08:21:25 +0000123 if (_currentDelayMs == 0)
124 {
125 // Not initialized, set current delay to target.
126 _currentDelayMs = targetDelayMs;
127 }
128 else if (targetDelayMs != _currentDelayMs)
129 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000130 int64_t delayDiffMs = static_cast<int64_t>(targetDelayMs) -
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 _currentDelayMs;
132 // Never change the delay with more than 100 ms every second. If we're changing the
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000133 // delay in too large steps we will get noticeable freezes. By limiting the change we
niklase@google.com470e71d2011-07-07 08:21:25 +0000134 // can increase the delay in smaller steps, which will be experienced as the video is
135 // played in slow motion. When lowering the delay the video will be played at a faster
136 // pace.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000137 int64_t maxChangeMs = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 if (frameTimestamp < 0x0000ffff && _prevFrameTimestamp > 0xffff0000)
139 {
140 // wrap
141 maxChangeMs = kDelayMaxChangeMsPerS * (frameTimestamp +
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000142 (static_cast<int64_t>(1)<<32) - _prevFrameTimestamp) / 90000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 }
144 else
145 {
146 maxChangeMs = kDelayMaxChangeMsPerS *
147 (frameTimestamp - _prevFrameTimestamp) / 90000;
148 }
149 if (maxChangeMs <= 0)
150 {
151 // Any changes less than 1 ms are truncated and
152 // will be postponed. Negative change will be due
153 // to reordering and should be ignored.
154 return;
155 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000156 delayDiffMs = std::max(delayDiffMs, -maxChangeMs);
157 delayDiffMs = std::min(delayDiffMs, maxChangeMs);
158
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000159 _currentDelayMs = _currentDelayMs + static_cast<int32_t>(delayDiffMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000160 }
161 _prevFrameTimestamp = frameTimestamp;
162}
163
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000164void VCMTiming::UpdateCurrentDelay(int64_t renderTimeMs,
165 int64_t actualDecodeTimeMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000166{
167 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000168 uint32_t targetDelayMs = TargetDelayInternal();
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000169
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000170 int64_t delayedMs = actualDecodeTimeMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 (renderTimeMs - MaxDecodeTimeMs() - _renderDelayMs);
172 if (delayedMs < 0)
173 {
174 return;
175 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000176 if (_currentDelayMs + delayedMs <= targetDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000178 _currentDelayMs += static_cast<uint32_t>(delayedMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000179 }
180 else
181 {
182 _currentDelayMs = targetDelayMs;
183 }
184}
185
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000186int32_t
187VCMTiming::StopDecodeTimer(uint32_t timeStamp,
188 int64_t startTimeMs,
189 int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000190{
191 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000192 const int32_t maxDecTime = MaxDecodeTimeMs();
193 int32_t timeDiffMs = _codecTimer.StopTimer(startTimeMs, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 if (timeDiffMs < 0)
195 {
196 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
197 "Codec timer error: %d", timeDiffMs);
stefan@webrtc.org06887ae2011-10-10 14:17:46 +0000198 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 }
200
201 if (_master)
202 {
203 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
204 "Frame decoded: timeStamp=%u decTime=%d maxDecTime=%u, at %u",
205 timeStamp, timeDiffMs, maxDecTime, MaskWord64ToUWord32(nowMs));
206 }
207 return 0;
208}
209
210void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000211VCMTiming::IncomingTimestamp(uint32_t timeStamp, int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000212{
213 CriticalSectionScoped cs(_critSect);
214 _tsExtrapolator->Update(nowMs, timeStamp, _master);
215}
216
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000217int64_t
218VCMTiming::RenderTimeMs(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000219{
220 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000221 const int64_t renderTimeMs = RenderTimeMsInternal(frameTimestamp, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 if (renderTimeMs < 0)
223 {
224 return renderTimeMs;
225 }
226 if (_master)
227 {
228 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
229 "Render frame %u at %u. Render delay %u, required delay %u,"
230 " max decode time %u, min total delay %u",
231 frameTimestamp, MaskWord64ToUWord32(renderTimeMs), _renderDelayMs,
232 _requiredDelayMs, MaxDecodeTimeMs(),_minTotalDelayMs);
233 }
234 return renderTimeMs;
235}
236
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000237int64_t
238VCMTiming::RenderTimeMsInternal(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000239{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000240 int64_t estimatedCompleteTimeMs =
niklase@google.com470e71d2011-07-07 08:21:25 +0000241 _tsExtrapolator->ExtrapolateLocalTime(frameTimestamp);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000242 if (estimatedCompleteTimeMs - nowMs > _maxVideoDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 {
244 if (_master)
245 {
246 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
247 "Timestamp arrived 2 seconds early, reset statistics",
248 frameTimestamp, estimatedCompleteTimeMs);
249 }
250 return -1;
251 }
252 if (_master)
253 {
254 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
255 "ExtrapolateLocalTime(%u)=%u ms",
256 frameTimestamp, MaskWord64ToUWord32(estimatedCompleteTimeMs));
257 }
258 if (estimatedCompleteTimeMs == -1)
259 {
260 estimatedCompleteTimeMs = nowMs;
261 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000262
263 // Make sure that we have at least the total minimum delay.
264 uint32_t actual_delay = std::max(_currentDelayMs, _minTotalDelayMs);
265 return estimatedCompleteTimeMs + actual_delay;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
268// Must be called from inside a critical section
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000269int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000270VCMTiming::MaxDecodeTimeMs(FrameType frameType /*= kVideoFrameDelta*/) const
271{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000272 const int32_t decodeTimeMs = _codecTimer.RequiredDecodeTimeMs(frameType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
274 if (decodeTimeMs < 0)
275 {
276 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
277 "Negative maximum decode time: %d", decodeTimeMs);
278 return -1;
279 }
280 return decodeTimeMs;
281}
282
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000283uint32_t
284VCMTiming::MaxWaitingTime(int64_t renderTimeMs, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000285{
286 CriticalSectionScoped cs(_critSect);
287
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000288 const int64_t maxWaitTimeMs = renderTimeMs - nowMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000289 MaxDecodeTimeMs() - _renderDelayMs;
290
291 if (maxWaitTimeMs < 0)
292 {
293 return 0;
294 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000295 return static_cast<uint32_t>(maxWaitTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000296}
297
298bool
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000299VCMTiming::EnoughTimeToDecode(uint32_t availableProcessingTimeMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000300{
301 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000302 int32_t maxDecodeTimeMs = MaxDecodeTimeMs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000303 if (maxDecodeTimeMs < 0)
304 {
305 // Haven't decoded any frames yet, try decoding one to get an estimate
306 // of the decode time.
307 return true;
308 }
309 else if (maxDecodeTimeMs == 0)
310 {
311 // Decode time is less than 1, set to 1 for now since
312 // we don't have any better precision. Count ticks later?
313 maxDecodeTimeMs = 1;
314 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000315 return static_cast<int32_t>(availableProcessingTimeMs) - maxDecodeTimeMs > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000316}
317
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000318void VCMTiming::SetMaxVideoDelay(int maxVideoDelayMs)
319{
320 CriticalSectionScoped cs(_critSect);
321 _maxVideoDelayMs = maxVideoDelayMs;
322}
323
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000324uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000325VCMTiming::TargetVideoDelay() const
326{
327 CriticalSectionScoped cs(_critSect);
328 return TargetDelayInternal();
329}
330
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000331uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000332VCMTiming::TargetDelayInternal() const
333{
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000334 return std::max(_minTotalDelayMs,
335 _requiredDelayMs + MaxDecodeTimeMs() + _renderDelayMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000336}
337
338}