HTTPLiveStreaming支持在m3u8中指定一个key文件(目前支持16-octet的AES-128加密),然后每个视频切段都使用这个key来加密。
可以所有切段共用一个key,也可以几个切段使用一个key,最细可以一个切段使用一个key。
然后把这些key文件加上验证功能,比如登陆才能读取到,这样就可以达到内容加密的效果了。
建议使用HTTPS来传输key文件。
注意:每个新key文件都会发起一个新的HTTP请求,因此每个切段一个key会大大加大服务器的连接数。
1、最好不要用HTTPS来传送视频文件和m3u8文件,因为这样很容易穿透cache服务器。
2、另外,cache服务器必须知道m3u8文件缓存的时间不能大于一个视频切段的长度。
可以在m3u8中指定2个BANDWIDTH相同的外部地址,这样客户端会自己在其中一路不可达时切换到另一路。
1、更长的分段导致更长的延迟和更长的初始化时间,切换码率(只能在切换分段的时候切)也更慢;
2、更短的分段导致对m3u8文件更密集的请求,从而导致更多网络流量;
3、Apple推荐的分段时长为10秒;
4、MPEG-TS流有比通常文件更多的头信息,会导致文件整体码率明显上升。可以使用Apple家的分段软件来减少和压缩其中不必要的头;
5、Apple家文档说10s分段的话会有约30s时延;
6、m3u8中可阻止客户端缓存文件,否则客户端会为了提高seek效率而缓存文件。
在写一个基于iphone的应用,主要是用来播放视频的.但是提交给苹果审核的时候却遭到百般刁难.尤其是关于在3G网络上播放视频流的限制:
9.4Videostreamingcontentoveracellularnetworklongerthan10minutesmustuseHTTPLiveandincludeabaseline64kbpsaudio-onlyHTTPLivestream
也罢,想想也是,在移动互联网直接播放一个几十M上百M的文件也确实是太浪费有限的流量了.难道说在互联网上直接下载整个文件,而不管会不会看完就不浪费流量了吗?觉得确实有必要研究一下这项技术了.
applehttplivestreaming.基于http的视频流播放,笔者称它为视频切片技术,先是将视频文件通过mpegts编码,然后通过apple提供的小工具segmenter将视频文件切割成很多小文件并维护一个时间列表.这些文件可以直接放在网站目录下面通过http协议被下载播放.不幸的是苹果提供的segmenter只能工作在mac下,我们需要一个基于linux的开源解决方案.
几经搜索和尝试最后找到CarsonMcDonald的<<iPhoneHTTPStreamingwithFFMpegandanOpenSourceSegmenter>>虽然文中给出了几乎"完美"的解决方案,但是由于时代的发展和实际环境的不同,笔者着实将这篇文章细细研究了N久,于是也便有了这篇文章的出现.接下笔者会给出在ubuntu10.04服务器编译安装ffmpeg和segmenter技术细节,并汇报一些心得.ok,goon.
1.编译安装ffmpeg
删除不用的已安装文件,升级apt-get缓存,安装必要的开发工具及库文件
apt-getremoveffmpegx264libx264-devlibmp3lame-dev
apt-getupdate
apt-getinstallbuild-essentialsubversiongit-corecheckinstallyasmtexi2html\
libopencore-amrnb-devlibopencore-amrwb-devlibsdl1.2-devlibtheora-devlibvorbis-dev\
libx11-devlibxfixes-devlibxvidcore-devzlib1g-devnasmyasmlibbz2-dev
需要用到的库及下载地址
faad2-2.7.tar.gz
faac-1.28.tar.gz
lame-3.98.4.tar.gz
ffmpeg-0.6.1.tar.gz
1).faad2的安装最简单,直接解压然后
./configure&&make&&makeinstall就ok了.
2).faac需要修改一个文件
vi+123./common/mp4v2/mpeg4ip.h
从123行开始修改此文件mpeg4ip.h,到129行结束。
修改前:
#ifdef__cplusplus
extern"C"{
#endif
char*strcasestr(constchar*haystack,constchar*needle);
#ifdef__cplusplus
}
#endif
修改后:
#ifdef__cplusplus
extern"C++"{
#endif
constchar*strcasestr(constchar*haystack,constchar*needle);
#ifdef__cplusplus
}
#endif
然后默认安装:
./configure&&make&&makeinstall
3).lame这样编译:
./configure--enable-nasm--disable-shared&&make&&makeinstall
4).x264则是取的最新的代码,然后默认安装
gitclonegit://git.videolan.org/x264.git
./configure&&make&&makeinstall&&cd..
5).ffmpeg的编译参数
./configure--enable-gpl--enable-nonfree--enable-pthreads\
--enable-libfaac--enable-libfaad--enable-libmp3lame--enable-libx264
为什么要选择ffmpeg-0.6.1呢?因为较早的版本编译完以后不能正常使用而从svn取的最新的代码则会好端端的出现Unknownoption"--enable-libfaad"错误.
2.安装segmenter
如果您有一定的linux使用经验,ffmpeg编译自然不在话下,也比较简单的,最难的就是这部分的segmenter的编译安装了.
先取出源代码:
svncheckouthttp://svn.assembla.com/svn/legend/segmenter/segmenter
修改一个小地方:
vi+242segmenter.c
把guess_format修改成av_guess_format
不然segmenter会在编译的时候提示:
segmenter.c:242:warning:‘guess_format’isdeprecated(declaredat/usr/local/include/libavformat/avformat.h:764)
接下来选择一种编译方式:
gcc-Wall-gsegmenter.c-osegmenter-L/usr/include/ffmpeg/libavformat-lavformat-L/usr/include/ffmpeg/libavcodec-lavcodec-L/usr/include/ffmpeg/libavutil-lavutil-I/usr/include/ffmpeg/-lbz2-lm-lmp3lame-lxvidcore-lx264-lfaad-lfaac-lpthread-lz
或者
gcc-Wall-gsegmenter.c-osegmenter-L/usr/local/src/ffmpeg/ffmpeg-0.6.1/libavformat-lavformat-L/usr/local/src/ffmpeg/ffmpeg-0.6.1/libavcodec-lavcodec-L/usr/local/src/ffmpeg/ffmpeg-0.6.1/libavutil-lavutil-I/usr/local/src/ffmpeg/ffmpeg-0.6.1/-lbz2-lm-lmp3lame-lxvidcore-lx264-lfaad-lfaac-lpthread-lz
其实无论哪种编译方式都是手动指定了库文件的位置,不然的话编译不过,这个地方最坑人,费了很多很多时间!
3.编码视频文件并切割
这之前的地方如果你遵循笔者的安装文档和提示应该很容易就通过了(虽然笔者花费了大量的时间摸索).但是正确编译以后,你并不知道正确切割文件以后的效果是什么样的,所以笔者在这里花费了超级大量的时间,这也是笔者为什么坚持要写出这篇文章的原因.
先列出笔者犯的几个致命错误吧:
1).不按apple文档格式转码
因为笔者使用的输入文件在编码的时候是针对apple的设备优化过的,可以直接在apple设备上播放并获得良好的观看效果.而在使用原作者的编码参数:
ffmpeg-i-fmpegts-acodeclibmp3lame-ar48000-ab64k-s320×240-vcodeclibx264-b96k-flags+loop-cmp+chroma-partitions+parti4x4+partp8x8+partb8x8-subq5-trellis1-refs1-coder0-me_range16-keyint_min25-sc_threshold40-i_qfactor0.71-bt200k-maxrate96k-bufsize96k-rc_eq'blurCplx^(1-qComp)'-qcomp0.6-qmin10-qmax51-qdiff4-level30-aspect320:240-g30-async2
时报错,在这种情况下,考虑到前一个原因,笔者自己摸索了一个编码代码:
ffmpeg-y-i-vcodeccopy-acodeccopy-vbsfh264_mp4toannexb
是可以正常编码和分割视频文件的.但是将应用提交给苹果审核后,苹果依旧给出了9.2的提示并拒绝了应用.这才想起来源视频在进行编码的过程中音频并没有使用64k的编码也没有单独增加一路音频流.
2).浪费时间解决可以忽略的错误提示
无论直接正常编译成功还是编译失败从别的机器上拷贝segmenter过来,在分割视频的时候都出现了:
[mpegts@0x2942160]max_analyze_durationreached
Output#0,mpegts,to'a/index':
Stream#0.0:Video:libx264,yuv420p,536x402,q=2-31,90ktbn,25tbc
Stream#0.1:Audio:libmp3lame,48000Hz,2channels,64kb/s
[mpegts@0x2a08430]muxrate1bps,pcrevery5pkts,sdtevery200,pat/pmtevery40pkts
[NULL@0x2956900]missingpictureinaccessunit
"max_analyze_durationreached"和"missingpictureinaccessunit"的提示.最初这两个提示困扰了笔者很久,不断的在网上搜索寻找解决办法;不断的重新编译ffmpeg和segmenter;不断的更换视频输入源,重新编码;直到最后发现即便有这两个提示存在并不影响视频的正常播放的时候,笔者决定接受现实:这两个提示可以存在.
3).解决视频长度问题
即使上面走过了那么多的艰难,但是你还是会发现这个世界是不完美的.毕竟segmenter是苹果开发了以后用在mac上的.不知道是移值到linux还是什么原因,这个工具的表现有点让人理解不了.它的参数是这样的:
segmenter
第二个参数,你指定视频分割间隔的时候,比如说指定了15秒.如果你的视频时长是32秒的话,你的视频文件会被分割成3段(每15秒一段,最后的2秒一段),而最后一段的播放时长,它竟然会写成15秒!明明就2秒干嘛要写成15秒!!!用quicktime还好说,它似乎会自动检查视频的时长纠正时间和进度条,而在iphone上,显示时长是取的视频文件里的时长(15x3=45s),而下载进度条显示的是实际文件的视频时长(32s),这样的话,你会发现,当一个视频被播放完的时候,时间还差13秒!怎么办呢?没办法了,我是看不懂c程序,但是哥会php啊,不就是时间不对嘛,哥给你重新计算一下时间重写一下文件,搞定!
4).测试时的网速问题
为了"大规模"的随机测试视频,笔者是在服务器上直接编码测试的.无论在quicktime还是iphone上,正常的表现应该是视频会被提前下载两到三个小段.结果笔者测试的时候,发现视频总是播一条下一段,笔者郁闷了很久发现:原来是公司网速太慢了.直接在iphone上用3G测试,很给力!
5).转码耗用cpu问题
视频转码是最费cpu的东东,如果想提高转码速度还是买两颗8核的cpu一块干活吧,速度哇哇的,你懂的.
ok,废话半天说一下笔者用的转码指令.
ffmpeg-y-ia.mp4-fmpegts-acodeclibmp3lame-ar48000-ab64k-vcodeclibx264-b250k\
-flags+loop-cmp+chroma-partitions+parti4x4+partp8x8+partb8x8-subq5-trellis1-refs1\
-coder0-me_range16-keyint_min25-sc_threshold40-i_qfactor0.71\
-bt250k-maxrate250k-bufsize250k-rc_eq'blurCplx^(1-qComp)'\
-qcomp0.6-qmin10-qmax51-qdiff4-level30-aspect320:240-g30-async2a.ts
segmentera.ts15aa/index.m3u8http://vod.rainbird.cc/
rm-rfa.ts
这个时候测试时访问的url为:http://vod.rainbird.cc/a/index.m3u8(随便写的,请勿对号入座)
4.nginx配置
vimime.types
添加以下两条儿,重启nginx
application/x-mpegURLm3u8;
video/MP2Tts;
一切顺利的话,这时候可以通过测试url观看视频了.
参考文档:
iPhoneHTTPStreamingwithFFMpegandanOpenSourceSegmenter
Howto:InstallandusethelatestFFmpegandx264