blob: 5b2cd0cbe2db645d8899c04f43ffd8f32fb85bf7 [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
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000060VCMTiming::Reset(int64_t nowMs /* = -1 */)
niklase@google.com470e71d2011-07-07 08:21:25 +000061{
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
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000085VCMTiming::SetRenderDelay(uint32_t renderDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000086{
87 CriticalSectionScoped cs(_critSect);
88 _renderDelayMs = renderDelayMs;
89}
90
91void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000092VCMTiming::SetMinimumTotalDelay(uint32_t minTotalDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000093{
94 CriticalSectionScoped cs(_critSect);
95 _minTotalDelayMs = minTotalDelayMs;
96}
97
98void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000099VCMTiming::SetRequiredDelay(uint32_t requiredDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000100{
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;
mikhal@webrtc.orgdbd6a6d2013-04-17 16:23:22 +0000110 // When in initial state, set current delay to minimum delay.
111 if (_currentDelayMs == 0) {
112 _currentDelayMs = _requiredDelayMs;
113 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000114 }
115}
116
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000117void VCMTiming::UpdateCurrentDelay(uint32_t frameTimestamp)
niklase@google.com470e71d2011-07-07 08:21:25 +0000118{
119 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000120 uint32_t targetDelayMs = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000121
niklase@google.com470e71d2011-07-07 08:21:25 +0000122 if (_currentDelayMs == 0)
123 {
124 // Not initialized, set current delay to target.
125 _currentDelayMs = targetDelayMs;
126 }
127 else if (targetDelayMs != _currentDelayMs)
128 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000129 int64_t delayDiffMs = static_cast<int64_t>(targetDelayMs) -
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 _currentDelayMs;
131 // Never change the delay with more than 100 ms every second. If we're changing the
mikhal@webrtc.orgef9f76a2013-02-15 23:22:18 +0000132 // delay in too large steps we will get noticeable freezes. By limiting the change we
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 // can increase the delay in smaller steps, which will be experienced as the video is
134 // played in slow motion. When lowering the delay the video will be played at a faster
135 // pace.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000136 int64_t maxChangeMs = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 if (frameTimestamp < 0x0000ffff && _prevFrameTimestamp > 0xffff0000)
138 {
139 // wrap
140 maxChangeMs = kDelayMaxChangeMsPerS * (frameTimestamp +
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000141 (static_cast<int64_t>(1)<<32) - _prevFrameTimestamp) / 90000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000142 }
143 else
144 {
145 maxChangeMs = kDelayMaxChangeMsPerS *
146 (frameTimestamp - _prevFrameTimestamp) / 90000;
147 }
148 if (maxChangeMs <= 0)
149 {
150 // Any changes less than 1 ms are truncated and
151 // will be postponed. Negative change will be due
152 // to reordering and should be ignored.
153 return;
154 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000155 delayDiffMs = std::max(delayDiffMs, -maxChangeMs);
156 delayDiffMs = std::min(delayDiffMs, maxChangeMs);
157
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000158 _currentDelayMs = _currentDelayMs + static_cast<int32_t>(delayDiffMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000159 }
160 _prevFrameTimestamp = frameTimestamp;
161}
162
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000163void VCMTiming::UpdateCurrentDelay(int64_t renderTimeMs,
164 int64_t actualDecodeTimeMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000165{
166 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000167 uint32_t targetDelayMs = TargetDelayInternal();
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000168
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000169 int64_t delayedMs = actualDecodeTimeMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 (renderTimeMs - MaxDecodeTimeMs() - _renderDelayMs);
171 if (delayedMs < 0)
172 {
173 return;
174 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000175 if (_currentDelayMs + delayedMs <= targetDelayMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000177 _currentDelayMs += static_cast<uint32_t>(delayedMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 }
179 else
180 {
181 _currentDelayMs = targetDelayMs;
182 }
183}
184
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000185int32_t
186VCMTiming::StopDecodeTimer(uint32_t timeStamp,
187 int64_t startTimeMs,
188 int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000189{
190 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000191 const int32_t maxDecTime = MaxDecodeTimeMs();
192 int32_t timeDiffMs = _codecTimer.StopTimer(startTimeMs, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 if (timeDiffMs < 0)
194 {
195 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
196 "Codec timer error: %d", timeDiffMs);
stefan@webrtc.org06887ae2011-10-10 14:17:46 +0000197 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 }
199
200 if (_master)
201 {
202 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
203 "Frame decoded: timeStamp=%u decTime=%d maxDecTime=%u, at %u",
204 timeStamp, timeDiffMs, maxDecTime, MaskWord64ToUWord32(nowMs));
205 }
206 return 0;
207}
208
209void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000210VCMTiming::IncomingTimestamp(uint32_t timeStamp, int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000211{
212 CriticalSectionScoped cs(_critSect);
213 _tsExtrapolator->Update(nowMs, timeStamp, _master);
214}
215
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000216int64_t
217VCMTiming::RenderTimeMs(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000218{
219 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000220 const int64_t renderTimeMs = RenderTimeMsInternal(frameTimestamp, nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 if (_master)
222 {
223 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
224 "Render frame %u at %u. Render delay %u, required delay %u,"
225 " max decode time %u, min total delay %u",
226 frameTimestamp, MaskWord64ToUWord32(renderTimeMs), _renderDelayMs,
227 _requiredDelayMs, MaxDecodeTimeMs(),_minTotalDelayMs);
228 }
229 return renderTimeMs;
230}
231
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000232int64_t
233VCMTiming::RenderTimeMsInternal(uint32_t frameTimestamp, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000234{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000235 int64_t estimatedCompleteTimeMs =
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 _tsExtrapolator->ExtrapolateLocalTime(frameTimestamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000237 if (_master)
238 {
239 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
240 "ExtrapolateLocalTime(%u)=%u ms",
241 frameTimestamp, MaskWord64ToUWord32(estimatedCompleteTimeMs));
242 }
243 if (estimatedCompleteTimeMs == -1)
244 {
245 estimatedCompleteTimeMs = nowMs;
246 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000247
248 // Make sure that we have at least the total minimum delay.
249 uint32_t actual_delay = std::max(_currentDelayMs, _minTotalDelayMs);
250 return estimatedCompleteTimeMs + actual_delay;
niklase@google.com470e71d2011-07-07 08:21:25 +0000251}
252
253// Must be called from inside a critical section
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000254int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000255VCMTiming::MaxDecodeTimeMs(FrameType frameType /*= kVideoFrameDelta*/) const
256{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000257 const int32_t decodeTimeMs = _codecTimer.RequiredDecodeTimeMs(frameType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000258
259 if (decodeTimeMs < 0)
260 {
261 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
262 "Negative maximum decode time: %d", decodeTimeMs);
263 return -1;
264 }
265 return decodeTimeMs;
266}
267
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000268uint32_t
269VCMTiming::MaxWaitingTime(int64_t renderTimeMs, int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000270{
271 CriticalSectionScoped cs(_critSect);
272
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000273 const int64_t maxWaitTimeMs = renderTimeMs - nowMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 MaxDecodeTimeMs() - _renderDelayMs;
275
276 if (maxWaitTimeMs < 0)
277 {
278 return 0;
279 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000280 return static_cast<uint32_t>(maxWaitTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000281}
282
283bool
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000284VCMTiming::EnoughTimeToDecode(uint32_t availableProcessingTimeMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000285{
286 CriticalSectionScoped cs(_critSect);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000287 int32_t maxDecodeTimeMs = MaxDecodeTimeMs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000288 if (maxDecodeTimeMs < 0)
289 {
290 // Haven't decoded any frames yet, try decoding one to get an estimate
291 // of the decode time.
292 return true;
293 }
294 else if (maxDecodeTimeMs == 0)
295 {
296 // Decode time is less than 1, set to 1 for now since
297 // we don't have any better precision. Count ticks later?
298 maxDecodeTimeMs = 1;
299 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000300 return static_cast<int32_t>(availableProcessingTimeMs) - maxDecodeTimeMs > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000301}
302
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000303uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000304VCMTiming::TargetVideoDelay() const
305{
306 CriticalSectionScoped cs(_critSect);
307 return TargetDelayInternal();
308}
309
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000310uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000311VCMTiming::TargetDelayInternal() const
312{
pwestin@webrtc.orgd35964a2013-04-30 16:06:10 +0000313 return std::max(_minTotalDelayMs,
314 _requiredDelayMs + MaxDecodeTimeMs() + _renderDelayMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000315}
316
317}