前言:直播模块主要采用了
BiliBili视频提供的开源框架ijkplayer
完成拉流,优酷的来疯直播提供的开源框架LFLiveKit
完成直播推流。项目中同时还涉及了动画,绘图,定位,自动布局,三方登录等等热门技术。
# 核心代码
#import
@interface ZYSPlayerViewController ()
@property(atomic, retain) id player;
@end
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = YES;
//注册直播需要用的通知
[self installMovieNotificationObservers];
//准备播放
[self.player prepareToPlay];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.navigationController.navigationBarHidden = NO;
//关闭直播
[self.player shutdown];
[self removeMovieNotificationObservers];
}
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化
[self initPlayer];
}
- (void)initPlayer {
///初始化ijkplayer并添加
IJKFFOptions * options = [IJKFFOptions optionsByDefault];
IJKFFMoviePlayerController * player = [[IJKFFMoviePlayerController alloc] initWithContentURLString:self.live.streamAddr withOptions:options];
self.player = player;
self.player.view.frame = self.view.bounds;
self.player.shouldAutoplay = YES;
[self.view addSubview:self.player.view];
}
注册通知&移除通知注册通知(ijkplayer是对FFMPeg进行封装,对拉流得到的H264视频编码以及AAC的音频进行解析,通过通知做响应的操作)
# 关键代码
#pragma mark Install Movie Notifications(注册通知ijkplayer是对FFMPeg进行封装,对拉流得到的H264视频编码以及AAC的音频进行解析,通过通知做响应的操作)
/* Register observers for the various movie object notifications. */
-(void)installMovieNotificationObservers
{
//监听网络环境,监听缓冲方法
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(loadStateDidChange:)
name:IJKMPMoviePlayerLoadStateDidChangeNotification
object:_player];
//监听直播完成回调
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackDidFinish:)
name:IJKMPMoviePlayerPlaybackDidFinishNotification
object:_player];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mediaIsPreparedToPlayDidChange:)
name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
object:_player];
//监听用户主动操作
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackStateDidChange:)
name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:_player];
}
#pragma mark Remove Movie Notification Handlers
/* Remove the movie notification observers from the movie object. */
-(void)removeMovieNotificationObservers
{
[[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerLoadStateDidChangeNotification object:_player];
[[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackDidFinishNotification object:_player];
[[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:_player];
[[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:_player];
}
///直播状态变化的监听
- (void)moviePlayBackStateDidChange:(NSNotification*)notification
{
// MPMoviePlaybackStateStopped,
// MPMoviePlaybackStatePlaying,
// MPMoviePlaybackStatePaused,
// MPMoviePlaybackStateInterrupted,
// MPMoviePlaybackStateSeekingForward,
// MPMoviePlaybackStateSeekingBackward
switch (_player.playbackState)
{
case IJKMPMoviePlaybackStateStopped: {
NSLog(@"IJKMPMoviePlayBackStateDidChange %d: stoped", (int)_player.playbackState);
break;
}
case IJKMPMoviePlaybackStatePlaying: {
NSLog(@"IJKMPMoviePlayBackStateDidChange %d: playing", (int)_player.playbackState);
break;
}
case IJKMPMoviePlaybackStatePaused: {
NSLog(@"IJKMPMoviePlayBackStateDidChange %d: paused", (int)_player.playbackState);
break;
}
case IJKMPMoviePlaybackStateInterrupted: {
NSLog(@"IJKMPMoviePlayBackStateDidChange %d: interrupted", (int)_player.playbackState);
break;
}
case IJKMPMoviePlaybackStateSeekingForward:
case IJKMPMoviePlaybackStateSeekingBackward: {
NSLog(@"IJKMPMoviePlayBackStateDidChange %d: seeking", (int)_player.playbackState);
break;
}
default: {
NSLog(@"IJKMPMoviePlayBackStateDidChange %d: unknown", (int)_player.playbackState);
break;
}
}
}
///直播结束的监听
- (void)moviePlayBackDidFinish:(NSNotification*)notification
{
// MPMovieFinishReasonPlaybackEnded, 直播结束
// MPMovieFinishReasonPlaybackError, 直播错误
// MPMovieFinishReasonUserExited 用户退出
int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
switch (reason)
{
case IJKMPMovieFinishReasonPlaybackEnded:
NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackEnded: %d\n", reason);
break;
case IJKMPMovieFinishReasonUserExited:
NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonUserExited: %d\n", reason);
break;
case IJKMPMovieFinishReasonPlaybackError:
NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackError: %d\n", reason);
break;
default:
NSLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
break;
}
}
///相关设置状态
- (void)loadStateDidChange:(NSNotification*)notification
{
// MPMovieLoadStateUnknown = 0,未知
// MPMovieLoadStatePlayable = 1 << 0,缓冲结束可以播放
// MPMovieLoadStatePlaythroughOK = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES 缓冲结束自动播放
// MPMovieLoadStateStalled = 1 << 2, // Playback will be automatically paused in this state, if started
//暂停
IJKMPMovieLoadState loadState = _player.loadState;
if ((loadState & IJKMPMovieLoadStatePlaythroughOK) != 0) {
NSLog(@"loadStateDidChange: IJKMPMovieLoadStatePlaythroughOK: %d\n", (int)loadState);
} else if ((loadState & IJKMPMovieLoadStateStalled) != 0) {
NSLog(@"loadStateDidChange: IJKMPMovieLoadStateStalled: %d\n", (int)loadState);
} else {
NSLog(@"loadStateDidChange: ???: %d\n", (int)loadState);
}
self.blurImageView.hidden = YES;
[self.blurImageView removeFromSuperview];
}