1.nginx rtmp本地推流拉流服务器搭建
1.1 安装 (没安装brew的同学,阔以看下这篇文章http://blog.csdn.net/wdd1324/article/details/72769789)
sudo brew install nginx
1.2 查看版本号
nginx -v
安装成功则返回 nginx version: nginx/1.12.2
1.3 启动nginx
sudo nginx
如果报错
nginx: [emerg] bind() to 0.0.0.0:80 failed (48: Address already in use)
这个是端口被占用,我们可以杀死其他占用该端口号的进程或者在nginx.conf里修改端口号
先说杀死一个进程的方法,后面会说到修改nginx.conf
sudo lsof -i tcp:8080
然后找到PID值,再kill掉该进程
kill PID
再次启动 nginx
启动成功
打开浏览器 输入http://localhost:8080 出现以下界面则成功
1.4 配置nginx
打开终端 cd到nginx目录下
cd /usr/local/etc/nginx
运行vim 打开nginx.conf
vim nginx.conf
配置rtmp (这里可以不用做配置,直接用一个端口就能实现推拉,推拉都为同一个端口)
listen为监听的端口号,192.168.4.205是我本地的ip地址,我用一个src作为推流地址,一个des作为拉流地址,用ffmpeg将输入源接入输出源,360x480为输出的分辨率
rtmp {
server {
listen 8080;
chunk_size 4000;
# TV mode: one publisher, many subscribers
application src {
# enable live streaming
live on;
interleave on;
wait_key on;
# publish only from localhost
allow publish all;
#deny publish all;
allow play all;
exec /usr/local/opt/ffmpeg/bin/ffmpeg -i rtmp://192.168.4.205:8080/src -vcodec libx264 -vprofile main -tune zerolatency -s 360x480 -pix_fmt yuv420p -movflags +faststart -preset ultrafast -f flv rtmp://192.168.4.205:8080/des;
}
application des {
live on;
interleave on;
wait_key on;
}
}
}
1.5 重启nginx
sudo nginx -s reload
这样就OK啦,可以在mac上通过OBS来推流,VLC来拉流测试是否成功。
1.6 其他命令与问题
关闭nginx
sudo nginx -s stop
2.使用LFLiveKit来推流(采用的是h264视频编码,ACC的音频硬编码)
2.1用Pods来添加LFLiveKit
pod 'LFLiveKit'
2.2LFLiveSession初始化
设置视频图像的分辨率
LFLiveVideoConfiguration *config = [LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Low1];
config.videoSize = CGSizeMake(360, 512); //图片分辨率
初始化session
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfigurationForQuality:LFLiveAudioQuality_Low] videoConfiguration:config captureType:LFLiveCaptureMaskVideo];
_session.preView= self.livingPushView; //推流预览
_session.captureDevicePosition = AVCaptureDevicePositionUnspecified; //设置为后置摄像头,默认为前置摄像头
_session.beautyFace = NO; //是否美颜
_session.running = YES; //是否播放(默认为NO的,不添加则无预览图像)
_session.delegate = self; //设置代理
2.3LFLive的代理方法
根据代理可以查看到推流状态
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state {
switch (state) {
case LFLiveReady: {
NSLog(@"-准备");
}
break;
case LFLivePending: {
NSLog(@"-连接中");
}
break;
case LFLiveStart: {
NSLog(@"-已连接");
}
break;
case LFLiveStop: {
NSLog(@"-已断开");
}
break;
case LFLiveError: {
NSLog(@"-连接出错");
}
break;
case LFLiveRefresh: {
NSLog(@"-正在刷新");
}
break;
default:
break;
}
}
2.4 开始推流
LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
stream.url = @"rtmp://192.168.4.205:8080/src";
[self.session startLive:stream];
界面消失的时候停止推流
[self.session stopLive];
下面我们看一下拉流
- IJKPlayer
3.1IJKMediaFramework集成
大家阔以看下这片文章,写得很详细
http://www.jianshu.com/p/1f06b27b3ac0
3.2 IJKMediaFramework集成成功后,在使用的地方导入
#import <IJKMediaFramework/IJKFFOptions.h>
#import <IJKMediaFramework/IJKMediaPlayer.h>
#import <IJKMediaFramework/IJKFFMoviePlayerController.h>
3.3 配置IJKFFOptions
IJKFFOptions *options = [IJKFFOptions optionsByDefault];
[options setPlayerOptionValue:@"1" forKey:@"an"]; //静音设置
[options setPlayerOptionValue:@"1" forKey:@"videotoolbox"]; //开启硬解码
[options setPlayerOptionIntValue:10 forKey:@"max-buffer-size"]; //最大缓存
[options setFormatOptionIntValue:10 forKey:@"rtbufsize"]; //缓存
[options setFormatOptionIntValue:2000000 forKey:@"analyzeduration"];
[options setFormatOptionValue:@"nobuffer" forKey:@"fflags"];
[options setFormatOptionIntValue:4096 forKey:@"probsize"];
这是楼主的一些配置参数。
3.4 IJKFFMoviePlayerController初始化
self.player = [[IJKFFMoviePlayerController alloc] initWithContentURLString:_ipstring2 withOptions:options];
self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.player.view.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
self.player.view.backgroundColor = [UIColor blackColor];
self.player.scalingMode = IJKMPMovieScalingModeAspectFill; //缩放模式
self.player.shouldAutoplay = YES; //开启自动播放(player准后后,自动播放)
[self.view addSubview:self.player.view];// 添加拉流预览视图
[self.player prepareToPlay];
3.5 添加观察者,监听拉流状态
//监听网络状态改变
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadStateDidChange:) name:IJKMPMoviePlayerLoadStateDidChangeNotification object:self.player];
//监听播放网络状态改变
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playStateDidChange:) name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:self.player];
//网络状态改变通知响应
- (void)loadStateDidChange:(NSNotification *)notification{
IJKMPMovieLoadState loadState = self.player.loadState;
if ((loadState & IJKMPMovieLoadStatePlaythroughOK) != 0) {
NSLog(@"LoadStateDidChange: 可以开始播放的状态: %d\n",(int)loadState);
}else if ((loadState & IJKMPMovieLoadStateStalled) != 0) {
NSLog(@"loadStateDidChange: IJKMPMovieLoadStateStalled: %d\n", (int)loadState);
} else {
NSLog(@"loadStateDidChange: ???: %d\n", (int)loadState);
}
}
//播放状态改变通知响应
- (void)playStateDidChange:(NSNotification *)notification{
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;
}
}
}
3.6 界面消失的时候,关闭播放器
[self.player stop];
[self.player shutdown];