1/*
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
11#include "webrtc/modules/video_coding/main/source/codec_timer.h"
12
13#include <assert.h>
14
15namespace webrtc
16{
17
18// The first kIgnoredSampleCount samples will be ignored.
19static const int32_t kIgnoredSampleCount = 5;
20
21VCMCodecTimer::VCMCodecTimer()
22:
23_filteredMax(0),
24_ignoredSampleCount(0),
25_shortMax(0),
26_history()
27{
28    Reset();
29}
30
31int32_t VCMCodecTimer::StopTimer(int64_t startTimeMs, int64_t nowMs)
32{
33    const int32_t timeDiff = static_cast<int32_t>(nowMs - startTimeMs);
34    MaxFilter(timeDiff, nowMs);
35    return timeDiff;
36}
37
38void VCMCodecTimer::Reset()
39{
40    _filteredMax = 0;
41    _ignoredSampleCount = 0;
42    _shortMax = 0;
43    for (int i=0; i < MAX_HISTORY_SIZE; i++)
44    {
45        _history[i].shortMax = 0;
46        _history[i].timeMs = -1;
47    }
48}
49
50// Update the max-value filter
51void VCMCodecTimer::MaxFilter(int32_t decodeTime, int64_t nowMs)
52{
53    if (_ignoredSampleCount >= kIgnoredSampleCount)
54    {
55        UpdateMaxHistory(decodeTime, nowMs);
56        ProcessHistory(nowMs);
57    }
58    else
59    {
60        _ignoredSampleCount++;
61    }
62}
63
64void
65VCMCodecTimer::UpdateMaxHistory(int32_t decodeTime, int64_t now)
66{
67    if (_history[0].timeMs >= 0 &&
68        now - _history[0].timeMs < SHORT_FILTER_MS)
69    {
70        if (decodeTime > _shortMax)
71        {
72            _shortMax = decodeTime;
73        }
74    }
75    else
76    {
77        // Only add a new value to the history once a second
78        if(_history[0].timeMs == -1)
79        {
80            // First, no shift
81            _shortMax = decodeTime;
82        }
83        else
84        {
85            // Shift
86            for(int i = (MAX_HISTORY_SIZE - 2); i >= 0 ; i--)
87            {
88                _history[i+1].shortMax = _history[i].shortMax;
89                _history[i+1].timeMs = _history[i].timeMs;
90            }
91        }
92        if (_shortMax == 0)
93        {
94            _shortMax = decodeTime;
95        }
96
97        _history[0].shortMax = _shortMax;
98        _history[0].timeMs = now;
99        _shortMax = 0;
100    }
101}
102
103void
104VCMCodecTimer::ProcessHistory(int64_t nowMs)
105{
106    _filteredMax = _shortMax;
107    if (_history[0].timeMs == -1)
108    {
109        return;
110    }
111    for (int i=0; i < MAX_HISTORY_SIZE; i++)
112    {
113        if (_history[i].timeMs == -1)
114        {
115            break;
116        }
117        if (nowMs - _history[i].timeMs > MAX_HISTORY_SIZE * SHORT_FILTER_MS)
118        {
119            // This sample (and all samples after this) is too old
120            break;
121        }
122        if (_history[i].shortMax > _filteredMax)
123        {
124            // This sample is the largest one this far into the history
125            _filteredMax = _history[i].shortMax;
126        }
127    }
128}
129
130// Get the maximum observed time within a time window
131int32_t VCMCodecTimer::RequiredDecodeTimeMs(FrameType /*frameType*/) const
132{
133    return _filteredMax;
134}
135
136}
137