blob: 91aed1470edbc72171a975df06f443d986aa8e74 [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.org759b0412013-05-07 16:36:00 +000037_prevFrameTimestamp(0)
niklase@google.com470e71d2011-07-07 08:21:25 +000038{
39 if (masterTiming == NULL)
40 {
41 _master = true;
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +000042 _tsExtrapolator = new VCMTimestampExtrapolator(_clock, vcmId, timingId);
niklase@google.com470e71d2011-07-07 08:21:25 +000043 }
44 else
45 {
46 _tsExtrapolator = masterTiming->_tsExtrapolator;
47 }
48}
49
50VCMTiming::~VCMTiming()
51{
52 if (_master)
53 {
54 delete _tsExtrapolator;
55 }
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000056 delete _critSect;
niklase@google.com470e71d2011-07-07 08:21:25 +000057}
58
59void
stefan@webrtc.org9f557c12013-05-17 12:55:07 +000060VCMTiming::Reset()
niklase@google.com470e71d2011-07-07 08:21:25 +000061{
62 CriticalSectionScoped cs(_critSect);
stefan@webrtc.org9f557c12013-05-17 12:55:07 +000063
64 _tsExtrapolator->Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +000065 _codecTimer.Reset();
66 _renderDelayMs = kDefaultRenderDelayMs;
67 _minTotalDelayMs = 0;
68 _requiredDelayMs = 0;
69 _currentDelayMs = 0;
70 _prevFrameTimestamp = 0;
71}
72
73void VCMTiming::ResetDecodeTime()
74{
75 _codecTimer.Reset();
76}
77
78void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000079VCMTiming::SetRenderDelay(uint32_t renderDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000080{
81 CriticalSectionScoped cs(_critSect);
82 _renderDelayMs = renderDelayMs;
83}
84
85void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000086VCMTiming::SetMinimumTotalDelay(uint32_t minTotalDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000087{
88 CriticalSectionScoped cs(_critSect);
89 _minTotalDelayMs = minTotalDelayMs;
90}
91
92void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000093VCMTiming::SetRequiredDelay(uint32_t requiredDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000094{
95 CriticalSectionScoped cs(_critSect);
96 if (requiredDelayMs != _requiredDelayMs)
97 {
98 if (_master)
99 {
100 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
101 "Desired jitter buffer level: %u ms", requiredDelayMs);
102 }
103 _requiredDelayMs = requiredDelayMs;
mikhal@webrtc.orgdbd6a6d2013-04-17 16:23:22 +0000104 // When in initial state, set current delay to minimum delay.
105 if (_currentDelayMs == 0) {
106 _currentDelayMs = _requiredDelayMs;
107 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 }
109}
110
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000111void VCMTiming::UpdateCurrentDelay(uint32_t frameTimestamp)
niklase@google.com470e71d2011-07-07 08:21:25 +0000112{
113 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000114 uint32_t targetDelayMs = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 if (_currentDelayMs == 0)
117 {
118 // Not initialized, set current delay to target.
119 _currentDelayMs = targetDelayMs;
120 }
121 else if (targetDelayMs != _currentDelayMs)
122 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000123 int64_t delayDiffMs = static_cast<int64_t>(targetDelayMs) -
niklase@google.com470e71d2011-07-07 08:21:25 +0000124 _currentDelayMs;
125 // Never change the delay with more than 100 ms every second. If we're changing the
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000126 // delay in too large steps we will get noticeable freezes. By limiting the change we
niklase@google.com470e71d2011-07-07 08:21:25 +0000127 // can increase the delay in smaller steps, which will be experienced as the video is
128 // played in slow motion. When lowering the delay the video will be played at a faster
129 // pace.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000130 int64_t maxChangeMs = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 if (frameTimestamp < 0x0000ffff && _prevFrameTimestamp > 0xffff0000)
132 {
133 // wrap
134 maxChangeMs = kDelayMaxChangeMsPerS * (frameTimestamp +
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000135 (static_cast<int64_t>(1)<<32) - _prevFrameTimestamp) / 90000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 }
137 else
138 {
139 maxChangeMs = kDelayMaxChangeMsPerS *
140 (frameTimestamp - _prevFrameTimestamp) / 90000;
141 }
142 if (maxChangeMs <= 0)
143 {
144 // Any changes less than 1 ms are truncated and
145 // will be postponed. Negative change will be due
146 // to reordering and should be ignored.
147 return;
148 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000149 delayDiffMs = std::max(delayDiffMs, -maxChangeMs);
150 delayDiffMs = std::min(delayDiffMs, maxChangeMs);
151
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000152 _currentDelayMs = _currentDelayMs + static_cast<int32_t>(delayDiffMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 }
154 _prevFrameTimestamp = frameTimestamp;
155}
156
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000157void VCMTiming::UpdateCurrentDelay(int64_t renderTimeMs,
158 int64_t actualDecodeTimeMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000159{
160 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000161 uint32_t targetDelayMs = TargetDelayInternal();
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000162
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000163 int64_t delayedMs = actualDecodeTimeMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 (renderTimeMs - MaxDecodeTimeMs() - _renderDelayMs);
165 if (delayedMs < 0)
166 {
167 return;
168 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000169 if (_currentDelayMs + delayedMs <= targetDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000171 _currentDelayMs += static_cast<uint32_t>(delayedMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 }
173 else
174 {
175 _currentDelayMs = targetDelayMs;
176 }
177}
178
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000179int32_t
180VCMTiming::StopDecodeTimer(uint32_t timeStamp,
181 int64_t startTimeMs,
182 int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000183{
184 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000185 const int32_t maxDecTime = MaxDecodeTimeMs();
186 int32_t timeDiffMs = _codecTimer.StopTimer(startTimeMs, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 if (timeDiffMs < 0)
188 {
189 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
190 "Codec timer error: %d", timeDiffMs);
stefan@webrtc.org06887ae2011-10-10 14:17:46 +0000191 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 }
193
194 if (_master)
195 {
196 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
197 "Frame decoded: timeStamp=%u decTime=%d maxDecTime=%u, at %u",
198 timeStamp, timeDiffMs, maxDecTime, MaskWord64ToUWord32(nowMs));
199 }
200 return 0;
201}
202
203void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000204VCMTiming::IncomingTimestamp(uint32_t timeStamp, int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000205{
206 CriticalSectionScoped cs(_critSect);
207 _tsExtrapolator->Update(nowMs, timeStamp, _master);
208}
209
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000210int64_t
211VCMTiming::RenderTimeMs(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000212{
213 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000214 const int64_t renderTimeMs = RenderTimeMsInternal(frameTimestamp, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000215 if (_master)
216 {
217 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
218 "Render frame %u at %u. Render delay %u, required delay %u,"
219 " max decode time %u, min total delay %u",
220 frameTimestamp, MaskWord64ToUWord32(renderTimeMs), _renderDelayMs,
221 _requiredDelayMs, MaxDecodeTimeMs(),_minTotalDelayMs);
222 }
223 return renderTimeMs;
224}
225
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000226int64_t
227VCMTiming::RenderTimeMsInternal(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000228{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000229 int64_t estimatedCompleteTimeMs =
niklase@google.com470e71d2011-07-07 08:21:25 +0000230 _tsExtrapolator->ExtrapolateLocalTime(frameTimestamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000231 if (_master)
232 {
233 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
234 "ExtrapolateLocalTime(%u)=%u ms",
235 frameTimestamp, MaskWord64ToUWord32(estimatedCompleteTimeMs));
236 }
237 if (estimatedCompleteTimeMs == -1)
238 {
239 estimatedCompleteTimeMs = nowMs;
240 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000241
242 // Make sure that we have at least the total minimum delay.
243 uint32_t actual_delay = std::max(_currentDelayMs, _minTotalDelayMs);
244 return estimatedCompleteTimeMs + actual_delay;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245}
246
247// Must be called from inside a critical section
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000248int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000249VCMTiming::MaxDecodeTimeMs(FrameType frameType /*= kVideoFrameDelta*/) const
250{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000251 const int32_t decodeTimeMs = _codecTimer.RequiredDecodeTimeMs(frameType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000252
253 if (decodeTimeMs < 0)
254 {
255 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
256 "Negative maximum decode time: %d", decodeTimeMs);
257 return -1;
258 }
259 return decodeTimeMs;
260}
261
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000262uint32_t
263VCMTiming::MaxWaitingTime(int64_t renderTimeMs, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000264{
265 CriticalSectionScoped cs(_critSect);
266
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000267 const int64_t maxWaitTimeMs = renderTimeMs - nowMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 MaxDecodeTimeMs() - _renderDelayMs;
269
270 if (maxWaitTimeMs < 0)
271 {
272 return 0;
273 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000274 return static_cast<uint32_t>(maxWaitTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000275}
276
277bool
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000278VCMTiming::EnoughTimeToDecode(uint32_t availableProcessingTimeMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000279{
280 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000281 int32_t maxDecodeTimeMs = MaxDecodeTimeMs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 if (maxDecodeTimeMs < 0)
283 {
284 // Haven't decoded any frames yet, try decoding one to get an estimate
285 // of the decode time.
286 return true;
287 }
288 else if (maxDecodeTimeMs == 0)
289 {
290 // Decode time is less than 1, set to 1 for now since
291 // we don't have any better precision. Count ticks later?
292 maxDecodeTimeMs = 1;
293 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000294 return static_cast<int32_t>(availableProcessingTimeMs) - maxDecodeTimeMs > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000295}
296
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000297uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000298VCMTiming::TargetVideoDelay() const
299{
300 CriticalSectionScoped cs(_critSect);
301 return TargetDelayInternal();
302}
303
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000304uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000305VCMTiming::TargetDelayInternal() const
306{
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000307 return std::max(_minTotalDelayMs,
308 _requiredDelayMs + MaxDecodeTimeMs() + _renderDelayMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000309}
310
311}