学习交流及技术讨论可新浪微博关注:极客James
一.流媒体
流媒体技术从传输形式上可以分为:渐进式下载和实施流媒体。
1.渐进式下载
它是介于实时播放和本地播放之间的一种播放方式,渐进式下载不必等到全部下载完成后在播放,可以边下载边播放,播放完成后,整个文件会保存下来。从用户的体验上合播放方的效果来看,渐进式下载和实时流媒体没有什么区别,不过是渐进式下载保留有文件在本地。下面来介绍下渐进式下载的开发 渐进式下载的API和本地播放的API没有什么太大的区别,可以使用MediaPlayer框架中得MediaPlayerController和MediaPlayerViewController进行播放,亦可以使用AVFoundation框架中得AVPlayer进行播放。在mac os系统下都有一个Apache HTTP服务器,首先打开服务,使用命令行:sudo apachectl -v 输入密码后 接着输入 sudo apachectl start 就可以了 然后把要播放的文件放到/Library/WebServer/documents下就可以了 .
2.实时流媒体
实时流媒体是一边接收数据包一边进行播放,本地不保留文件副本,数据总是实时传送的。用户可以快进快退,不过,实时流媒体播放必须保证数据包的传输速度大于文件的播放速度,否则影响播放效果。
实时流媒体传输的协议有:RTSP和HLS、MMS。HLS是苹果公司提出的,它只请求基本的HTTP报文,与RTSP和MMS不同,HLS可以穿过任何允许HTTP数据通过的防火墙。而且,HLS对服务器没有特殊要求,只要能够提供HTTP服务就可以了。
HLS的解决方案:首先通过音频或视频采集设备采集数据,然后将数据传递给Server对音频或者视频进行编码,编码要求采用MPEG-2格式,编码完成之后再通过媒体文件分隔工具进行分割,然后再讲这些分割好的文件和他们的索引文件发布到发布服务器上,然后客户端就可以访问了。
二.HLS
HTTP Live Streaming(HLS)是苹果公司(Apple Inc.)实现的基于HTTP的流媒体传输协议,可实现流媒体的直播和点播,主要应用在iOS系统,为iOS设备(如iPhone、iPad)提供音视频直播和点播方案。HLS点播,基本上就是常见的分段HTTP点播,不同在于,它的分段非常小。要实现HLS点播,重点在于对媒体文件分段,目前有不少开源工具可以使用,这里我就不再讨论,只谈HLS直播技术。
HLS实现方式原理图
相对于常见的流媒体直播协议,例如RTMP协议、RTSP协议、MMS协议等,HLS直播最大的不同在于,直播客户端获取到的,并不是一个完整的数据流。HLS协议在服务器端将直播数据流存储为连续的、很短时长的媒体文件(MPEG-TS格式),而客户端则不断的下载并播放这些小文件,因为服务器端总是会将最新的直播数据生成新的小文件,这样客户端只要不停的按顺序播放从服务器获取到的文件,就实现了直播。由此可见,基本上可以认为,HLS是以点播的技术方式来实现直播。由于数据通过HTTP协议传输,所以完全不用考虑防火墙或者代理的问题,而且分段文件的时长很短,客户端可以很快的选择和切换码率,以适应不同带宽条件下的播放。不过HLS的这种技术特点,决定了它的延迟一般总是会高于普通的流媒体直播协议。
根据以上的了解要实现HTTP Live Streaming直播,需要研究并实现以下技术关键点
(1)采集视频源和音频源的数据
(2)对原始数据进行H264编码和AAC编码
(3)视频和音频数据封装为MPEG-TS包
(4)HLS分段生成策略及m3u8索引文件
(5)HTTP传输协议
三.基于B站的流媒体解决方案Ijkplayer框架
最近在关注流媒体直播这块儿,经过技术老大的推荐B站的ijkplayer框架,开始了一段爬坑历程……
(1)第一步到github上下载B站开源的ijkplayer框架:
github网址:B站开源ilkplayer下载地址
(2)根据说明文档进行编译前的各种操作,其实不难就三大步骤
注意: 带有#号标注的是注释,不用在控制台中输入
第一步:运行环境的搭建(需要ruby,home-brew,git,yams等环境),打开终端将以下没有#号开头的语句进行输入.
# install homebrew, git, yasm
ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
brew install git
brew install yasm
# add these lines to your ~/.bash_profile or ~/.profile
# export ANDROID_SDK=
# export ANDROID_NDK=
# on Cygwin (unmaintained)
# install git, make, yams
第二步: 将ijkplayer项目克隆到本地并且将ffmpeg集成到ijkplayer中(这一步骤比较耗时,需要耐心等待),在终端输入以下命令..
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-ios
cd ijkplayer-ios
git checkout -B latest
./init-ios.sh
cd ios
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
第三步: 打开ijkplayer-ios下的iOS文件下的IJKMedioDemo
官方上的以下两句的意思是将IJKMediaPlayer导入到你的项目中
#import ios/IJKMediaPlayer for MediaPlayer.framework-like interface (recommended)
#open ios/IJKMediaDemo/IJKMediaDemo.xcodeproj with Xcode
然后将IJKMediaPlayer拖到此文件中.
这样就可以打开官方给出的demo示例程序了.
运行出来的效果图:
以上是官方给出的demo,仿照demo里面很多功能都是可以实现的.那么问题来了,如何将IJKPlayer集成到自己的项目中呢?本人在集成的时候遇到了很大的坑……
将ijkplayer集成到自己的项目中:
创建自己的项目:
第一步:将IJKMediaFrameWork.framework静态库和IJKMediaPlayer入到项目文件中
第二不:打开项目添加到这两个文件到主目录,然后打开Build Phases添加以下库
这样就完美了,run以下就可以轻松加愉快的进行流媒体的相关开发了……..
四.M3U8
做流媒体开发必须接触的一种文件叫M3U8文件,那么什么是M3U8呢?
M3U8文件是指UTF-8编码格式的M3U文件。M3U文件是记录了一个索引纯文本文件,打开它时播放软件并不是播放它,而是根据它的索引找到对应的音视频文件的网络地址进行在线播放。
M3U文件标签及属性说明
M3U文件中可以包含多个tag,每个tag的功能和属性如下:
#EXTM3U
每个M3U文件第一行必须是这个tag,请标示作用
#EXT-X-MEDIA-SEQUENCE:140651513
每一个media URI 在 PlayList中只有唯一的序号,相邻之间序号+1, 一个media URI并不是必须要包含的,如果没有,默认为0
#EXTINF:,
duration 指定每个媒体段(ts)的持续时间(秒),仅对其后面的URI有效,title是下载资源的url
#EXT-X-TARGETDURATION
指定最大的媒体段时间长(秒)。所以#EXTINF中指定的时间长度必须小于或是等于这个最大值。这个tag在整个PlayList文件中只能出现一 次(在嵌套的情况下,一般有真正ts url的m3u8才会出现该tag)
#EXT-X-KEY
表示怎么对media segments进行解码。其作用范围是下次该tag出现前的所有media URI,属性为NONE 或者 AES-128。NONE表示 URI以及IV(Initialization Vector)属性必须不存在, AES-128(Advanced EncryptionStandard)表示URI必须存在,IV可以不存在。
对于AES-128的情况,keytag和URI属性共同表示了一个key文件,通过URI可以获得这个key,如果没有IV(Initialization Vector),则使用序列号作为IV进行编解码,将序列号的高位赋到16个字节的buffer中,左边补0;如果有IV,则将改值当成16个字节的16进制数。
#EXT-X-PROGRAM-DATE-TIME
将一个绝对时间或是日期和一个媒体段中的第一个sample相关联,只对下一个meida URI有效,格式如#EXT-X-PROGRAM-DATE-TIME:
For example: #EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00
#EXT-X-ALLOW-CACHE
是否允许做cache,这个可以在PlayList文件中任意地方出现,并且最多出现一次,作用效果是所有的媒体段。格式如下:#EXT-X-ALLOW-CACHE:
#EXT-X-PLAYLIST-TYPE
提供关于PlayList的可变性的信息, 这个对整个PlayList文件有效,是可选的,格式如下:#EXT-X-PLAYLIST-TYPE::如果是VOD,则服务器不能改变PlayList 文件;如果是EVENT,则服务器不能改变或是删除PlayList文件中的任何部分,但是可以向该文件中增加新的一行内容。
#EXT-X-ENDLIST
表示PlayList的末尾了,它可以在PlayList中任意位置出现,但是只能出现一个,格式如下:#EXT-X-ENDLIST
#EXT-X-MEDIA
被用来在PlayList中表示相同内容的不用语种/译文的版本,比如可以通过使用3个这种tag表示3中不用语音的音频,或者用2个这个tag表示不同角度的video在PlayLists中。这个标签是独立存在的,属性包含:
URI:如果没有,则表示这个tag描述的可选择版本在主PlayList的EXT-X-STREAM-INF中存在;
TYPE:AUDIO and VIDEO;
GROUP-ID:具有相同ID的MEDIAtag,组成一组样式;
LANGUAGE:确定使用的主要语言
NAME:人类可读的语言的翻译
DEFAULT:YES或是NO,默认是No,如果是YES,则客户端会以这种选项来播放,除非用户自己进行选择。
AUTOSELECT:YES或是NO,默认是No,如果是YES,则客户端会根据当前播放环境来进行选择(用户没有根据自己偏好进行选择的前提下)。
#EXT-X-STREAM-INF
指定一个包含多媒体信息的 media URI 作为PlayList,一般做M3U8的嵌套使用,它只对紧跟后面的URI有效,格式如下:#EXT-X-STREAM-INF:有以下属性:
BANDWIDTH:带宽,必须有。
PROGRAM-ID:该值是一个十进制整数,惟一地标识一个在PlayList文件范围内的特定的描述。一个PlayList 文件中可能包含多个有相同ID的此tag。
CODECS:不是必须的。
RESOLUTION:分辨率。
AUDIO:这个值必须和AUDIO类别的“EXT-X-MEDIA”标签中“GROUP-ID”属性值相匹配。
VIDEO:同上