直播类app中拉流技术的实现[转]
之前说过推流的实现 ,现在来说一下拉流的实现。demo下载地址:https://pan.baidu.com/s/1fU5SMyEDRAVaGBIBvYzbVw
拉流的实现我们主要通过LFLiveKit,LFLiveKit支持H264和AAC编码,支持美颜和水印效果,传输协议是rtmp,支持弱网丢帧,记载网络环境差的情况下,为了保证视频的通常,会自动丢弃个别帧。
先看一下LFLiveKit提供的Demo运行效果:(准备工具VLC软件)
1.github上搜索LFLiveKit。
2.打开下载后文件的LFLiveKitDemo工程(这里我们使用的是OC的Demo,不是swift),控制台中cd +这个工程的路径,然后pod install,之后便可运行在真机上。
3.打开LFLivePreview.m文件,在这个文件的末尾会发现有这样一行代码: stream.url = @"rtmp://live.hkstv.hk.lxdns.com:1935/live/stream153”;并将这个网址复制到浏览器中打开,此时会自动打开VLC软件,点击playList中的网址,便可播放手机端的拉流视频。
4.如果以上步骤执行无误,就说明手机端的拉流视频已经成功推送到服务器上,我们通过VLC可以获取到服务器上的推流视频。
接下来看看如何将LFLiveKit继承到我们自己的项目中去。
首先在podfile文件中添加pod ‘LFLiveKit’ ,然后 pod install。接下来就可以直接开始代码部分了。
创建一个继承与UIView的LFLivePreview类,在LFLivePreview.h文件中对外提供两个方法,开始拉直播和关闭直播方法。
@interface LFLivePreview : UIView
- (void)startLive;
- (void)stopLive;
@end
在LFLivePreview.m文件中,首先导入头文件#import "LFLiveSession.h”,并遵守LFLiveSessionDelegate协议,然后添加一个属性@property (nonatomic, strong) LFLiveSession *session;看一些这个属性的懒加载代码:
- (LFLiveSession *)session {
if (!_session) {
/*** 默认分辨率368 * 640 音频:44.1 iphone6以上48 双声道 方向竖屏 ***/
LFLiveAudioConfiguration * audioConfiguration =[LFLiveAudioConfiguration defaultConfiguration];
LFLiveVideoConfiguration * videoConfiguration = [LFLiveVideoConfiguration defaultConfiguration];
//最新写法
_session = [[LFLiveSession alloc]initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration captureType:LFLiveCaptureDefaultMask];
// _session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration liveType:LFLiveRTMP];
_session.delegate = self;
_session.showDebugInfo = NO;
_session.preView = self;
}
return _session;
}
在初始化这个view的时候首先要实现音频和视频授权操作。
- (void)requestAccessForVideo {
__weak typeof(self) _self = self;
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
switch (status) {
case AVAuthorizationStatusNotDetermined: {
// 许可对话没有出现,发起授权许可
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
dispatch_async(dispatch_get_main_queue(), ^{
[_self.session setRunning:YES];
});
}
}];
break;
}
case AVAuthorizationStatusAuthorized: {
// 已经开启授权,可继续
dispatch_async(dispatch_get_main_queue(), ^{
[_self.session setRunning:YES];
});
break;
}
case AVAuthorizationStatusDenied:
case AVAuthorizationStatusRestricted:
// 用户明确地拒绝授权,或者相机设备无法访问
break;
default:
break;
}
}
- (void)requestAccessForAudio {
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
switch (status) {
case AVAuthorizationStatusNotDetermined: {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
}];
break;
}
case AVAuthorizationStatusAuthorized: {
break;
}
case AVAuthorizationStatusDenied:
case AVAuthorizationStatusRestricted:
break;
default:
break;
}
}
开始直播
- (void)startLive {
LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
//这是直播的网址,直接复制LFLiveKit提供的这个地址
stream.url = @"rtmp://live.hkstv.hk.lxdns.com:1935/live/stream153";
[self.session startLive:stream];
}
- (void)startLive:(LFLiveStreamInfo *)streamInfo {
if (!streamInfo) return;
_streamInfo = streamInfo;
_streamInfo.videoConfiguration = _videoConfiguration;
_streamInfo.audioConfiguration = _audioConfiguration;
[self.socket start];
}
停止直播
- (void)stopLive {
[self.session stopLive];
}
- (void)stopLive {
self.uploading = NO;
[self.socket stop];
self.socket = nil;
}
美颜效果
- (void)beautyBtnClick:(UIButton *)btn{
self.session.beautyFace = !self.session.beautyFace;
self.beautyButton.selected = !self.session.beautyFace;
}
镜头切换
- (void)cameraBtnClick:(UIButton *)btn{
AVCaptureDevicePosition devicePositon = self.session.captureDevicePosition;
self.session.captureDevicePosition = (devicePositon == AVCaptureDevicePositionBack) ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
}
退出直播
- (void)closeBtnClick:(UIButton *)btn{
[self stopLive];
[self.controller dismissViewControllerAnimated:YES completion:nil];
}
下面这个代理方法是监控直播状态的代理方法
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state {
NSLog(@"liveStateDidChange: %ld", state);
switch (state) {
case LFLiveReady:
_stateLabel.text = @"未连接";
break;
case LFLivePending:
_stateLabel.text = @"连接中";
break;
case LFLiveStart:
_stateLabel.text = @"已连接";
break;
case LFLiveError:
_stateLabel.text = @"连接错误";
break;
case LFLiveStop:
_stateLabel.text = @"未连接";
break;
default:
break;
}
}
外部直播控制器界面调用形式
- (IBAction)startLive:(id)sender {
UIView * back = [[UIView alloc] initWithFrame:self.view.bounds];
back.backgroundColor = [UIColor blackColor];
[self.view addSubview:back];
LFLivePreview * liveView = [[LFLivePreview alloc] initWithFrame:self.view.bounds withController:self];
[self.view addSubview:liveView];
[liveView startLive];
}