blob: 1146223482b150aa56270fdd985be6eb47a03dd4 [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
123 // Make sure we try to sync with audio
124 if (targetDelayMs < _minTotalDelayMs)
125 {
126 targetDelayMs = _minTotalDelayMs;
127 }
128
129 if (_currentDelayMs == 0)
130 {
131 // Not initialized, set current delay to target.
132 _currentDelayMs = targetDelayMs;
133 }
134 else if (targetDelayMs != _currentDelayMs)
135 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000136 int64_t delayDiffMs = static_cast<int64_t>(targetDelayMs) -
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 _currentDelayMs;
138 // Never change the delay with more than 100 ms every second. If we're changing the
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000139 // delay in too large steps we will get noticeable freezes. By limiting the change we
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 // can increase the delay in smaller steps, which will be experienced as the video is
141 // played in slow motion. When lowering the delay the video will be played at a faster
142 // pace.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000143 int64_t maxChangeMs = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000144 if (frameTimestamp < 0x0000ffff && _prevFrameTimestamp > 0xffff0000)
145 {
146 // wrap
147 maxChangeMs = kDelayMaxChangeMsPerS * (frameTimestamp +
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000148 (static_cast<int64_t>(1)<<32) - _prevFrameTimestamp) / 90000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 }
150 else
151 {
152 maxChangeMs = kDelayMaxChangeMsPerS *
153 (frameTimestamp - _prevFrameTimestamp) / 90000;
154 }
155 if (maxChangeMs <= 0)
156 {
157 // Any changes less than 1 ms are truncated and
158 // will be postponed. Negative change will be due
159 // to reordering and should be ignored.
160 return;
161 }
162 else if (delayDiffMs < -maxChangeMs)
163 {
164 delayDiffMs = -maxChangeMs;
165 }
166 else if (delayDiffMs > maxChangeMs)
167 {
168 delayDiffMs = maxChangeMs;
169 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000170 _currentDelayMs = _currentDelayMs + static_cast<int32_t>(delayDiffMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 }
172 _prevFrameTimestamp = frameTimestamp;
173}
174
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000175void VCMTiming::UpdateCurrentDelay(int64_t renderTimeMs,
176 int64_t actualDecodeTimeMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000177{
178 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000179 uint32_t targetDelayMs = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 // Make sure we try to sync with audio
181 if (targetDelayMs < _minTotalDelayMs)
182 {
183 targetDelayMs = _minTotalDelayMs;
184 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000185 int64_t delayedMs = actualDecodeTimeMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000186 (renderTimeMs - MaxDecodeTimeMs() - _renderDelayMs);
187 if (delayedMs < 0)
188 {
189 return;
190 }
191 else if (_currentDelayMs + delayedMs <= targetDelayMs)
192 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000193 _currentDelayMs += static_cast<uint32_t>(delayedMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 }
195 else
196 {
197 _currentDelayMs = targetDelayMs;
198 }
199}
200
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000201int32_t
202VCMTiming::StopDecodeTimer(uint32_t timeStamp,
203 int64_t startTimeMs,
204 int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000205{
206 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000207 const int32_t maxDecTime = MaxDecodeTimeMs();
208 int32_t timeDiffMs = _codecTimer.StopTimer(startTimeMs, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 if (timeDiffMs < 0)
210 {
211 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
212 "Codec timer error: %d", timeDiffMs);
stefan@webrtc.org06887ae2011-10-10 14:17:46 +0000213 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 }
215
216 if (_master)
217 {
218 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
219 "Frame decoded: timeStamp=%u decTime=%d maxDecTime=%u, at %u",
220 timeStamp, timeDiffMs, maxDecTime, MaskWord64ToUWord32(nowMs));
221 }
222 return 0;
223}
224
225void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000226VCMTiming::IncomingTimestamp(uint32_t timeStamp, int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000227{
228 CriticalSectionScoped cs(_critSect);
229 _tsExtrapolator->Update(nowMs, timeStamp, _master);
230}
231
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000232int64_t
233VCMTiming::RenderTimeMs(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000234{
235 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000236 const int64_t renderTimeMs = RenderTimeMsInternal(frameTimestamp, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000237 if (renderTimeMs < 0)
238 {
239 return renderTimeMs;
240 }
241 if (_master)
242 {
243 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
244 "Render frame %u at %u. Render delay %u, required delay %u,"
245 " max decode time %u, min total delay %u",
246 frameTimestamp, MaskWord64ToUWord32(renderTimeMs), _renderDelayMs,
247 _requiredDelayMs, MaxDecodeTimeMs(),_minTotalDelayMs);
248 }
249 return renderTimeMs;
250}
251
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000252int64_t
253VCMTiming::RenderTimeMsInternal(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000254{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000255 int64_t estimatedCompleteTimeMs =
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 _tsExtrapolator->ExtrapolateLocalTime(frameTimestamp);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000257 if (estimatedCompleteTimeMs - nowMs > _maxVideoDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000258 {
259 if (_master)
260 {
261 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
262 "Timestamp arrived 2 seconds early, reset statistics",
263 frameTimestamp, estimatedCompleteTimeMs);
264 }
265 return -1;
266 }
267 if (_master)
268 {
269 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
270 "ExtrapolateLocalTime(%u)=%u ms",
271 frameTimestamp, MaskWord64ToUWord32(estimatedCompleteTimeMs));
272 }
273 if (estimatedCompleteTimeMs == -1)
274 {
275 estimatedCompleteTimeMs = nowMs;
276 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 return estimatedCompleteTimeMs + _currentDelayMs;
278}
279
280// Must be called from inside a critical section
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000281int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000282VCMTiming::MaxDecodeTimeMs(FrameType frameType /*= kVideoFrameDelta*/) const
283{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000284 const int32_t decodeTimeMs = _codecTimer.RequiredDecodeTimeMs(frameType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000285
286 if (decodeTimeMs < 0)
287 {
288 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
289 "Negative maximum decode time: %d", decodeTimeMs);
290 return -1;
291 }
292 return decodeTimeMs;
293}
294
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000295uint32_t
296VCMTiming::MaxWaitingTime(int64_t renderTimeMs, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000297{
298 CriticalSectionScoped cs(_critSect);
299
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000300 const int64_t maxWaitTimeMs = renderTimeMs - nowMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000301 MaxDecodeTimeMs() - _renderDelayMs;
302
303 if (maxWaitTimeMs < 0)
304 {
305 return 0;
306 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000307 return static_cast<uint32_t>(maxWaitTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000308}
309
310bool
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000311VCMTiming::EnoughTimeToDecode(uint32_t availableProcessingTimeMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000312{
313 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000314 int32_t maxDecodeTimeMs = MaxDecodeTimeMs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000315 if (maxDecodeTimeMs < 0)
316 {
317 // Haven't decoded any frames yet, try decoding one to get an estimate
318 // of the decode time.
319 return true;
320 }
321 else if (maxDecodeTimeMs == 0)
322 {
323 // Decode time is less than 1, set to 1 for now since
324 // we don't have any better precision. Count ticks later?
325 maxDecodeTimeMs = 1;
326 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000327 return static_cast<int32_t>(availableProcessingTimeMs) - maxDecodeTimeMs > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000328}
329
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000330void VCMTiming::SetMaxVideoDelay(int maxVideoDelayMs)
331{
332 CriticalSectionScoped cs(_critSect);
333 _maxVideoDelayMs = maxVideoDelayMs;
334}
335
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000336uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000337VCMTiming::TargetVideoDelay() const
338{
339 CriticalSectionScoped cs(_critSect);
340 return TargetDelayInternal();
341}
342
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000343uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000344VCMTiming::TargetDelayInternal() const
345{
346 return _requiredDelayMs + MaxDecodeTimeMs() + _renderDelayMs;
347}
348
349}