iOS 处理HLS视频流

一、HLS介绍

  HLS是苹果主导的音视频传输协议,其主要的格式是一个索引文件(M3U8)+ ts分片的视频文件。

  HLS的优势是iOS系统天然支持,通过Http 80传输,规避了常规的防火墙问题。

  视频的分片方便服务器CDN对视频文件分发缓存。

  HLS支持视频点播和直播,直播的延时可能达到10s。

 

二、HLS协议内容

  

  完整的HLS协议包含,视频加密标准(MPEG4、H264)、音频加密标准(AAC、MP3);

            视频封装标准 TS

            视频如何切片 M3U8  

            视频如何传输 M3U8索引描述ts流分片

  

  对于客户端来说,常见的就是对HLS协议的利用

  M3U8描述格式:

  通过苹果的 https://developer.apple.com/streaming/examples/advanced-stream-ts.html 在线视频,可以抓包看到

 

 

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-INDEPENDENT-SEGMENTS

#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=2218327,BANDWIDTH=2227464,CODECS="avc1.640020,mp4a.40.2",RESOLUTION=960x540,FRAME-RATE=60.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v5/prog_index.m3u8
#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=8144656,BANDWIDTH=8178040,CODECS="avc1.64002a,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=60.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v9/prog_index.m3u8
#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=6307144,BANDWIDTH=6453202,CODECS="avc1.64002a,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=60.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v8/prog_index.m3u8
#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=4775338,BANDWIDTH=5054232,CODECS="avc1.64002a,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=60.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v7/prog_index.m3u8
#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=3240596,BANDWIDTH=3289288,CODECS="avc1.640020,mp4a.40.2",RESOLUTION=1280x720,FRAME-RATE=60.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v6/prog_index.m3u8
#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=1292926,BANDWIDTH=1296989,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=768x432,FRAME-RATE=30.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v4/prog_index.m3u8
#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=914722,BANDWIDTH=922242,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,FRAME-RATE=30.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v3/prog_index.m3u8
#EXT-X-STREAM-INF:AVERAGE-BANDWIDTH=541239,BANDWIDTH=553010,CODECS="avc1.640015,mp4a.40.2",RESOLUTION=480x270,FRAME-RATE=30.000,CLOSED-CAPTIONS="cc1",AUDIO="aud1",SUBTITLES="sub1"
v2/prog_index.m3u8

  

  HLS协议是一个文本协议,一个M3U8中通过不同的Tag来描述,视频的内容

  参考:https://tools.ietf.org/html/rfc8216

  

  这篇文章写的比较清楚,https://www.cnblogs.com/jimodetiantang/p/9133564.html

 

三、HLS在iOS上面的的应用

  1)如果仅仅是播放,那就比较简单,直接使用AVPlayer接口就可以了

  AVPlayer加载AVPlayerItem的结构,这个对象通过对本地音视频文件或者远程视频文件的封装的到

  AVURLAsset通过对M3U8播放地址对封装,可以的到一个远程对Asset,穿入到AVPlayer中,可以自动下载播放

  可以很方便看到,这个封装中可以传入对应对Cookie

  类似这种,下面的URL是Mp4文件,如果换成M3U8也可以播放的

    NSURL *assetUrl = [NSURL URLWithString:@"http://flv2.bn.netease.com/videolib3/1606/23/RiTxE9164/SD/RiTxE9164-mobile.mp4"];
    
    AVAsset *asset = [AVAsset assetWithURL:assetUrl];
    
    AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset];
    
    self.player = [AVPlayer playerWithPlayerItem:item];
    

  2)HLS的下载解析

  通过上面的例子,可以的到一个AVUrlAsset,这个asset除了用来播放之外,还可以用来下载

  

  可以初始化为一个DownloadTask,然后跟普通的下载一样,放入NSUrlSession中

   类似下面的代码

 NSURL *assetURL = [NSURL URLWithString:@"STREAMING_HOST/video/hls/3729170.m3u8"];
    AVURLAsset *hlsAsset = [AVURLAsset assetWithURL:assetURL];

    urlSessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"assetDowloadConfigIdentifier"];
    avAssetDownloadSession = [AVAssetDownloadURLSession sessionWithConfiguration:urlSessionConfiguration assetDownloadDelegate:self delegateQueue:[NSOperationQueue mainQueue]];

    // Download movie
    avAssetDownloadTask = [avAssetDownloadSession assetDownloadTaskWithURLAsset:hlsAsset assetTitle:@"downloadedMedia" assetArtworkData:nil options:nil];

//@{AVAssetDownloadTaskMinimumRequiredMediaBitrateKey : @(300000)}


    [avAssetDownloadTask resume];

  当下载完毕之后,会回调

  

  在这里,会在本地会生成一个movpkg的文件夹,也就是MOV打包文件

  在这个文件夹中,包含一个一个M3U8的描述文件,和多个frag视频分片

  这里的分片有可能是加密的,如果是加密的,需要通过M3U8中 ,指定key的url,下载到key,并且通过M3U8解析到IV

  通过Key和IV,使用AES CBC 解析的到解密后到视频文件。

  TS流本身可以直接通过二进制到方式追加,追加之后还是可以直接播放的。

  如果,要进行合并,可以使用ffmpeg 的命令行进行ts流合并

 

四、附加

  这里的下载回调,建议不通过来处理成功的逻辑,因为这里处理成功的逻辑时,拿不到本地文件的下载路径

/* Sent as the last message related to a specific task.  Error may be
 * nil, which implies that no error occurred and this task is complete. 
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                           didCompleteWithError:(nullable NSError *)error;

  

  

  

posted @ 2019-06-27 20:30  兜兜有糖的博客  阅读(6033)  评论(0编辑  收藏  举报