hls协议
Ⅰ HLS,RTMP,HTTP这些协议有什么区别
HLS (HTTP Live Streaming)
Apple的动态码率自适应技术。主要用于PC和Apple终端的音视频服务。包括一个m3u(8)的索引文件,TS媒体分片文件和key加密串文件。
常用的流媒体协议主要有 HTTP 渐进下载和基于 RTSP/RTP 的实时流媒体协议,这二种基本是完全不同的东西,目前比较方便又好用的是用 HTTP 渐进下载方法。在这个中 apple 公司的 HTTP Live Streaming 是这个方面的代表。它最初是苹果公司针对iPhone、iPod、iTouch和iPad等移动设备而开发的流.现在见到在桌面也有很多应用了,HTML5 是直接支持这个。
但是HLS协议的小切片方式会生成大量的文件,存储或处理这些文件会造成大量资源浪费。如果要实现数天的时移,索引量将会是个巨额数字,并明显影响请求速度。因此,HLS协议对存储I/O要求相当苛刻。对此,也有公司提出了非常好的解决方案。
新型点播服务器系统,独创了内存缓存数据实时切片技术,颠覆了这种传统实现方法,从根本上解决了大量切片的碎片问题,使得单台服务器的切片与打包能力不再是瓶颈。其基本原理如下:
不将TS切片文件存到磁盘,而是存在内存当中,这种技术使得服务器的磁盘上面不再会有“数以吨计”的文件碎片,极大减少了磁盘的I/O次数,延长了服务器磁盘的使用寿命,极大提高了服务器运行的稳定性。同时,由于使用这种技术,使得终端请求数据时直接从服务器的内存中获取,极大提高了对终端数据请求的反应速度,优化了视频观看体验。
RTSP协议,这应该是实时性最好的了,如果要想实时性要求很高,比如0.5s以内,这个是不错的选择。前阵子模仿spydroid写了个建议的rtsp 服务器,其实就是options,describe,setup,play,pause,teardown这几步了,这个协议用的最广泛,网上介绍也比较 多。要想真正深入了解rtsp协议,c++语言功底好的可以查看live555 。
Ⅱ Edge浏览器为什么要支持苹果HLS协议
HLS协议允许流媒体分段下载,不过这种HTTP分段点播的方式已经用于很多流媒体服务网站。版但HLS的特别之处在权于,它的分段非常小,而这种小的分段方式也让HLS独特的在线视频直播方式成为可能。
HLS直播最大的特色,同时也是不同传统网络直播的方式在于,直播客户端获取到的,一直都不是一个完整的数据流。HLS协议在服务器端将直播数据流截取并存储为连续的、时长很短的媒体文件,客户端则不断下载并播放这些小文件,因为服务器端总是会将最新的直播数据生成新的小文件,这样客户端只要不停的按顺序播放从服务器获取到的文件,并利用生成的m3u8文件进行索引,从而实现完整地视频直播。
此外与实时传输协议(RTP)不同,HLS只请求基本的HTTP报文,因此可以穿过任何允许HTTP数据通过的防火墙或者代理服务器,而它也很容易使用内容分发网络来传输媒体流。
Ⅲ 求推荐几个同时支持hls和rtmp协议的监控摄像头
iOS在调用一个摄像头的同时另外一个摄像头会停止工作。
Ⅳ HLS什么意思
HTTP Live Streaming(缩写是抄HLS)是一个由袭苹果公司提出的基于HTTP的流媒体网络传输协议。
HLS协议是苹果推出的解决方案,将视频分成5-10秒的视频小分片,然后用m3u8索引表进行管理,由于客户端下载到的视频都是5-10秒的完整数据,故视频的流畅性很好,但也同样引入了很大的延迟(HLS的一般延迟在10-30s左右)。
相比于FLV,HLS在iPhone和大部分android手机浏览器上的支持非常给力。
(4)hls协议扩展阅读:
HLS协议客户端支持简单, 只需要支持 HTTP 请求即可, HTTP 协议无状态, 只需要按顺序下载媒体片段即可,而且网络兼容性好, HTTP 数据包也可以方便地通过防火墙或者代理服务器。
但是相比RTMP 这类长连接协议, 用到互动直播场景延时较高。HLS(HTTP Live Streaming)是苹果公司推出的流媒体协议, 用于直播或点播场景, 应该算是当前平台兼容性最好的流媒体协议了. 其他主流的流媒体协议还有RTP(内容传输使用UDP)和Adobe的RTMP(基于TCP).
Ⅳ Firefox是不是不支持hls协议
恩,不支持。
Ⅵ 有没有既支持HLS协议,又支持H265的android播放器
泰捷的盒子(we20s),完美支持H265解码+HLS协议(点播+直播)
Ⅶ 流媒体协议RTMP、RTSP与HLS有什么不同
1.HLS(HTTPLiveStreaming):Apple的动态码率自适应技术。主要用于PC和Apple终端的音视频服务。
2.http为计算机网络中进行数据交换而建立的规则,网络中一个微机用户和一个大型主机的操作员进行通信。
3.流媒体协议是用来描述进程之间信息交换数据时的规则术语。
Ⅷ 如何用nginee+ffmpeg实现苹果HLS协议
//循环处理命令行参数
while(optindex< argc){
opt = argv[optindex++];
//如果传入的参数是“-”打头
if(handleoptions&& opt[0]=='-'&& opt[1]!='\0'){
//如果传入的参数是“--”打头
if(opt[1]=='-'&& opt[2]=='\0'){
handleoptions =0;
//略过
continue;
}
//丢弃第一个字符”-”
opt++;
//解析命令行参数
//eg–acodec
//对应的 opt和 argv[optindex]为 “acodec” “”
if((ret= parse_option(optctx, opt, argv[optindex], options))<0)
exit_program(1);
optindex += ret;
}else{
//此时 opt的值为输出文件名如 test.ts
if(parse_arg_function)
//处理输出文件的相关内容,如 struct OutputFile的初始化
parse_arg_function(optctx, opt);
}
}
在此,ffmpeg 默认的处理输出文件名参数为:
staticvoid opt_output_file(void*optctx,constchar*filename)
2.2处理命令行参数
int parse_option(void*optctx,constchar*opt,constchar*arg, const OptionDef*options)
2.2.1查找匹配的Option
const OptionDef*po;
int bool_val=1;
int*dstcount;
void*dst;
//从全局变量options数组中查找opt对应的OptionDef
po = find_option(options, opt);
//如果未找到且以”no”打头
//不需要传递参数的选项是bool类型的选项,默认为true
//如果需要设置为false,则需要加上”no”,以下的if则是处理这种情况
if(!po->name&& opt[0]=='n'&& opt[1]=='o'){
//去掉开头的”no”重新查找
po = find_option(options, opt +2);
//如果仍未找到或者找到的选项不是bool类型
if(!(po->name&&(po->flags& OPT_BOOL)))
//报错
goto unknown_opt;
bool_val =0;
}
//如果未找到且不是以上的”no”打头情况
if(!po->name)
//寻找默认配置进行处理
po = find_option(options,"default");
//default配置也未找到,报错
if(!po->name){
unknown_opt:
av_log(NULL, AV_LOG_ERROR,"Unrecognizedoption '%s'\n", opt);
return AVERROR(EINVAL);
}
//如果选项必须有参数但是没有可用的参数,报错
if(po->flags& HAS_ARG&&!arg){
av_log(NULL, AV_LOG_ERROR,"Missingargument for option '%s'\n", opt);
return AVERROR(EINVAL);
}
现在来查看一下find_option方法的实现:
staticconst OptionDef*find_option(const OptionDef*po,constchar*name)
根据name在全局变量options数组中查找OptionDef
//这里先处理参数带有冒号的情况。比如 codec:a codec:v等
constchar*p= strchr(name,':');
int len= p? p- name: strlen(name);
//遍历options
while(po->name!=NULL){
//比较option的名称与name是否相符。
//这里 codec 与 codec:a相匹配
if(!strncmp(name, po->name, len)&& strlen(po->name)== len)
break;
po++;
}
return po;
2.2.2寻找选项地址
以下的代码用于将 void*dst变量赋值。让dst指向需要赋值的选项地址。
//如果选项在OptionContext中是以偏移量定位或者是 SpecifierOpt*数组的类型
dst= po->flags&(OPT_OFFSET| OPT_SPEC)?
//dst指向从 optctx地址偏移u.off的位置
(uint8_t*)optctx+ po->u.off:
//否则直接指向 OptionDef结构中定义的位置
po->u.dst_ptr;
//如果选项是SpecifierOpt*数组
if(po->flags& OPT_SPEC){
//数组首地址
SpecifierOpt **so= dst;
char*p= strchr(opt,':');
//这里是取得数组的当前长度+1
//请回顾 1.1中的描述:
//SpecifierOpt *xxx;
//int nb_xxx;
//当so指向xxx时刻,so+1指向nb_xxx
dstcount =(int*)(so+1);
//动态增长数组
*so = grow_array(*so,sizeof(**so), dstcount,*dstcount+1);
//将创建的SpecifierOpt结构体中的specifier赋值
//如codec:v 则specifier值为 “v”
(*so)[*dstcount-1].specifier= av_strp(p? p+1:"");
//dst指针指向数组新增的SpecifierOpt中的 u地址
//此时dstcount的值已经变作新数组的长度,亦即原数组长度+1
dst =&(*so)[*dstcount-1].u;",rich:"0"};
2015-01-09 15:25 提问者采纳
//处理window的情况
prepare_app_arguments(&argc,&argv);
optindex=1;
//循环处理命令行参数
while(optindex< argc){
opt = argv[optindex++];
//如果传入的参数是“-”打头
if(handleoptions&& opt[0]=='-'&& opt[1]!='\0'){
//如果传入的参数是“--”打头
if(opt[1]=='-'&& opt[2]=='\0'){
handleoptions =0;
//略过
continue;
}
//丢弃第一个字符”-”
opt++;
//解析命令行参数
//eg–acodec
//对应的 opt和 argv[optindex]为 “acodec” “”
if((ret= parse_option(optctx, opt, argv[optindex], options))<0)
exit_program(1);
optindex += ret;
}else{
//此时 opt的值为输出文件名如 test.ts
if(parse_arg_function)
//处理输出文件的相关内容,如 struct OutputFile的初始化
parse_arg_function(optctx, opt);
}
}
在此,ffmpeg 默认的处理输出文件名参数为:
staticvoid opt_output_file(void*optctx,constchar*filename)
2.2处理命令行参数
int parse_option(void*optctx,constchar*opt,constchar*arg, const OptionDef*options)
2.2.1查找匹配的Option
const OptionDef*po;
int bool_val=1;
int*dstcount;
void*dst;
//从全局变量options数组中查找opt对应的OptionDef
po = find_option(options, opt);
//如果未找到且以”no”打头
//不需要传递参数的选项是bool类型的选项,默认为true
//如果需要设置为false,则需要加上”no”,以下的if则是处理这种情况
if(!po->name&& opt[0]=='n'&& opt[1]=='o'){
//去掉开头的”no”重新查找
po = find_option(options, opt +2);
//如果仍未找到或者找到的选项不是bool类型
if(!(po->name&&(po->flags& OPT_BOOL)))
//报错
goto unknown_opt;
bool_val =0;
}
//如果未找到且不是以上的”no”打头情况
if(!po->name)
//寻找默认配置进行处理
po = find_option(options,"default");
//default配置也未找到,报错
if(!po->name){
unknown_opt:
av_log(NULL, AV_LOG_ERROR,"Unrecognizedoption '%s'\n", opt);
return AVERROR(EINVAL);
}
//如果选项必须有参数但是没有可用的参数,报错
if(po->flags& HAS_ARG&&!arg){
av_log(NULL, AV_LOG_ERROR,"Missingargument for option '%s'\n", opt);
return AVERROR(EINVAL);
}
现在来查看一下find_option方法的实现:
staticconst OptionDef*find_option(const OptionDef*po,constchar*name)
根据name在全局变量options数组中查找OptionDef
//这里先处理参数带有冒号的情况。比如 codec:a codec:v等
constchar*p= strchr(name,':');
int len= p? p- name: strlen(name);
//遍历options
while(po->name!=NULL){
//比较option的名称与name是否相符。
//这里 codec 与 codec:a相匹配
if(!strncmp(name, po->name, len)&& strlen(po->name)== len)
break;
po++;
}
Ⅸ hls直播协议最小延迟是几秒
我们测试过,正在做,延迟22s以上,和pc没法比,pc都是用flash做的
Ⅹ 如何用nginx+ffmpeg实现苹果HLS协议
//循环处理命令行参数
while(optindex< argc){
opt = argv[optindex++];
//如果传入的参数是“-”打头
if(handleoptions&& opt[0]=='-'&& opt[1]!='\0'){
//如果传入的参数是“--”打头
if(opt[1]=='-'&& opt[2]=='\0'){
handleoptions =0;
//略过
continue;
}
//丢弃第一个字符”-”
opt++;
//解析命令行参数
//eg–acodec
//对应的 opt和 argv[optindex]为 “acodec” “”
if((ret= parse_option(optctx, opt, argv[optindex], options))<0)
exit_program(1);
optindex += ret;
}else{
//此时 opt的值为输出文件名如 test.ts
if(parse_arg_function)
//处理输出文件的相关内容,如 struct OutputFile的初始化
parse_arg_function(optctx, opt);
}
}
在此,ffmpeg 默认的处理输出文件名参数为:
staticvoid opt_output_file(void*optctx,constchar*filename)
2.2处理命令行参数
int parse_option(void*optctx,constchar*opt,constchar*arg, const OptionDef*options)
2.2.1查找匹配的Option
const OptionDef*po;
int bool_val=1;
int*dstcount;
void*dst;
//从全局变量options数组中查找opt对应的OptionDef
po = find_option(options, opt);
//如果未找到且以”no”打头
//不需要传递参数的选项是bool类型的选项,默认为true
//如果需要设置为false,则需要加上”no”,以下的if则是处理这种情况
if(!po->name&& opt[0]=='n'&& opt[1]=='o'){
//去掉开头的”no”重新查找
po = find_option(options, opt +2);
//如果仍未找到或者找到的选项不是bool类型
if(!(po->name&&(po->flags& OPT_BOOL)))
//报错
goto unknown_opt;
bool_val =0;
}
//如果未找到且不是以上的”no”打头情况
if(!po->name)
//寻找默认配置进行处理
po = find_option(options,"default");
//default配置也未找到,报错
if(!po->name){
unknown_opt:
av_log(NULL, AV_LOG_ERROR,"Unrecognizedoption '%s'\n", opt);
return AVERROR(EINVAL);
}
//如果选项必须有参数但是没有可用的参数,报错
if(po->flags& HAS_ARG&&!arg){
av_log(NULL, AV_LOG_ERROR,"Missingargument for option '%s'\n", opt);
return AVERROR(EINVAL);
}
现在来查看一下find_option方法的实现:
staticconst OptionDef*find_option(const OptionDef*po,constchar*name)
根据name在全局变量options数组中查找OptionDef
//这里先处理参数带有冒号的情况。比如 codec:a codec:v等
constchar*p= strchr(name,':');
int len= p? p- name: strlen(name);
//遍历options
while(po->name!=NULL){
//比较option的名称与name是否相符。
//这里 codec 与 codec:a相匹配
if(!strncmp(name, po->name, len)&& strlen(po->name)== len)
break;
po++;
}
return po;
2.2.2寻找选项地址
以下的代码用于将 void*dst变量赋值。让dst指向需要赋值的选项地址。
//如果选项在OptionContext中是以偏移量定位或者是 SpecifierOpt*数组的类型
dst= po->flags&(OPT_OFFSET| OPT_SPEC)?
//dst指向从 optctx地址偏移u.off的位置
(uint8_t*)optctx+ po->u.off:
//否则直接指向 OptionDef结构中定义的位置
po->u.dst_ptr;
//如果选项是SpecifierOpt*数组
if(po->flags& OPT_SPEC){
//数组首地址
SpecifierOpt **so= dst;
char*p= strchr(opt,':');
//这里是取得数组的当前长度+1
//请回顾 1.1中的描述:
//SpecifierOpt *xxx;
//int nb_xxx;
//当so指向xxx时刻,so+1指向nb_xxx
dstcount =(int*)(so+1);
//动态增长数组
*so = grow_array(*so,sizeof(**so), dstcount,*dstcount+1);
//将创建的SpecifierOpt结构体中的specifier赋值
//如codec:v 则specifier值为 “v”
(*so)[*dstcount-1].specifier= av_strp(p? p+1:"");
//dst指针指向数组新增的SpecifierOpt中的 u地址
//此时dstcount的值已经变作新数组的长度,亦即原数组长度+1
dst =&(*so)[*dstcount-1].u;",rich:"0"};
2015-01-09 15:25 提问者采纳
//处理window的情况
prepare_app_arguments(&argc,&argv);
optindex=1;
//循环处理命令行参数
while(optindex< argc){
opt = argv[optindex++];
//如果传入的参数是“-”打头
if(handleoptions&& opt[0]=='-'&& opt[1]!='\0'){
//如果传入的参数是“--”打头
if(opt[1]=='-'&& opt[2]=='\0'){
handleoptions =0;
//略过
continue;
}
//丢弃第一个字符”-”
opt++;
//解析命令行参数
//eg–acodec
//对应的 opt和 argv[optindex]为 “acodec” “”
if((ret= parse_option(optctx, opt, argv[optindex], options))<0)
exit_program(1);
optindex += ret;
}else{
//此时 opt的值为输出文件名如 test.ts
if(parse_arg_function)
//处理输出文件的相关内容,如 struct OutputFile的初始化
parse_arg_function(optctx, opt);
}
}
在此,ffmpeg 默认的处理输出文件名参数为:
staticvoid opt_output_file(void*optctx,constchar*filename)
2.2处理命令行参数
int parse_option(void*optctx,constchar*opt,constchar*arg, const OptionDef*options)
2.2.1查找匹配的Option
const OptionDef*po;
int bool_val=1;
int*dstcount;
void*dst;
//从全局变量options数组中查找opt对应的OptionDef
po = find_option(options, opt);
//如果未找到且以”no”打头
//不需要传递参数的选项是bool类型的选项,默认为true
//如果需要设置为false,则需要加上”no”,以下的if则是处理这种情况
if(!po->name&& opt[0]=='n'&& opt[1]=='o'){
//去掉开头的”no”重新查找
po = find_option(options, opt +2);
//如果仍未找到或者找到的选项不是bool类型
if(!(po->name&&(po->flags& OPT_BOOL)))
//报错
goto unknown_opt;
bool_val =0;
}
//如果未找到且不是以上的”no”打头情况
if(!po->name)
//寻找默认配置进行处理
po = find_option(options,"default");
//default配置也未找到,报错
if(!po->name){
unknown_opt:
av_log(NULL, AV_LOG_ERROR,"Unrecognizedoption '%s'\n", opt);
return AVERROR(EINVAL);
}
//如果选项必须有参数但是没有可用的参数,报错
if(po->flags& HAS_ARG&&!arg){
av_log(NULL, AV_LOG_ERROR,"Missingargument for option '%s'\n", opt);
return AVERROR(EINVAL);
}
现在来查看一下find_option方法的实现:
staticconst OptionDef*find_option(const OptionDef*po,constchar*name)
根据name在全局变量options数组中查找OptionDef
//这里先处理参数带有冒号的情况。比如 codec:a codec:v等
constchar*p= strchr(name,':');
int len= p? p- name: strlen(name);
//遍历options
while(po->name!=NULL){
//比较option的名称与name是否相符。
//这里 codec 与 codec:a相匹配
if(!strncmp(name, po->name, len)&& strlen(po->name)== len)
break;
po++;
}
return po;
2.2.2寻找选项地址
以下的代码用于将 void*dst变量赋值。让dst指向需要赋值的选项地址。
//如果选项在OptionContext中是以偏移量定位或者是 SpecifierOpt*数组的类型
dst= po->flags&(OPT_OFFSET| OPT_SPEC)?
//dst指向从 optctx地址偏移u.off的位置
(uint8_t*)optctx+ po->u.off:
//否则直接指向 OptionDef结构中定义的位置
po->u.dst_ptr;
//如果选项是SpecifierOpt*数组
if(po->flags& OPT_SPEC){
//数组首地址
SpecifierOpt **so= dst;
char*p= strchr(opt,':');
//这里是取得数组的当前长度+1
//请回顾 1.1中的描述:
//SpecifierOpt *xxx;
//int nb_xxx;
//当so指向xxx时刻,so+1指向nb_xxx
dstcount =(int*)(so+1);
//动态增长数组
*so = grow_array(*so,sizeof(**so), dstcount,*dstcount+1);
//将创建的SpecifierOpt结构体中的specifier赋值
//如codec:v 则specifier值为 “v”
(*so)[*dstcount-1].specifier= av_strp(p? p+1:"");
//dst指针指向数组新增的SpecifierOpt中的 u地址
//此时dstcount的值已经变作新数组的长度,亦即原数组长度+1
dst =&(*so)[*dstcount-1].u;