blob: 98a69e962fd8fcfe735ae9c40f3d48632829a286 [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
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000013
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000014#include "webrtc/modules/video_coding/main/source/internal_defines.h"
15#include "webrtc/modules/video_coding/main/source/jitter_buffer_common.h"
16#include "webrtc/modules/video_coding/main/source/timestamp_extrapolator.h"
17#include "webrtc/system_wrappers/interface/clock.h"
18#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000020
21
niklase@google.com470e71d2011-07-07 08:21:25 +000022namespace webrtc {
23
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000024VCMTiming::VCMTiming(Clock* clock,
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000025 int32_t vcm_id,
26 int32_t timing_id,
27 VCMTiming* master_timing)
28 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
29 vcm_id_(vcm_id),
30 clock_(clock),
31 timing_id_(timing_id),
32 master_(false),
33 ts_extrapolator_(),
34 codec_timer_(),
35 render_delay_ms_(kDefaultRenderDelayMs),
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000036 min_playout_delay_ms_(0),
37 jitter_delay_ms_(0),
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000038 current_delay_ms_(0),
fischman@webrtc.org37bb4972013-10-23 23:59:45 +000039 last_decode_ms_(0),
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000040 prev_frame_timestamp_(0) {
41 if (master_timing == NULL) {
42 master_ = true;
43 ts_extrapolator_ = new VCMTimestampExtrapolator(clock_, vcm_id, timing_id);
44 } else {
45 ts_extrapolator_ = master_timing->ts_extrapolator_;
46 }
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000049VCMTiming::~VCMTiming() {
50 if (master_) {
51 delete ts_extrapolator_;
52 }
53 delete crit_sect_;
niklase@google.com470e71d2011-07-07 08:21:25 +000054}
55
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000056void VCMTiming::Reset() {
57 CriticalSectionScoped cs(crit_sect_);
58 ts_extrapolator_->Reset();
59 codec_timer_.Reset();
60 render_delay_ms_ = kDefaultRenderDelayMs;
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000061 min_playout_delay_ms_ = 0;
62 jitter_delay_ms_ = 0;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000063 current_delay_ms_ = 0;
64 prev_frame_timestamp_ = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000065}
66
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000067void VCMTiming::ResetDecodeTime() {
68 codec_timer_.Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +000069}
70
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000071void VCMTiming::set_render_delay(uint32_t render_delay_ms) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000072 CriticalSectionScoped cs(crit_sect_);
73 render_delay_ms_ = render_delay_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +000074}
75
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000076void VCMTiming::set_min_playout_delay(uint32_t min_playout_delay_ms) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000077 CriticalSectionScoped cs(crit_sect_);
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000078 min_playout_delay_ms_ = min_playout_delay_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +000079}
80
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000081void VCMTiming::SetJitterDelay(uint32_t jitter_delay_ms) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000082 CriticalSectionScoped cs(crit_sect_);
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000083 if (jitter_delay_ms != jitter_delay_ms_) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000084 if (master_) {
85 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
86 VCMId(vcm_id_, timing_id_),
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000087 "Desired jitter buffer level: %u ms", jitter_delay_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +000088 }
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000089 jitter_delay_ms_ = jitter_delay_ms;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000090 // When in initial state, set current delay to minimum delay.
91 if (current_delay_ms_ == 0) {
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000092 current_delay_ms_ = jitter_delay_ms_;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000093 }
94 }
niklase@google.com470e71d2011-07-07 08:21:25 +000095}
96
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000097void VCMTiming::UpdateCurrentDelay(uint32_t frame_timestamp) {
98 CriticalSectionScoped cs(crit_sect_);
99 uint32_t target_delay_ms = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000101 if (current_delay_ms_ == 0) {
102 // Not initialized, set current delay to target.
103 current_delay_ms_ = target_delay_ms;
104 } else if (target_delay_ms != current_delay_ms_) {
105 int64_t delay_diff_ms = static_cast<int64_t>(target_delay_ms) -
106 current_delay_ms_;
107 // Never change the delay with more than 100 ms every second. If we're
108 // changing the delay in too large steps we will get noticeable freezes. By
109 // limiting the change we can increase the delay in smaller steps, which
110 // will be experienced as the video is played in slow motion. When lowering
111 // the delay the video will be played at a faster pace.
112 int64_t max_change_ms = 0;
113 if (frame_timestamp < 0x0000ffff && prev_frame_timestamp_ > 0xffff0000) {
114 // wrap
115 max_change_ms = kDelayMaxChangeMsPerS * (frame_timestamp +
116 (static_cast<int64_t>(1) << 32) - prev_frame_timestamp_) / 90000;
117 } else {
118 max_change_ms = kDelayMaxChangeMsPerS *
119 (frame_timestamp - prev_frame_timestamp_) / 90000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 }
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000121 if (max_change_ms <= 0) {
122 // Any changes less than 1 ms are truncated and
123 // will be postponed. Negative change will be due
124 // to reordering and should be ignored.
125 return;
126 }
127 delay_diff_ms = std::max(delay_diff_ms, -max_change_ms);
128 delay_diff_ms = std::min(delay_diff_ms, max_change_ms);
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000129
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000130 current_delay_ms_ = current_delay_ms_ + static_cast<int32_t>(delay_diff_ms);
131 }
132 prev_frame_timestamp_ = frame_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000133}
134
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000135void VCMTiming::UpdateCurrentDelay(int64_t render_time_ms,
136 int64_t actual_decode_time_ms) {
137 CriticalSectionScoped cs(crit_sect_);
138 uint32_t target_delay_ms = TargetDelayInternal();
139 int64_t delayed_ms = actual_decode_time_ms -
140 (render_time_ms - MaxDecodeTimeMs() - render_delay_ms_);
141 if (delayed_ms < 0) {
142 return;
143 }
144 if (current_delay_ms_ + delayed_ms <= target_delay_ms) {
145 current_delay_ms_ += static_cast<uint32_t>(delayed_ms);
146 } else {
147 current_delay_ms_ = target_delay_ms;
148 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000149}
150
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000151int32_t VCMTiming::StopDecodeTimer(uint32_t time_stamp,
152 int64_t start_time_ms,
153 int64_t now_ms) {
154 CriticalSectionScoped cs(crit_sect_);
155 const int32_t max_dec_time = MaxDecodeTimeMs();
156 int32_t time_diff_ms = codec_timer_.StopTimer(start_time_ms, now_ms);
157 if (time_diff_ms < 0) {
158 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(vcm_id_,
159 timing_id_), "Codec timer error: %d", time_diff_ms);
160 assert(false);
161 }
fischman@webrtc.org37bb4972013-10-23 23:59:45 +0000162 last_decode_ms_ = time_diff_ms;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000163 if (master_) {
164 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(vcm_id_,
165 timing_id_),
166 "Frame decoded: time_stamp=%u dec_time=%d max_dec_time=%u, at %u",
167 time_stamp, time_diff_ms, max_dec_time, MaskWord64ToUWord32(now_ms));
168 }
169 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000170}
171
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000172void VCMTiming::IncomingTimestamp(uint32_t time_stamp, int64_t now_ms) {
173 CriticalSectionScoped cs(crit_sect_);
174 ts_extrapolator_->Update(now_ms, time_stamp, master_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000175}
176
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000177int64_t VCMTiming::RenderTimeMs(uint32_t frame_timestamp, int64_t now_ms)
178 const {
179 CriticalSectionScoped cs(crit_sect_);
180 const int64_t render_time_ms = RenderTimeMsInternal(frame_timestamp, now_ms);
181 if (master_) {
182 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(vcm_id_,
183 timing_id_), "Render frame %u at %u. Render delay %u",
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000184 "jitter delay %u, max decode time %u, playout delay %u",
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000185 frame_timestamp, MaskWord64ToUWord32(render_time_ms), render_delay_ms_,
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000186 jitter_delay_ms_, MaxDecodeTimeMs(), min_playout_delay_ms_);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000187 }
188 return render_time_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +0000189}
190
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000191int64_t VCMTiming::RenderTimeMsInternal(uint32_t frame_timestamp,
192 int64_t now_ms) const {
193 int64_t estimated_complete_time_ms =
194 ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp);
195 if (master_) {
196 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
197 VCMId(vcm_id_, timing_id_), "ExtrapolateLocalTime(%u)=%u ms",
198 frame_timestamp, MaskWord64ToUWord32(estimated_complete_time_ms));
199 }
200 if (estimated_complete_time_ms == -1) {
201 estimated_complete_time_ms = now_ms;
202 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000203
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000204 // Make sure that we have at least the playout delay.
205 uint32_t actual_delay = std::max(current_delay_ms_, min_playout_delay_ms_);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000206 return estimated_complete_time_ms + actual_delay;
niklase@google.com470e71d2011-07-07 08:21:25 +0000207}
208
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000209// Must be called from inside a critical section.
210int32_t VCMTiming::MaxDecodeTimeMs(FrameType frame_type /*= kVideoFrameDelta*/)
211 const {
212 const int32_t decode_time_ms = codec_timer_.RequiredDecodeTimeMs(frame_type);
213 if (decode_time_ms < 0) {
214 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(vcm_id_,
215 timing_id_), "Negative maximum decode time: %d", decode_time_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000216 return -1;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000217 }
218 return decode_time_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +0000219}
220
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000221uint32_t VCMTiming::MaxWaitingTime(int64_t render_time_ms, int64_t now_ms)
222 const {
223 CriticalSectionScoped cs(crit_sect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000224
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000225 const int64_t max_wait_time_ms = render_time_ms - now_ms -
226 MaxDecodeTimeMs() - render_delay_ms_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000227
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000228 if (max_wait_time_ms < 0) {
229 return 0;
230 }
231 return static_cast<uint32_t>(max_wait_time_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000232}
233
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000234bool VCMTiming::EnoughTimeToDecode(uint32_t available_processing_time_ms)
235 const {
236 CriticalSectionScoped cs(crit_sect_);
237 int32_t max_decode_time_ms = MaxDecodeTimeMs();
238 if (max_decode_time_ms < 0) {
239 // Haven't decoded any frames yet, try decoding one to get an estimate
240 // of the decode time.
241 return true;
242 } else if (max_decode_time_ms == 0) {
243 // Decode time is less than 1, set to 1 for now since
244 // we don't have any better precision. Count ticks later?
245 max_decode_time_ms = 1;
246 }
247 return static_cast<int32_t>(available_processing_time_ms) -
248 max_decode_time_ms > 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249}
250
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000251uint32_t VCMTiming::TargetVideoDelay() const {
252 CriticalSectionScoped cs(crit_sect_);
253 return TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000254}
255
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000256uint32_t VCMTiming::TargetDelayInternal() const {
hclam@chromium.org30fb7b82013-06-18 21:37:09 +0000257 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
258 VCMId(vcm_id_, timing_id_),
259 "Delay: min_playout=%u jitter=%u max_decode=%u render=%u",
260 min_playout_delay_ms_, jitter_delay_ms_, MaxDecodeTimeMs(),
261 render_delay_ms_);
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000262 return std::max(min_playout_delay_ms_,
263 jitter_delay_ms_ + MaxDecodeTimeMs() + render_delay_ms_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000264}
265
fischman@webrtc.org37bb4972013-10-23 23:59:45 +0000266void VCMTiming::GetTimings(int* decode_ms,
267 int* max_decode_ms,
268 int* current_delay_ms,
269 int* target_delay_ms,
270 int* jitter_buffer_ms,
271 int* min_playout_delay_ms,
272 int* render_delay_ms) const {
273 CriticalSectionScoped cs(crit_sect_);
274 *decode_ms = last_decode_ms_;
275 *max_decode_ms = MaxDecodeTimeMs();
276 *current_delay_ms = current_delay_ms_;
277 *target_delay_ms = TargetDelayInternal();
278 *jitter_buffer_ms = jitter_delay_ms_;
279 *min_playout_delay_ms = min_playout_delay_ms_;
280 *render_delay_ms = render_delay_ms_;
281}
282
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000283} // namespace webrtc