MPEG DASH编码的基于frame的视频数据集下载
作者:互联网
文章目录
MPEG DASH简介
- MPEG DASH是三大流媒体协议之一:MPEG DASH, HLS,Smooth Streaming. MPEG DASH诞生的目的是为了统一标准,因此是兼容SmoothStreaming和HLS的. 同时支持TS profile和 ISO profile,支持节目观看等级控制,支持父母锁. 详细介绍请看三种主流的流媒体协议MEPG DASH,HLS,Smooth Streaming及其manifest 文件字段解释.
- Manifest.mpd (MPD:Media Presentation Description) 文件是MPEG DASH编码视频的索引文件,该文件包含了整个mpeg dash码流的构成(manifest以.mpd结尾). 其优势就是不需要流媒体服务器缓存该视频的全部视频流,客户端请求视频服务器,服务器将manifest.mpd发送给客户端,客户端可以根据视频的URL+不同的byte range指定(chunk的url)进行任意chunk的下载,更加灵活.详细请看MPEG DASH编码的基于chunk的视频数据集下载
- 但其缺点是:
- 传输时延长.由于video provider到video streaming server之间的网络拓扑复杂,所以仅考虑video streaming server到client之间的可控时延.可以表示为:
T(s,c)=Ttrcoder(s)+Ttrans(s,c)+Twaite(c)
由于转码服务器需要进行2次转码,实现不同码率视频之间的segment对齐.增加了转码服务器的资源开销,也增加了转码服务器的转码时间.只有整个chunk完整下载到客户端,客户端才能进行视频播放,增加了客户端的等待时延. - 码率选择保守.由于网络吞吐量变化极大且难以预测,离当前时刻越远,预测越不精准,所以根据网络吞吐量的预测和当前buffer的大小进行预测下一个chunk的码率,为了避免卡顿,码率将会更加保守.并且随着chunk的大小增加,更加保守.
- 码率切换将更加笨重.由于仅在chunk边界进行码率选择,所以chunk期间内的码率不一定是当前时刻的最优码率.
- 为了改进这些缺点,需要构建一套基于帧的视频传输框架,不仅解决chunk所可以解决的问题,而且可以更优的用户体验.
MPEG DASH编码的基于frame的视频数据集下载
构建基于帧的视频传输框架的前提是要有基于帧的原始视频数据集. 目前我们可以获取很多基于I帧对齐的原始视频数据集,这是因为现有的转码服务器会进行2轮转码,自动将不同码率的视频实现I帧对齐.但要去除 I帧对齐所带来的时延和资源开销,必须获取I帧不对齐的视频数据集.
数据集来源
本博文使用的原始视频数据集来源于竞赛
基于frame的数据集重构步骤
- I帧数据与非I帧数据的分离.
- I帧数据与非I帧数据的重构.关键在于:
- 如何获取GOP的长度.第一个GOP的长度通过np.random.choice()获取,其他的GOP长度,通过真实的I帧不对齐数据集中GOP长度的概率分布,进行依概率获取.
- 如何匹配I帧与非I帧. 通过遍历I帧数据,获取插入I帧位置的I帧与上下非I帧的帧到达时间差最小.
- 如何实现I帧与非I帧的帧到达时间平滑.这是通过统计获取的. 在真实的基于frame的视频数据集中, I帧的到达时间间隔和其他帧的到达时间间隔相差在毫秒级. 进而可以认为所有帧的到达间隔与帧类型无关,仅仅与视频提供者到流媒体服务器的网络有关.所以我才用帧到达时间没有与原始数据帧的时间完全对应,而是自适应的进行时间浮动,实现时间的平滑.
实现代码
以下是根据I帧对齐的视频数据集,进行重构的代码,实现不同码率视频轨迹之间I帧不对齐,GOP不等长, 同一码率视频轨迹内部,GOP也不等长,依真实视频轨迹数据集中GOP长度的概率分布,随机获取.
# 原始数据集,不同码率视频轨迹之间I帧对齐,GOP等长=50.
# 原始数据集,同一码率视频轨迹内部GOP固定=50
# 构造数据集.不同码率视频轨迹之间I帧不对齐,GOP不等长,{500kb/s:25,850kb/s:25,1200kb/s:49,1850kb/s:49}
# 构造数据集.同一码率视频轨迹内部,GOP也不等长,依真实视频轨迹数据集中GOP长度的概率分布,随机获取.
# !/usr/bin/evn python3
# -*- coding:UTF-8 -*-
import numpy as np
import os
BASE_VIDEO_TRACE = '../frame_datasets/video_final/frame_trace_'
BITRATE_LEVELS = 2
bitrate_level = 4
bitrate_gop = {0: 0, 1: 0, 2: 1, 3: 1}
# 获取[500kb/s,1200kb/s]的真实视频数据集的GOP长度分布
def GOP_len_describe():
frame_arrive_time = []
frame_size = []
frame_time_len = []
gop_flag = []
for bitrate in range(BITRATE_LEVELS):
frame_arrive_time.append([])
frame_size.append([])
frame_time_len.append([])
gop_flag.append([])
with open(BASE_VIDEO_TRACE + str(bitrate)) as f:
for line in f:
frame_arrive_time[bitrate].append(float(line.split()[0]))
frame_size[bitrate].append(float(line.split()[1]))
frame_time_len[bitrate].append(1.0/float(line.split()[3]))
gop_flag[bitrate].append(int(float(line.split()[2])))
GOP_len = {}
for bitrate in range(BITRATE_LEVELS):
GOP_len[bitrate] = {}
num = 0
for i in range(len(gop_flag[bitrate])):
num += 1
if gop_flag[bitrate][i] == 1:
if num in GOP_len[bitrate]:
GOP_len[bitrate][num] += 1
else:
GOP_len[bitrate][num] = 1
num = 0
return GOP_len
# GOP长度的依概率选择. gop is in [0,1]. 用于表示服从哪一个分布.
# gop == 0:表示服从码率为500kb/s的GOP分布,GOP长度的众数为25
# gop == 1:表示服从码率为1200kb/s的GOP分布,GOP长度的众数为49
def GOP_len_choise(gop):
GOP_len = GOP_len_describe()
gop_len = GOP_len[gop]
gop_len_value = [i for i in gop_len.values()]
gop_len_key = [i for i in gop_len.keys()]
probs = [i/np.sum([gop_len_value]) for i in gop_len_value]
choise = np.random.choice(gop_len_key, p=probs)
return choise
# 选择离当前P帧在时间上最近的I帧.
def choise_near_frame(time_list, time):
id = 0
for i in range(len(time_list)):
if np.abs(time_list[i] - time) < np.abs(time_list[id] - time):
id = i
return id
# 视频数据集重构,I帧对齐的视频数据集,重构为I帧不对齐的视频数据集
# 其中帧到达时间没有与原始数据帧的时间完全对应,这是因为I帧的到达时间间隔和其他帧的到达时间间隔相差在毫秒级
# 进而可以认为所有帧的到达间隔与帧类型无关,仅仅与视频提供者到流媒体服务器的网络有关.
def video_gen(video_traces, video_traces_new):
# 帧到达时间
frame_arrive_time = []
# I帧到达时间
key_frame_arrive_time = []
key_frame_size = []
# 非I帧到达时间
other_frame_arrive_time = []
other_frame_size = []
for bitrate in range(bitrate_level):
frame_arrive_time.append([])
key_frame_arrive_time.append([])
key_frame_size.append([])
other_frame_arrive_time.append([])
other_frame_size.append([])
# I帧与非I帧的信息读取
with open(video_traces + str(bitrate), 'r') as f:
for line in f:
frame_arrive_time[bitrate].append(float(line.split()[0]))
if int(line.split()[2]) == 1:
key_frame_arrive_time[bitrate].append(float(line.split()[0]))
key_frame_size[bitrate].append(float(line.split()[1]))
else:
other_frame_arrive_time[bitrate].append(float(line.split()[0]))
other_frame_size[bitrate].append(float(line.split()[1]))
# 视频数据重构
with open(video_traces_new + str(bitrate), 'w') as f1:
n = 0 # 表示非I帧的序列号
m = 0 # 表示帧的序列号
choise = np.random.choice(25) # 选择GOP的长度
while 1:
# 在GOP边界,插入I帧
if choise == 1:
id = choise_near_frame(key_frame_arrive_time[bitrate], other_frame_arrive_time[bitrate][n])
f1.write(str(frame_arrive_time[bitrate][m]) + ' ' + \
str(key_frame_size[bitrate][id]) + ' ' + \
str(25) + ' ' + \
str(1) + '\n')
choise = GOP_len_choise(bitrate_gop[bitrate])
m += 1
# 其他情况,插入非I帧
else:
f1.write(str(frame_arrive_time[bitrate][m]) + ' ' + \
str(other_frame_size[bitrate][n]) + ' ' + \
str(25) + ' ' + \
str(0) + '\n')
choise -= 1
n += 1
m += 1
if m >= len(frame_arrive_time[bitrate])-1:
break
def main():
video_type = ["room", "game", "sports"]
for i in range(len(video_type)):
video_traces = "../frame_datasets/" + video_type[i] + "/frame_trace_"
video_traces_new = "./" + video_type[i] + "/frame_trace_"
if not os.path.exists(video_type[i]):
os.makedirs(video_type[i])
video_gen(video_traces, video_traces_new)
main()
如有任何问题,欢迎留言.
标签:视频,MPEG,frame,len,DASH,time,bitrate,GOP 来源: https://blog.csdn.net/qq_31813549/article/details/100166858