iOS 實時流媒體解析

實時流媒體

實時流媒體是一邊接收數據包一邊播放,本地不保留文件副本,實時流式傳輸總是實時傳送,可以實時實況轉播,支持隨機訪問,用戶可以快進或者快退以觀看前面或後面的內容。實時流媒體傳輸必須保證數據包的傳輸速度大於文件的播放速度,否則用戶看到的視頻會出現暫停。當網絡堵塞情況下視頻質量會下降,所以要想保證視頻的質量漸進式下載會更好一些。

實時流媒體協議:

RTSP(Real Time Streaming Protocol)

MMS(Microsoft Media Server protocol)

HLS(Http Live Streaming)

這裏主要介紹HLS,

HLS(HTTP Live Streaming)是蘋果公司針對iPhone、iPod、iTouch和iPad等移動設備而開發的基於HTTP協議的流媒體解決方案

https://developer.apple.com/streaming/

技術關鍵點

1.採集視頻源和音頻源的數據

2.對原始數據進行H264編碼和AAC編碼

3.視頻和音頻數據封裝爲MPEG-TS包

4.HLS分段生成策略及m3u8索引文件

5.HTTP傳輸協議

搭建HLS流媒體服務器

Apache HTTP Server (蘋果自帶)

Tomcat Web Server

IIS(Internet Information Services)

這裏只推薦Apache HTTP Server

打開終端,vi /etc/apache2/httpd.conf

<IfModule mime_module>下

添加兩行

AddType application/x-mpegURL.M3U8

AddType video/MP2T.ts

可能你的權限不夠,那就用 sudo chmod 777 /etc/apache2/httpd.conf

然後 vi /etc/apache2/httpd.conf

重啓服務器

sudo apachectl restart 

==============================================

或者搭建xmpp服務器  或者不搭建,從優酷獲取m3u8

==============================================

創建一個工程

從git中下載庫:http://git.oschina.net/1213125967/HLS

將庫導入工程

需要引入第三方開源框架:ASIHttpRequest,CocoaHTTPServer,m3u8

需要導入系統框架:libsqlite3.dylib、libz.dylib、libxml2.dylib、CoreTelephony.framework、SystemConfiguration.framework、MobileCoreServices.framework、Security.framework、CFNetwork.framework、MediaPlayer.framework

在library search path 中添加 /usr/include/libxml2

添加頭文件

?
1
2
3
4
#import <MediaPlayer/MediaPlayer.h>
#import "M3U8Handler.h"
#import "VideoDownloader.h"
#import "HTTPServer.h"

聲明屬性:

?
1
2
@property (nonatomic, strong)HTTPServer * httpServer;
@property (nonatomic, strong)VideoDownloader *downloader;

預先播放,畢先設置服務器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma mark - 打開本地服務器
- (void)openHttpServer
{
    self.httpServer = [[HTTPServer alloc] init];
    [self.httpServer setType:@"_http._tcp."];  // 設置服務類型
    [self.httpServer setPort:12345]; // 設置服務器端口
     
    // 獲取本地Documents路徑
    NSString *pathPrefix = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
     
    // 獲取本地Documents路徑下downloads路徑
    NSString *webPath = [pathPrefix stringByAppendingPathComponent:kPathDownload];
    NSLog(@"-------------\nSetting document root: %@\n", webPath);
     
    // 設置服務器路徑
    [self.httpServer setDocumentRoot:webPath];
    NSError *error;
     
    if(![self.httpServer start:&error])
    {
        NSLog(@"-------------\nError starting HTTP Server: %@\n", error);
    }
}

搭建完成後,播放什麼的,都是取決於需求

在線流媒體播放

?
1
2
3
4
5
6
    // 優酷視頻m3u8新地址格式如下:http://pl.youku.com/playlist/m3u8?vid=XNzIwMDE5NzI4&type=mp4
    // 如果上面的鏈接不可用,那麼使用這個鏈接http://v.youku.com/player/getM3U8/vid/XNzIwMDE5NzI4/type/flv
    NSURL *url = [[NSURL alloc] initWithString:@"http://v.youku.com/player/getM3U8/vid/XNzIwMDE5NzI4/type/mp4"];
    MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
     
    [self presentMoviePlayerViewControllerAnimated:player];

視頻下載

?
1
2
3
4
5
6
7
    M3U8Handler *handler = [[M3U8Handler alloc] init];
    handler.delegate = self;
    // 解析m3u8視頻地址
    [handler praseUrl:[NSString stringWithFormat:@"http://pl.youku.com/playlist/m3u8?vid=XNzIwMDE5NzI4&type=mp4"]];
     
    // 開啓網絡指示器
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

播放本地視頻

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    NSString * playurl = [NSString stringWithFormat:@"http://127.0.0.1:12345/XNzIwMDE5NzI4/movie.m3u8"];
    NSLog(@"本地視頻地址-----%@", playurl);
     
    // 獲取本地Documents路徑
    NSString *pathPrefix = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
     
    // 獲取本地Documents路徑下downloads路徑
    NSString *localDownloadsPath = [pathPrefix stringByAppendingPathComponent:kPathDownload];
     
    // 獲取視頻本地路徑
    NSString *filePath = [localDownloadsPath stringByAppendingPathComponent:@"XNzIwMDE5NzI4/movie.m3u8"];
    NSFileManager *fileManager = [NSFileManager defaultManager];
     
    // 判斷視頻是否緩存完成,如果完成則播放本地緩存
    if ([fileManager fileExistsAtPath:filePath]) {
        MPMoviePlayerViewController *playerViewController =[[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString: playurl]];
        [self presentMoviePlayerViewControllerAnimated:playerViewController];
    }
    else{
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Sorry" message:@"當前視頻未緩存" delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alertView show];
    }


添加代理 <M3U8HandlerDelegate,VideoDownloadDelegate>

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#pragma mark --------------視頻解析完成----------------
-(void)praseM3U8Finished:(M3U8Handler*)handler
{
    handler.playlist.uuid = @"XNzIwMDE5NzI4";
    self.downloader = [[VideoDownloader alloc]initWithM3U8List:handler.playlist];
    [self.downloader addObserver:self forKeyPath:@"totalprogress" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    self.downloader.delegate = self;
    [self.downloader startDownloadVideo];
}
 
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"下載進度 - %f", self.downloader.totalprogress);
}
 
#pragma mark --------------視頻解析失敗----------------
-(void)praseM3U8Failed:(M3U8Handler*)handler
{
    NSLog(@"視頻解析失敗-failed -- %@",handler);
}
 
#pragma mark --------------視頻下載完成----------------
-(void)videoDownloaderFinished:(VideoDownloader*)request
{
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    [request createLocalM3U8file];
    NSLog(@"----------視頻下載完成-------------");
}
 
#pragma mark --------------視頻下載失敗----------------
-(void)videoDownloaderFailed:(VideoDownloader*)request
{
    NSLog(@"----------視頻下載失敗-----------");
}
發佈了53 篇原創文章 · 獲贊 0 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章