blob: 36131b1bbf839e299639fc2b2d9a7de9c1ff39a7 [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,
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +000022 WebRtc_Word32 vcmId,
23 WebRtc_Word32 timingId,
24 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),
37_prevFrameTimestamp(0)
38{
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
60VCMTiming::Reset(WebRtc_Word64 nowMs /* = -1 */)
61{
62 CriticalSectionScoped cs(_critSect);
63 if (nowMs > -1)
64 {
65 _tsExtrapolator->Reset(nowMs);
66 }
67 else
68 {
69 _tsExtrapolator->Reset();
70 }
71 _codecTimer.Reset();
72 _renderDelayMs = kDefaultRenderDelayMs;
73 _minTotalDelayMs = 0;
74 _requiredDelayMs = 0;
75 _currentDelayMs = 0;
76 _prevFrameTimestamp = 0;
77}
78
79void VCMTiming::ResetDecodeTime()
80{
81 _codecTimer.Reset();
82}
83
84void
85VCMTiming::SetRenderDelay(WebRtc_UWord32 renderDelayMs)
86{
87 CriticalSectionScoped cs(_critSect);
88 _renderDelayMs = renderDelayMs;
89}
90
91void
92VCMTiming::SetMinimumTotalDelay(WebRtc_UWord32 minTotalDelayMs)
93{
94 CriticalSectionScoped cs(_critSect);
95 _minTotalDelayMs = minTotalDelayMs;
96}
97
98void
99VCMTiming::SetRequiredDelay(WebRtc_UWord32 requiredDelayMs)
100{
101 CriticalSectionScoped cs(_critSect);
102 if (requiredDelayMs != _requiredDelayMs)
103 {
104 if (_master)
105 {
106 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
107 "Desired jitter buffer level: %u ms", requiredDelayMs);
108 }
109 _requiredDelayMs = requiredDelayMs;
110 }
111}
112
113void VCMTiming::UpdateCurrentDelay(WebRtc_UWord32 frameTimestamp)
114{
115 CriticalSectionScoped cs(_critSect);
116 WebRtc_UWord32 targetDelayMs = TargetDelayInternal();
117
118 // Make sure we try to sync with audio
119 if (targetDelayMs < _minTotalDelayMs)
120 {
121 targetDelayMs = _minTotalDelayMs;
122 }
123
124 if (_currentDelayMs == 0)
125 {
126 // Not initialized, set current delay to target.
127 _currentDelayMs = targetDelayMs;
128 }
129 else if (targetDelayMs != _currentDelayMs)
130 {
131 WebRtc_Word64 delayDiffMs = static_cast<WebRtc_Word64>(targetDelayMs) -
132 _currentDelayMs;
133 // Never change the delay with more than 100 ms every second. If we're changing the
134 // delay in too large steps we will get noticable freezes. By limiting the change we
135 // can increase the delay in smaller steps, which will be experienced as the video is
136 // played in slow motion. When lowering the delay the video will be played at a faster
137 // pace.
138 WebRtc_Word64 maxChangeMs = 0;
139 if (frameTimestamp < 0x0000ffff && _prevFrameTimestamp > 0xffff0000)
140 {
141 // wrap
142 maxChangeMs = kDelayMaxChangeMsPerS * (frameTimestamp +
143 (static_cast<WebRtc_Word64>(1)<<32) - _prevFrameTimestamp) / 90000;
144 }
145 else
146 {
147 maxChangeMs = kDelayMaxChangeMsPerS *
148 (frameTimestamp - _prevFrameTimestamp) / 90000;
149 }
150 if (maxChangeMs <= 0)
151 {
152 // Any changes less than 1 ms are truncated and
153 // will be postponed. Negative change will be due
154 // to reordering and should be ignored.
155 return;
156 }
157 else if (delayDiffMs < -maxChangeMs)
158 {
159 delayDiffMs = -maxChangeMs;
160 }
161 else if (delayDiffMs > maxChangeMs)
162 {
163 delayDiffMs = maxChangeMs;
164 }
165 _currentDelayMs = _currentDelayMs + static_cast<WebRtc_Word32>(delayDiffMs);
166 }
167 _prevFrameTimestamp = frameTimestamp;
168}
169
170void VCMTiming::UpdateCurrentDelay(WebRtc_Word64 renderTimeMs,
171 WebRtc_Word64 actualDecodeTimeMs)
172{
173 CriticalSectionScoped cs(_critSect);
174 WebRtc_UWord32 targetDelayMs = TargetDelayInternal();
175 // Make sure we try to sync with audio
176 if (targetDelayMs < _minTotalDelayMs)
177 {
178 targetDelayMs = _minTotalDelayMs;
179 }
180 WebRtc_Word64 delayedMs = actualDecodeTimeMs -
181 (renderTimeMs - MaxDecodeTimeMs() - _renderDelayMs);
182 if (delayedMs < 0)
183 {
184 return;
185 }
186 else if (_currentDelayMs + delayedMs <= targetDelayMs)
187 {
188 _currentDelayMs += static_cast<WebRtc_UWord32>(delayedMs);
189 }
190 else
191 {
192 _currentDelayMs = targetDelayMs;
193 }
194}
195
196WebRtc_Word32
197VCMTiming::StopDecodeTimer(WebRtc_UWord32 timeStamp,
198 WebRtc_Word64 startTimeMs,
199 WebRtc_Word64 nowMs)
200{
201 CriticalSectionScoped cs(_critSect);
202 const WebRtc_Word32 maxDecTime = MaxDecodeTimeMs();
203 WebRtc_Word32 timeDiffMs = _codecTimer.StopTimer(startTimeMs, nowMs);
204 if (timeDiffMs < 0)
205 {
206 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
207 "Codec timer error: %d", timeDiffMs);
stefan@webrtc.org06887ae2011-10-10 14:17:46 +0000208 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 }
210
211 if (_master)
212 {
213 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
214 "Frame decoded: timeStamp=%u decTime=%d maxDecTime=%u, at %u",
215 timeStamp, timeDiffMs, maxDecTime, MaskWord64ToUWord32(nowMs));
216 }
217 return 0;
218}
219
220void
221VCMTiming::IncomingTimestamp(WebRtc_UWord32 timeStamp, WebRtc_Word64 nowMs)
222{
223 CriticalSectionScoped cs(_critSect);
224 _tsExtrapolator->Update(nowMs, timeStamp, _master);
225}
226
227WebRtc_Word64
228VCMTiming::RenderTimeMs(WebRtc_UWord32 frameTimestamp, WebRtc_Word64 nowMs) const
229{
230 CriticalSectionScoped cs(_critSect);
231 const WebRtc_Word64 renderTimeMs = RenderTimeMsInternal(frameTimestamp, nowMs);
232 if (renderTimeMs < 0)
233 {
234 return renderTimeMs;
235 }
236 if (_master)
237 {
238 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
239 "Render frame %u at %u. Render delay %u, required delay %u,"
240 " max decode time %u, min total delay %u",
241 frameTimestamp, MaskWord64ToUWord32(renderTimeMs), _renderDelayMs,
242 _requiredDelayMs, MaxDecodeTimeMs(),_minTotalDelayMs);
243 }
244 return renderTimeMs;
245}
246
247WebRtc_Word64
248VCMTiming::RenderTimeMsInternal(WebRtc_UWord32 frameTimestamp, WebRtc_Word64 nowMs) const
249{
250 WebRtc_Word64 estimatedCompleteTimeMs =
251 _tsExtrapolator->ExtrapolateLocalTime(frameTimestamp);
252 if (estimatedCompleteTimeMs - nowMs > kMaxVideoDelayMs)
253 {
254 if (_master)
255 {
256 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
257 "Timestamp arrived 2 seconds early, reset statistics",
258 frameTimestamp, estimatedCompleteTimeMs);
259 }
260 return -1;
261 }
262 if (_master)
263 {
264 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
265 "ExtrapolateLocalTime(%u)=%u ms",
266 frameTimestamp, MaskWord64ToUWord32(estimatedCompleteTimeMs));
267 }
268 if (estimatedCompleteTimeMs == -1)
269 {
270 estimatedCompleteTimeMs = nowMs;
271 }
272
273 return estimatedCompleteTimeMs + _currentDelayMs;
274}
275
276// Must be called from inside a critical section
277WebRtc_Word32
278VCMTiming::MaxDecodeTimeMs(FrameType frameType /*= kVideoFrameDelta*/) const
279{
280 const WebRtc_Word32 decodeTimeMs = _codecTimer.RequiredDecodeTimeMs(frameType);
281
282 if (decodeTimeMs < 0)
283 {
284 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
285 "Negative maximum decode time: %d", decodeTimeMs);
286 return -1;
287 }
288 return decodeTimeMs;
289}
290
291WebRtc_UWord32
292VCMTiming::MaxWaitingTime(WebRtc_Word64 renderTimeMs, WebRtc_Word64 nowMs) const
293{
294 CriticalSectionScoped cs(_critSect);
295
296 const WebRtc_Word64 maxWaitTimeMs = renderTimeMs - nowMs -
297 MaxDecodeTimeMs() - _renderDelayMs;
298
299 if (maxWaitTimeMs < 0)
300 {
301 return 0;
302 }
303 return static_cast<WebRtc_UWord32>(maxWaitTimeMs);
304}
305
306bool
307VCMTiming::EnoughTimeToDecode(WebRtc_UWord32 availableProcessingTimeMs) const
308{
309 CriticalSectionScoped cs(_critSect);
310 WebRtc_Word32 maxDecodeTimeMs = MaxDecodeTimeMs();
311 if (maxDecodeTimeMs < 0)
312 {
313 // Haven't decoded any frames yet, try decoding one to get an estimate
314 // of the decode time.
315 return true;
316 }
317 else if (maxDecodeTimeMs == 0)
318 {
319 // Decode time is less than 1, set to 1 for now since
320 // we don't have any better precision. Count ticks later?
321 maxDecodeTimeMs = 1;
322 }
323 return static_cast<WebRtc_Word32>(availableProcessingTimeMs) - maxDecodeTimeMs > 0;
324}
325
326WebRtc_UWord32
327VCMTiming::TargetVideoDelay() const
328{
329 CriticalSectionScoped cs(_critSect);
330 return TargetDelayInternal();
331}
332
333WebRtc_UWord32
334VCMTiming::TargetDelayInternal() const
335{
336 return _requiredDelayMs + MaxDecodeTimeMs() + _renderDelayMs;
337}
338
339}