视频直播
拉流:
从服务器获取视频直播流地址,播放直播 使用IJKMediaFramework.framework
使用:
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:flv withOptions:options];
moviePlayer.view.frame = self.contentView.bounds;
// 填充fill
moviePlayer.scalingMode = IJKMPMovieScalingModeAspectFill;
// 设置自动播放(必须设置为NO, 防止自动播放, 才能更好的控制直播的状态)
moviePlayer.shouldAutoplay = NO;
// 默认不显示
moviePlayer.shouldShowHudView = NO;
[self.contentView insertSubview:moviePlayer.view atIndex:0];
[moviePlayer prepareToPlay];
self.moviePlayer = moviePlayer;
推流:
开始直播,视频采集和视频流处理与传输
直播采用L
LFLiveKit 支持的流类型
rtmp格式 、 tcp 传输flv格式
使用
开播逻辑
- (void)startLive {
MPLiveModel *liveModel = [ZQGlobalObject sharedZQGlobalObject].liveModel;
// 拼接推流地址 “url/流名”
NSString *url = [NSString stringWithFormat:@"%@/%@", liveModel.rtmpUrl, liveModel.videoId];
// 创建流对象
LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
stream.url = url;
// 推流对象开始推流
[_session startLive:stream];
}
进出后台处理
#pragma mark 应用程序通知监听
- (void)applicationNotification:(NSNotification *)note {
if (_session) {
// 进入后台
if (note.name == UIApplicationDidEnterBackgroundNotification) { // 进入后台
NSLog(@"进入后台");
[_controlView pauseLive];
// 从后台回到直播间
} else if (note.name == UIApplicationWillEnterForegroundNotification) {
if (!_session.running) {
_session.running = YES;
}
[self startLive];
}
}
}
退出直播间,释放对象
- (void)dealloc {
if (_session) {
_session.delegate = nil;
_session = nil;
}
NSLog(@"退出直播间");
}
创建推流对象并设置播放参数
- (LFLiveSession *)session {
if(!_session){
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Medium2 orientation:UIInterfaceOrientationPortrait] liveType:LFLiveRTMP];
_session.delegate = self;
_session.running = YES;
_session.preView = _preview;
}
return _session;
}
创建推流要展示推流效果的视图对象
- (MPLiveControlView *)controlView {
if (_controlView == nil) {
_controlView = [[MPLiveControlView alloc] initWithFrame:self.view.frame];
_controlView.delegate = self;
_controlView.session = self.session;
}
return _controlView;
}
推流状态的回调
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state{
NSLog(@"liveStateDidChange: %ld", state);
WS(weakSelf);
dispatch_async(dispatch_get_main_queue(), ^{
switch (state) {
case LFLiveReady:
[weakSelf.controlView setLiveState:MPLiveStateLoading];
break;
case LFLivePending:
[weakSelf.controlView setLiveState:MPLiveStateLoading];
break;
case LFLiveStart:
[weakSelf.controlView setLiveState:MPLiveStatePlay];
break;
case LFLiveError:
// _stateLabel.text = @"连接错误";
break;
case LFLiveStop:
[weakSelf.controlView setLiveState:MPLiveStateStop];
break;
default:
break;
}
});
}
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo{
NSLog(@"debugInfo: %lf", debugInfo.dataFlow);
}
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode{
NSLog(@"errorCode: %ld", errorCode);
}
弹幕可以使用BarrageRenderer
简单使用:
_renderer = [[BarrageRenderer alloc] init];
// 设置弹幕的显示区域. 基于父控件的.
_renderer.canvasMargin = UIEdgeInsetsMake(ALinScreenHeight * 0.3, 10, 10, 10);
[self.contentView addSubview:_renderer.view];
弹幕配置
#pragma mark - 弹幕描述符生产方法
/// 生成精灵描述 - 过场文字弹幕
- (BarrageDescriptor *)walkTextSpriteDescriptorWithDirection:(NSInteger)direction
{
BarrageDescriptor * descriptor = [[BarrageDescriptor alloc]init];
descriptor.spriteName = NSStringFromClass([BarrageWalkTextSprite class]);
descriptor.params[@"text"] = self.danMuText[arc4random_uniform((uint32_t)self.danMuText.count)];
descriptor.params[@"textColor"] = Color(arc4random_uniform(256), arc4random_uniform(256), arc4random_uniform(256));
descriptor.params[@"speed"] = @(100 * (double)random()/RAND_MAX+50);
descriptor.params[@"direction"] = @(direction);
descriptor.params[@"clickAction"] = ^{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:@"弹幕被点击" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];
[alertView show];
};
return descriptor;
}
[_renderer start];