標籤:
推流完成後,需要拉流才能進行完整的直播。拉流我們採用的也是一個開源的第三方庫IJKMediaFramework。
這個庫本質是一個播放器,能播放flv格式的播放器。用起來和ios內建的AVPlayer很相似。
實現功能:1.拉流播放。2.監聽。
一.建立佔位圖和卡頓佔位動效,代碼如下:
//直播前的佔位圖片
- (UIImageView *)placeHolderView{ if (!_placeHolderView) { _placeHolderView = [[UIImageView alloc] init]; _placeHolderView.frame = self.view.bounds; _placeHolderView.image = [UIImage imageNamed:@"profile_user_414x414"]; // 強制布局 [_placeHolderView layoutIfNeeded]; } return _placeHolderView;}
//卡頓佔位動效- (void)showActivityView{ if (!_activity) { _activity= [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; _activity.frame = CGRectMake((SCREAM_WEIGHT-100)*0.5, (SCREAM_HIGHT-100)*0.5, 100, 100); } [self.activity startAnimating]; [self.view addSubview:self.activity];}//關閉卡頓佔位動效- (void)stopActivityView{ if ([_activity isAnimating]) { [_activity startAnimating]; } [_activity removeFromSuperview]; _activity = nil;}
二.拉流播放(建立播放器播放),代碼如下:
- (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.placeHolderView]; [self showActivityView]; IJKFFOptions *options = [IJKFFOptions optionsByDefault]; [options setPlayerOptionIntValue:1 forKey:@"videotoolbox"]; // 畫面播放速率(fps) (可以改,確認非標準楨率會導致音畫不同步,所以只能設定為15或者29.97) [options setPlayerOptionIntValue:29.97 forKey:@"r"]; // -vol——設定音量大小,256為標準音量。(要設定成兩倍音量時則輸入512,依此類推 [options setPlayerOptionIntValue:512 forKey:@"vol"]; IJKFFMoviePlayerController *moviePlayer = [[IJKFFMoviePlayerController alloc] initWithContentURLString:PLAY_URL withOptions:options]; moviePlayer.view.frame = self.view.bounds; moviePlayer.scalingMode = IJKMPMovieScalingModeAspectFill; // 設定自動播放(必須設定為NO, 防止自動播放, 才能更好的控制直播的狀態) moviePlayer.shouldAutoplay = NO; // 預設不顯示 moviePlayer.shouldShowHudView = NO; [self.view insertSubview:moviePlayer.view atIndex:0]; [moviePlayer prepareToPlay]; self.moviePlayer = moviePlayer; // 設定監聽 [self addObserver]; [self.view addSubview:self.outBtn];}
三.設定監聽(主要是監聽緩衝情況),代碼如下:
- (void)addObserver{ //監聽載入狀態改變通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadStateDidChange:) name:IJKMPMoviePlayerLoadStateDidChangeNotification object:self.moviePlayer];}- (void)loadStateDidChange:(NSNotification *) notification{ //狀態為緩衝幾乎完成,可以連續播放 if ((self.moviePlayer.loadState & IJKMPMovieLoadStatePlaythroughOK) != 0) { if (!self.moviePlayer.isPlaying) { //開始播放 [self.moviePlayer play]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if (_placeHolderView) { [_placeHolderView removeFromSuperview]; _placeHolderView = nil; } [self stopActivityView]; }); }else{ // 如果是網路狀態不好, 斷開後恢複, 也需要去掉載入 if ([_activity isAnimating]) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self stopActivityView]; }); } } } //緩衝中 else if (self.moviePlayer.loadState & IJKMPMovieLoadStateStalled){ [self showActivityView]; /* 這裡主播可能已經結束直播了。我們需要請求伺服器查看主播是否已經結束直播。 方法: 1、從伺服器擷取主播是否已經關閉直播。 優點:能夠正確的擷取主播端是否正在直播。 缺點:主播端異常crash的情況下是沒有辦法通知伺服器該直播關閉的。 2、使用者http請求該地址,若請求成功表示直播未結束,否則結束 優點:能夠真實的擷取主播端是否有推流資料 缺點:如果主播端丟包率太低,但是能夠恢複的情況下,資料請求同樣是失敗的。 */ __weak typeof(self)weakSelf = self; [[ALinNetworkTool shareTool] GET:PLAY_URL parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"請求成功%@, 等待繼續播放", responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"請求失敗, 載入失敗介面, 關閉播放器%@", error); [weakSelf performSelector:@selector(outBtnTouched)]; }]; }}
四.記得關閉前釋放
- (void)dealloc{ if (_moviePlayer) { [_moviePlayer shutdown]; [_moviePlayer.view removeFromSuperview]; _moviePlayer = nil; } [[NSNotificationCenter defaultCenter]removeObserver:self];}
總結:項目中還有許多缺陷等待一一完善。
iOS簡單直播實現(三:IJKMediaFramework拉流)