blob: 2a381bde122360c089a248264b03f19b946e6a3c [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;
111 }
112}
113
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000114void VCMTiming::UpdateCurrentDelay(uint32_t frameTimestamp)
niklase@google.com470e71d2011-07-07 08:21:25 +0000115{
116 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000117 uint32_t targetDelayMs = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000118
119 // Make sure we try to sync with audio
120 if (targetDelayMs < _minTotalDelayMs)
121 {
122 targetDelayMs = _minTotalDelayMs;
123 }
124
125 if (_currentDelayMs == 0)
126 {
127 // Not initialized, set current delay to target.
128 _currentDelayMs = targetDelayMs;
129 }
130 else if (targetDelayMs != _currentDelayMs)
131 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000132 int64_t delayDiffMs = static_cast<int64_t>(targetDelayMs) -
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 _currentDelayMs;
134 // Never change the delay with more than 100 ms every second. If we're changing the
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000135 // delay in too large steps we will get noticeable freezes. By limiting the change we
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 // can increase the delay in smaller steps, which will be experienced as the video is
137 // played in slow motion. When lowering the delay the video will be played at a faster
138 // pace.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000139 int64_t maxChangeMs = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 if (frameTimestamp < 0x0000ffff && _prevFrameTimestamp > 0xffff0000)
141 {
142 // wrap
143 maxChangeMs = kDelayMaxChangeMsPerS * (frameTimestamp +
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000144 (static_cast<int64_t>(1)<<32) - _prevFrameTimestamp) / 90000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 }
146 else
147 {
148 maxChangeMs = kDelayMaxChangeMsPerS *
149 (frameTimestamp - _prevFrameTimestamp) / 90000;
150 }
151 if (maxChangeMs <= 0)
152 {
153 // Any changes less than 1 ms are truncated and
154 // will be postponed. Negative change will be due
155 // to reordering and should be ignored.
156 return;
157 }
158 else if (delayDiffMs < -maxChangeMs)
159 {
160 delayDiffMs = -maxChangeMs;
161 }
162 else if (delayDiffMs > maxChangeMs)
163 {
164 delayDiffMs = maxChangeMs;
165 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000166 _currentDelayMs = _currentDelayMs + static_cast<int32_t>(delayDiffMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000167 }
168 _prevFrameTimestamp = frameTimestamp;
169}
170
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000171void VCMTiming::UpdateCurrentDelay(int64_t renderTimeMs,
172 int64_t actualDecodeTimeMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000173{
174 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000175 uint32_t targetDelayMs = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 // Make sure we try to sync with audio
177 if (targetDelayMs < _minTotalDelayMs)
178 {
179 targetDelayMs = _minTotalDelayMs;
180 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000181 int64_t delayedMs = actualDecodeTimeMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 (renderTimeMs - MaxDecodeTimeMs() - _renderDelayMs);
183 if (delayedMs < 0)
184 {
185 return;
186 }
187 else if (_currentDelayMs + delayedMs <= targetDelayMs)
188 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000189 _currentDelayMs += static_cast<uint32_t>(delayedMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000190 }
191 else
192 {
193 _currentDelayMs = targetDelayMs;
194 }
195}
196
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000197int32_t
198VCMTiming::StopDecodeTimer(uint32_t timeStamp,
199 int64_t startTimeMs,
200 int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000201{
202 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000203 const int32_t maxDecTime = MaxDecodeTimeMs();
204 int32_t timeDiffMs = _codecTimer.StopTimer(startTimeMs, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 if (timeDiffMs < 0)
206 {
207 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
208 "Codec timer error: %d", timeDiffMs);
stefan@webrtc.org06887ae2011-10-10 14:17:46 +0000209 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000210 }
211
212 if (_master)
213 {
214 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
215 "Frame decoded: timeStamp=%u decTime=%d maxDecTime=%u, at %u",
216 timeStamp, timeDiffMs, maxDecTime, MaskWord64ToUWord32(nowMs));
217 }
218 return 0;
219}
220
221void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000222VCMTiming::IncomingTimestamp(uint32_t timeStamp, int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000223{
224 CriticalSectionScoped cs(_critSect);
225 _tsExtrapolator->Update(nowMs, timeStamp, _master);
226}
227
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000228int64_t
229VCMTiming::RenderTimeMs(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000230{
231 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000232 const int64_t renderTimeMs = RenderTimeMsInternal(frameTimestamp, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 if (renderTimeMs < 0)
234 {
235 return renderTimeMs;
236 }
237 if (_master)
238 {
239 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
240 "Render frame %u at %u. Render delay %u, required delay %u,"
241 " max decode time %u, min total delay %u",
242 frameTimestamp, MaskWord64ToUWord32(renderTimeMs), _renderDelayMs,
243 _requiredDelayMs, MaxDecodeTimeMs(),_minTotalDelayMs);
244 }
245 return renderTimeMs;
246}
247
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000248int64_t
249VCMTiming::RenderTimeMsInternal(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000250{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000251 int64_t estimatedCompleteTimeMs =
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 _tsExtrapolator->ExtrapolateLocalTime(frameTimestamp);
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000253 if (estimatedCompleteTimeMs - nowMs > _maxVideoDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 {
255 if (_master)
256 {
257 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
258 "Timestamp arrived 2 seconds early, reset statistics",
259 frameTimestamp, estimatedCompleteTimeMs);
260 }
261 return -1;
262 }
263 if (_master)
264 {
265 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
266 "ExtrapolateLocalTime(%u)=%u ms",
267 frameTimestamp, MaskWord64ToUWord32(estimatedCompleteTimeMs));
268 }
269 if (estimatedCompleteTimeMs == -1)
270 {
271 estimatedCompleteTimeMs = nowMs;
272 }
273
274 return estimatedCompleteTimeMs + _currentDelayMs;
275}
276
277// Must be called from inside a critical section
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000278int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000279VCMTiming::MaxDecodeTimeMs(FrameType frameType /*= kVideoFrameDelta*/) const
280{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000281 const int32_t decodeTimeMs = _codecTimer.RequiredDecodeTimeMs(frameType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000282
283 if (decodeTimeMs < 0)
284 {
285 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
286 "Negative maximum decode time: %d", decodeTimeMs);
287 return -1;
288 }
289 return decodeTimeMs;
290}
291
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000292uint32_t
293VCMTiming::MaxWaitingTime(int64_t renderTimeMs, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000294{
295 CriticalSectionScoped cs(_critSect);
296
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000297 const int64_t maxWaitTimeMs = renderTimeMs - nowMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000298 MaxDecodeTimeMs() - _renderDelayMs;
299
300 if (maxWaitTimeMs < 0)
301 {
302 return 0;
303 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000304 return static_cast<uint32_t>(maxWaitTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000305}
306
307bool
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000308VCMTiming::EnoughTimeToDecode(uint32_t availableProcessingTimeMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000309{
310 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000311 int32_t maxDecodeTimeMs = MaxDecodeTimeMs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000312 if (maxDecodeTimeMs < 0)
313 {
314 // Haven't decoded any frames yet, try decoding one to get an estimate
315 // of the decode time.
316 return true;
317 }
318 else if (maxDecodeTimeMs == 0)
319 {
320 // Decode time is less than 1, set to 1 for now since
321 // we don't have any better precision. Count ticks later?
322 maxDecodeTimeMs = 1;
323 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000324 return static_cast<int32_t>(availableProcessingTimeMs) - maxDecodeTimeMs > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000325}
326
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000327void VCMTiming::SetMaxVideoDelay(int maxVideoDelayMs)
328{
329 CriticalSectionScoped cs(_critSect);
330 _maxVideoDelayMs = maxVideoDelayMs;
331}
332
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000333uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000334VCMTiming::TargetVideoDelay() const
335{
336 CriticalSectionScoped cs(_critSect);
337 return TargetDelayInternal();
338}
339
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000340uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000341VCMTiming::TargetDelayInternal() const
342{
343 return _requiredDelayMs + MaxDecodeTimeMs() + _renderDelayMs;
344}
345
346}