直播
实现流程
更新时间: 2022/12/29 16:24:51
API 时序图
init与unInit,start与stop都要保持匹配使用。
实现方法
1 创建推流实例
SDK在初始化推流阶段,设置推流地址,配置推流参数。创建推流session 提供的接口有三种,您可以根据是否需要定制直播参数而选择。
API原型
- 只设置直播推流的地址,创建直播推流对象,其它推流相关参数将采用默认配置:
/**
* 初始化mediacapture
*
* @param liveStreamingURL 推流的url地址
*
* @return LSMediaCapture
*/
-(instancetype)initLiveStream:(NSString *)liveStreamingURL
- 设置直播推流的地址,并支持设置直播中的视频相关参数:
/**
初始化mediacapture
@param liveStreamingURL 推流的url
@param videoParaCtx 推流视频参数
@return LSMediaCapture
*/
- (instancetype)initLiveStream:(NSString *)liveStreamingURL withVideoParaCtxConfiguration:(LSVideoParaCtxConfiguration *)videoParaCtx
- 设置直播推流的地址,并支持设置直播中的音视频所有可配置参数:
/**
初始化mediacapture
@param liveStreamingURL 推流的url
@param configuration 推流参数
@return LSMediaCapture
*/
- (instancetype)initLiveStream:(NSString *)liveStreamingURL withLivestreamParaCtxConfiguration:(LSLiveStreamingParaCtxConfiguration *)configuration
参数说明
参数 | 类型 | 说明 |
---|---|---|
liveStreamingURL | NSString | 推流地址 |
videoParaCtx | LSVideoParaCtxConfiguration | 视频参数 |
configuration | LSLiveStreamingParaCtxConfiguration | 音视频参数 |
示例
LSMediaCapture *mediaCapture = [[LSMediaCapture alloc]initLiveStream:url withLivestreamParaCtxConfiguration:streamparaCtx];
特殊说明
请通过如下代码检测初始化推流是否成功,避免因相关硬件读取失败,导致无法正常使用推流SDK。
if (mediaCapture == nil) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@"初始化失败" forKey:NSLocalizedDescriptionKey];
NSError *error = [NSError errorWithDomain:@"LSMediaCaptureErrorDomain" code:0 userInfo:userInfo];
}
2 打开、暂停、恢复视频预览
API原型
/**
* 打开视频预览
*
* @param preview 预览窗口
*/
-(void)startVideoPreview:(UIView*)preview
/**
* @warning 暂停视频预览。如果正在直播,则同时关闭视频预览以及视频推流
*
*/
- (void)pauseVideoPreview
/**
* @warning 继续视频预览。如果正在直播,则开始视频推流
*
*/
- (void)resumeVideoPreview
参数说明
参数 | 类型 | 说明 |
---|---|---|
preview | UIView | 需要显示的预览画面 |
示例
[_mediaCapture startVideoPreview:localPreview];
特殊说明
支持直播过程中改变preview的大小。
3 开始或停止直播
API原型
/**
* 开始直播
*
* @param completionBlock 具体错误信息
*/
- (void)startLiveStream:(void(^)(NSError *error))completionBlock;
/**
* 结束推流
* @warning 只有直播真正开始后,也就是收到LSLiveStreamingStarted消息后,才可以关闭直播,error为nil的时候,说明直播结束,否则直播过程中发生错误
*/
- (void)stopLiveStream:(void(^)(NSError *error))completionBlock;
参数说明
参数 | 类型 | 说明 |
---|---|---|
completionBlock | void(^)(NSError *error) | 开始和停止直播过程中发生的错误回调。nil表示正常。 |
示例
[_mediaCapture startLiveStream:^(NSError *error) {
if (error != nil) {
//开始推流,出现错误,首先检查参数和网络是否正常,对应日志查看具体错误内容
[weakSelf showErrorInfo:error ];
}
}];
[_mediaCapture stopLiveStream:^(NSError *error) {
if (error == nil) {
dispatch_async(dispatch_get_main_queue(), ^(void){
_isLiving = NO;
[weakSelectView.startBtn setBackgroundImage:[UIImage imageNamed:@"restart"] forState:UIControlStateNormal];
});
}
}];
特殊说明
无
4 释放推流实例
反初始化:释放资源
API原型
/**
反初始化:释放资源
*/
-(void)unInitLiveStream
参数说明
无
示例
[mediaCapture unInitLiveStream];
mediaCapture = nil;
特殊说明
建议在调用unInitLiveStream之后,将mediaCapture实例对象置为空,用于完全释放资源
代码示例
- 必须 SDK涉及到麦克风,摄像头的采集,需要事先打开使用权限,申请权限代码如下。
- (BOOL)requestMediaCapturerAccessWithCompletionHandler:(void (^)(BOOL, NSError*))handler {
AVAuthorizationStatus videoAuthorStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
AVAuthorizationStatus audioAuthorStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
if (AVAuthorizationStatusAuthorized == videoAuthorStatus && AVAuthorizationStatusAuthorized == audioAuthorStatus) {
handler(YES,nil);
}else{
if (AVAuthorizationStatusRestricted == videoAuthorStatus || AVAuthorizationStatusDenied == videoAuthorStatus) {
NSString *errMsg = NSLocalizedString(@"此应用需要访问摄像头,请设置", @"此应用需要访问摄像头,请设置");
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:errMsg};
NSError *error = [NSError errorWithDomain:@"访问权限" code:0 userInfo:userInfo];
handler(NO,error);
return NO;
}
if (AVAuthorizationStatusRestricted == audioAuthorStatus || AVAuthorizationStatusDenied == audioAuthorStatus) {
NSString *errMsg = NSLocalizedString(@"此应用需要访问麦克风,请设置", @"此应用需要访问麦克风,请设置");
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:errMsg};
NSError *error = [NSError errorWithDomain:@"访问权限" code:0 userInfo:userInfo];
handler(NO,error);
return NO;
}
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
if (granted) {
handler(YES,nil);
}else{
NSString *errMsg = NSLocalizedString(@"不允许访问麦克风", @"不允许访问麦克风");
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:errMsg};
NSError *error = [NSError errorWithDomain:@"访问权限" code:0 userInfo:userInfo];
handler(NO,error);
}
}];
}else{
NSString *errMsg = NSLocalizedString(@"不允许访问摄像头", @"不允许访问摄像头");
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:errMsg};
NSError *error = [NSError errorWithDomain:@"访问权限" code:0 userInfo:userInfo];
handler(NO,error);
}
}];
}
return YES;
}
- 必须 初始化推流对象
LSLiveStreamingParaCtxConfiguration *paraCtx = [LSLiveStreamingParaCtxConfiguration defaultLiveStreamingConfiguration];//直播推流参数
paraCtx.eHaraWareEncType = LS_HRD_AV;
paraCtx.eOutFormatType = LS_OUT_FMT_RTMP;
paraCtx.eOutStreamType = LS_HAVE_AV; //这里可以设置推音视频流/音频流/视频流,如果只推送视频流,则不支持伴奏播放音乐
//视频相关参数
paraCtx.sLSVideoParaCtx.interfaceOrientation = LS_CAMERA_ORIENTATION_PORTRAIT;//摄像头的方向,可以选择横屏或者竖屏
paraCtx.sLSVideoParaCtx.cameraPosition = LS_CAMERA_POSITION_FRONT;//前后摄像头
paraCtx.sLSVideoParaCtx.bitrate = 640000; //码率
paraCtx.sLSVideoParaCtx.fps = 24; //帧率
paraCtx.sLSVideoParaCtx.videoStreamingQuality = LS_VIDEO_QUALITY_HIGH; //分辨率
paraCtx.sLSVideoParaCtx.isCameraZoomPinchGestureOn = YES; //打开摄像头zoom功能
paraCtx.sLSVideoParaCtx.isCameraFlashEnabled = YES; //打开摄像头flash功能
paraCtx.sLSVideoParaCtx.isVideoWaterMarkEnabled = YES; //开启水印
paraCtx.sLSVideoParaCtx.videoRenderMode = LS_VIDEO_RENDER_MODE_SCALE_16x9;//设置为16:9模式 //对端接收的图像将以16:9比例绘制
paraCtx.sLSVideoParaCtx.isVideoFilterOn = YES; //开启美颜
paraCtx.sLSVideoParaCtx.filterType = LS_GPUIMAGE_ZIRAN;//默认使用这种滤镜
paraCtx.sLSVideoParaCtx.isQosOn = YES; // 开启码率自适应调整功能
paraCtx.sLSVideoParaCtx.isFrontCameraMirroredPreView = YES; //是否镜像前置摄像头预览
paraCtx.sLSVideoParaCtx.isFrontCameraMirroredCode = NO; //是否镜像前置摄像头编码
//音频相关参数
paraCtx.sLSAudioParaCtx.bitrate = 64000;
paraCtx.sLSAudioParaCtx.frameSize = 2048;
paraCtx.sLSAudioParaCtx.numOfChannels = 1;
paraCtx.sLSAudioParaCtx.samplerate = 44100;
NSString* _streamUrl = @"rtmp:pxxxxx" ;//初始化阶段允许 此字段为nil
LSMediaCapture* _mediaCapture;
_mediaCapture = [[LSMediaCapture alloc]initLiveStream:_streamUrl withLivestreamParaCtxConfiguration:paraCtx]; //初始化推流
- 可调用非必须 打开视频预览
[_mediaCapture startVideoPreview:self.localPreview];
- 可调用非必须 开启直播之前可以重新设置推流地址,当然也可以继续使用初始化推流阶段的推流地址。
_mediaCapture.pushUrl = @"rtmp://pxxx";
- 可调用非必须 开启直播之前可以重新设置视频相关参数
[_mediaCapture setBitrate:150000 fps:30 cameraOrientation:LS_CAMERA_ORIENTATION_PORTRAIT];//视频的码率,帧率,以及视频的方向横屏或者竖屏
//如果摄像头方向发生变化了,想要camera的预览画面跟着旋转,则在调用一次开启预览
[_mediaCapture startVideoPreview:self.localPreview];
- 可调用非必须 注册mediacapture的notification监听,获取直播过程中的各种状态信息,不是必须
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onStartLiveStream:) name:LS_LiveStreaming_Started object:nil]; //直播开始通知
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onFinishedLiveStream:) name:LS_LiveStreaming_Finished object:nil]; // 直播结束通知
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onBadNetworking:) name:LS_LiveStreaming_Bad object:nil]; //直播过程中网络差通知
- 必须 设置获取直播过程中的错误回调
__weak MediaCaptureViewController *weakSelf = self;
_mediaCapture.onLiveStreamError = ^(NSError* error)
{
if (error != nil) {
[weakSelf LiveStreamErrorInterrup];
}
};
- 可调用非必须 显示统计信息
//调用统计数据回调
_mediaCapture.onStatisticInfoGot = ^(LSStatisticsObject* statistics)
{
if (statistics != nil) {
dispatch_async(dispatch_get_main_queue(),^(void) {[weakSelf showStatInfo:statistics];});
}
};
- 可调用非必须 添加水印
UIImage* image = [UIImage imageNamed:[[[NSBundle mainBundle] bundlePath]stringByAppendingPathComponent:@"logo.png"]];
[_mediaCapture addWaterMark:image rect:CGRectMake(20, 20, 60, 34) location:LS_WATERMARK_LOCATION_RIGHTUP];
- 必须 开启直播
[_mediaCapture startLiveStream:^(NSError *error) {
if (error != nil) {
[weakSelf showErrorInfo:error ];//直播出错可以将出错信息直接显示给用户,也可以封装成统一格式,告诉用户检查网络等情况,尝试重新开启直播
}
}];
- 可调用非必须 直播开启准备工作已经完成,当收到“直播开始notification”,说明推流真的开始了,可以在收到这个notification后,做一些动作,不是必须。
-(void)onStartLiveStream:(NSNotification*)notification
{
NSLog(@"on start live stream");//只有收到直播开始的 信号,才可以关闭直播
__weak MediaCaptureViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^(void){
_isLiving = YES;
weakSelf.showStatButton.enabled = YES;
UIImage *startBtnImage = [UIImage imageNamed:@"pause0.png"];
[weakSelf.startButton setImage:startBtnImage forState:UIControlStateNormal];
//当直播开始时,获取当前最新的一张图片
[ weakSelf.mediaCapture snapShotWithCompletionBlock:^(UIImage *latestFrameImage) {
UIImageWriteToSavedPhotosAlbum(latestFrameImage, weakSelf, nil, nil);
}];
});
}
- 必须 当收到直播出错回调,需要关闭直播,您可以在关闭推流之后,重新开启直播,不需要将资源释放,当然也可以将资源mediacapture全部释放,重新来一次初始化,开启直播操作
-(void)LiveStreamErrorInterrup{
[_mediaCapture stopLiveStream:^(NSError *error) {
if (error == nil) {
NSLog(@"直播结束了");
}else{
NSLog(@"结束直播发生错误");//调用 stopLiveStream()
}
}];
}
- 必须 关闭推流
__weak MediaCaptureViewController *weakSelf1 = self;
[_mediaCapture stopLiveStream:^(NSError *error) {
if (error == nil) {
NSLog(@"直播结束了");
}else{
NSLog(@"结束直播发生错误");//调用 stopLiveStream()
}
}];
- 至此,一次推流过程结束,如果您需要再次开启直播,可以直接 回到
开启直播
动作,也可以将 _mediaCapture资源释放,重新从初始化推流
开始。
Demo接入Faceunity
- Faceunity的github地址
- Demo 已集成Faceunity相关功能,假设你需要在demo中演示相关功能,需要打开demo中的开关,并向Faceunity或者网易云信视频索要具体的证书秘钥。
- 具体的操作如下图所示。
- 打开demo开关
- 填写具体的证书秘钥
此文档是否对你有帮助?
有帮助
去反馈