-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathABR.py
160 lines (130 loc) · 5.9 KB
/
ABR.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import sys
class Algorithm:
def __init__(self):
# fill your self params
# same value
self.BITRATE = [500.0, 850.0, 1200.0, 1850.0]
self.frame_time_len = 0.04
self.SKIP_PENALTY = 0.5
self.BITRATE_LEVEL = 4
self.segment_length = 51
self.segment_time_len = self.frame_time_len * self.segment_length
# variable value
self.prev_rate = 0
self.prev_cdn_newest_id = 0
self.prev_R_hat = [0] * self.BITRATE_LEVEL # (self.BITRATE_LEVEL, )
# value need to tune
self.LAMBDA = 3.3 #tested
self.l_min = 4.0
self.l_max = 10.0
self.N_WMA = 1
self.N_1 = 1
self.beta = 0.5
self.buffer_threshold = 1.4
# Initail
def Initial(self):
# Initail your session or something
self.l_min = 4.0
self.l_max = 10.0
self.beta = 0.5
# calculated value
self.R_history = [[0] * self.N_1 for _ in range(self.BITRATE_LEVEL)] # (self.BITRATE_LEVEL, self.N_1)
self.C_denominator = self.N_WMA * (self.N_WMA + 1) / 2
self.SC_slowest = 2/(self.l_max + 1)
self.SC_fastest = 2/(self.l_min + 1)
# Define your algo
def run(self, time, S_time_interval, S_send_data_size, S_chunk_len, S_rebuf, S_buffer_size,
S_play_time_len,S_end_delay, S_decision_flag, S_buffer_flag, S_cdn_flag, S_skip_time,
end_of_video, cdn_newest_id, download_id, cdn_has_frame, IntialVars):
# print(f"S_send_data_size : {S_send_data_size}")
# print(f"S_send_data_size : {S_send_data_size}, S_chunk_len : {S_chunk_len}, cdn_has_frame : {cdn_has_frame}")
# If you choose the marchine learning
'''
V_nm is coding bitrate
R_nm is actual bitrate
R^hat is predicted actual bitrate, use n to predict n+1
SC is smoothing factor
ER is efficient ratio
N_1 is # of samples used to calculate ER
D is estimated latency(need to minimize)
d is segment length (50*frame_time_len ?)
T is downloading time of next segment
C is throughput estimate by weighted moving average
N_WMA # of sample used to estimated C
B is estimated buffer occupancy
v estimated frame accumulation speed in CDN
'''
buf_now = S_buffer_size[-1]
bit_rate = 0
# bitrate control
# estimate c (throughput) using weighted moving average (bps)
C_numerator = 0
for i in range(self.N_WMA):
if S_time_interval[-i-1] != 0:
C_numerator += (self.N_WMA - i) * (S_send_data_size[-i-1] / S_time_interval[-i-1])
estimated_C = C_numerator / self.C_denominator
estimated_C = max(0.000001, estimated_C)
## estimate R_hat for every bitrate using KAMA
## R : bps
min_estimate_latency = sys.maxsize
prev_R = sum(S_send_data_size[-50:]) / self.segment_time_len
for b in range(self.BITRATE_LEVEL):
self.R_history[b].append(prev_R * (self.BITRATE[b] / self.BITRATE[self.prev_rate]))
# calculate ER = change / volatility
change = abs(self.R_history[b][-1] - self.R_history[b][0])
volatility = 0
for i in range(self.N_1):
volatility += abs(self.R_history[b][i] - self.R_history[b][i+1])
volatility = max(0.000001, volatility)
ER = change / volatility
self.R_history[b].pop(0)
# calculate SC
SC = (ER*(self.SC_fastest - self.SC_slowest) + self.SC_slowest) ** 2
# R_hat = R_n+1_m
R_hat = (1 - SC) * self.prev_R_hat[b] + SC * self.R_history[b][-1]
# calculate T
T = R_hat * self.frame_time_len*self.segment_length / estimated_C
# calculate B
if buf_now < 0.5:
gamma = 0.95
elif buf_now > 1.0:
gamma = 1.05
else:
gamma = 1
B = max(buf_now + self.frame_time_len*self.segment_length - gamma * T, 0)
# calculate
v = self.beta * (cdn_newest_id - self.prev_cdn_newest_id) * self.frame_time_len / sum(S_time_interval[-50:])
# latency caused by accumulated video at CDN after next downloading interval
D_cdn = max((cdn_newest_id - download_id)*self.frame_time_len + v*T - self.frame_time_len*self.segment_length, 0)
if min_estimate_latency > B + D_cdn and B > self.buffer_threshold:
min_estimate_latency = B + D_cdn
bit_rate = b
# for next segment
self.prev_R_hat[b] = R_hat
# determine target buffer by buffer size
# if in [B^0_min, B^0_max), target_buffer = 1
# otherwise, target_buffer = 0
buf_now = S_buffer_size[-1]
if 0.3 <= buf_now and buf_now < 1.0:
target_buffer = 1
else:
target_buffer = 0
# QoE based latency limit
# LAMBDA may need tuning (3.3 is currently best)
'''
LATENCY_PENALTY = 0.005
if S_end_delay[-1] <=1.0:
LATENCY_PENALTY = 0.005
else:
LATENCY_PENALTY = 0.01
latency_limit = self.frame_time_len * (self.BITRATE[bit_rate]/1000.0 + self.SKIP_PENALTY) / (LATENCY_PENALTY * self.LAMBDA)
'''
latency_limit = 1.8 # fixed latency is better than prediction
# for next iteration
self.prev_rate = bit_rate
self.prev_cdn_newest_id = cdn_newest_id
return bit_rate, target_buffer, latency_limit
def get_params(self):
# get your params
your_params = []
return your_params