iOS直播推流SDK开发集成
1 概述
1.1 SDK简介
1.1.1 SDK业务简介
网易云信直播源自网易多年视频技术沉淀,基于专业的跨平台视频编解码技术和大规模视频内容分发网络,提供稳定流畅、低延时、高并发的直播服务。
网易云信直播推流SDK,用于支持在直播流程中,采集摄像头或自定义音视频数据,进行视频前处理,并进行编码推流到服务器。具有稳定、高效、功能全面的特点。
1.1.2 SDK技术简介
直播推流 SDK 由如下图所示的结构组成。 其中,实线框是直播的主要模块,包括音视频采集、处理、编码和打包发送。虚线框是辅助模块,关闭后不影响直播功能。
网络信息统计功能帮助开发者实现网络状况的实时监测,尤其在弱网络环境下,能够快速准确的探知网络可用带宽等信息,帮助开发者调整产品策略,改善产品的用户体验。
1.2 设备和系统要求:
- 支持iOS 9.0及以上系统
1.3 功能特性
- 支持推流到主流 RTMP 服务器
- 支持 H.264 和 AAC 编码
- 支持视频硬件编码和音频硬件编码
- 支持纯音频或者纯视频推流
- 支持直播中伴音
- 支持直播中单独暂停音频或者视频
- 支持MP4录制
- 支持显示推流统计信息
- 支持自定义YUV、PCM输入
- 支持YUV、PCM回调
- 支持直播前测速
- 支持音视频设备管理
- 支持音视频采集,编码,打包,传输
- 支持 armv7、arm64、i386、x86_64 架构
- 资源占用率低,库文件小
- 画质清晰,延时低
- 支持闪光灯开启操作(Flash)
- 支持摄像头缩放操作(Zoom)
- 支持前后置摄像头动态切换
- 支持分辨率动态切换
- 支持自动对焦
- 支持视频本地预览镜像操作(主播)
- 支持视频编码镜像操作(观众)
- 支持视频截图
- 支持黑白、自然、粉嫩、怀旧四款滤镜
- 支持磨皮强度调节
- 支持美白强度调节
- 支持曝光度调节
- 支持添加静态水印
- 支持添加动态水印
- 支持添加动态涂鸦
- 支持关闭本地预览静态水印
- 支持关闭本地预览动态水印
- 支持清除水印
2 开发准备
2.1 准备工作
2.2 集成SDK
本文是根据官网的直播推流 Demo 来介绍 SDK 的集成,可在网易云信官网下载最新的直播推流 iOS Demo,来查看更多的实现细节。
2.2.1 集成方式
直播 SDK 提供两种集成方式:您既可以通过 CocoaPods
自动集成我们的 SDK,也可以通过手动下载 SDK, 然后添加到您的项目中。
我们提供两个下载地址。分别为:
官网 SDK 下载入口。
我们提供了 GitHub 发布仓库 。NMCLiveStreaming。
手动集成
直播推流 SDK 包含 demo、libs、docs 三个部分,在网易云信官网可以下载 Demo 和 SDK 包。
demo部分: 里面包含一个示例工程,实现了音视频直播推流功能,有完整的源代码。
docs目录: 存放直播推流 SDK 各接口 API 类的用法。
libs目录: 存放直播推流 SDK 的动态库和资源文件,包括真机版本和模拟器版本,文件列表如下:
libs
├── NMCLiveStreaming.framework
├── NMCBasicModuleFramework.framework
└── NMCVideoFilter.bundle
开发者将动态库和资源文件导入自己的工程即可。
根据自己工程需要,下载对应版本的 直播 SDK,得到 NMCLiveStreaming.framework 、NMCBasicModuleFramework.framework文件 ,以及未连接的全部三方依赖库 注1 ,将他们导入工程。
添加其他 NMCLiveStreaming SDK 依赖库
- VideoToolbox.framework
- AudioToolbox.framework
- libz.1.tbd
- libsqlite3.tbd
- libc++.tbd
- libresolv.tbd
注1 :开发者应根据自身项目,将不冲突的依赖库也添加进工程。
MINI SDK: MINI SDK的包大小会比正常SDK小很多,但同时MINI SDK也将缺少视频前处理相关功能(裁剪、滤镜、美颜、水印等)和音视频软件编码,其他部分与正常SDK相同。
在
Build Settings
->Other Linker Flags
里,添加选项-ObjC
。如果需要在后台时保持音频通话状态,在
Capabilities
->Background Modes
里 勾选audio, airplay, and Picture in Picture
。在需要使用直播 SDK 的地方
#import <NMCLiveStreaming/NMCLiveStreaming.h>
。在需要使用直播 MINI SDK 的地方
#import <NMCLiveStreaming_MINI/NMCLiveStreaming_MINI.h>
。
自动集成
在 Podfile
文件中加入
直播完整版:
pod 'NMCLiveStreaming'
或 直播 精简版
pod 'NMCLiveStreaming_MINI'
安装
pod install
如果无法安装 SDK 最新版本,运行以下命令更新本地的 CocoaPods 仓库列表
pod repo update
3 API概览
类别 | API名称 | 功能 |
---|---|---|
创建推流实例1 | - (instancetype)initLiveStream:(NSString *)liveStreamingURL; | 只需要设置推流地址的创建直播推流对象,其它推流相关参数将采用默认配置 |
创建推流实例2 | - (instancetype)initLiveStream:(NSString )liveStreamingURL withVideoParaCtxConfiguration:(LSVideoParaCtxConfiguration )videoParaCtx; | 不仅设置直播推流的地址,同时提供直播中视频相关参数设置 |
创建推流实例3 | - (instancetype)initLiveStream:(NSString )liveStreamingURL withLivestreamParaCtxConfiguration:(LSLiveStreamingParaCtxConfiguration )configuration; | 不仅设置直播推流地址,同时提供直播中所有可配置参数设置 |
销毁推流实例 | -(void)unInitLiveStream; | 反初始化:释放资源;建议在调用unInitLiveStream之后,将mediaCapture实例对象置为空,用于完全释放资源 |
打开视频预览 | -(void)startVideoPreview:(UIView*)preview | SDK提供视频预览功能,上层需要创建 UIView 对象,作为视频预览的窗口 |
暂停视频预览 | - (void)pauseVideoPreview | 画面不移除,暂停视频采集 |
继续视频预览 | - (void)resumeVideoPreview | 恢复视频采集 |
开始直播 | - (void)startLiveStream:(void(^)(NSError *error))completionBlock | 开始音视频推流,开始失败的具体消息由 NSError参数给出 |
结束推流 | - (void)stopLiveStream:(void(^)(NSError *error))completionBlock | 结束音视频推流,结束失败的具体消息由 NSError参数给出 |
中断视频推流 | - (void)pauseVideoLiveStream | 中断视频编码,最终不会发送 |
重启视频推流 | - (void)resumeVideoLiveStream | 恢复视频编码,最终发送 |
中断音频推流 | - (BOOL)pauseAudioLiveStream | 中断音频编码,最终不会发送 |
重启音频推流 | - (BOOL)resumeAudioLiveStream | 恢复音频编码,最终发送 |
更新自定义统计数据 | - (void)updateCutomStatistics:(NSDictionary *)customDict | 添加一些自定义的统计数据到网易云信统计数据管理平台 |
检查是否正在直播 | - (BOOL)checkIsLiving | 获取当前直播状态 |
设置日志的level | - (void)setTraceLevel:(LSMediaLog)logLevel | 设置日志的级别 |
获取当前sdk的版本号 | + (NSString*) getSDKVersionID | 获取当前sdk的版本号 |
获取当前视频帧时间戳 | -(uint64_t)currentSyncTimestamp | 获取当前视频帧时间戳,对应syncTimestamp一起使用 |
获取当前时间戳 | -(uint64_t)currentStreamTimestamp | 获取当前时间戳,对应streamTimestampPassthrough一起使用 |
发送自定义数据 | -(NSError )sendCustomData:(LSCustomDataObject )sendObject | 发送自定义数据 |
开始录制并保存本地文件(mp4录制) | - (BOOL)startRecord:(NSString *)recordFileName videoStreamingQuality:(LSVideoStreamingQuality)videoStreamingQuality | 开启mp4录制 |
停止本地录制 | - (BOOL)stopRecord | 停止mp4录制 |
开始播放混音文件 | - (BOOL)startPlayMusic:(NSString*)musicURL withEnableSignleFileLooped:(BOOL)enableLoop | 支持是否循环播放 |
结束播放混音文件,释放播放文件 | - (BOOL)stopPlayMusic | 结束播放混音文件 |
恢复播放混音文件 | - (BOOL)resumePlayMusic | 恢复播放混音文件 |
中断播放混音文件 | - (BOOL)pausePlayMusic | 中断播放混音文件 |
设置混音强度 | - (void)setMixIntensity:(int )value | 设置混音强度 |
采集模块采集的视频数据回调 | void (^externalCaptureSampleBufferCallback)(CMSampleBufferRef sampleBuffer) | 采集数据回调给外部用户进行视频前处理 |
将外部前处理之后的视频数据发送给sdk | -(void)externalInputSampleBuffer:(CMSampleBufferRef)sampleBuffer | 用户将外部进行视频前处理好回送给SDK,进行编码发送 |
麦克风采集到的原始裸数据的回调 | void (^externalCaptureAudioRawData)(AudioBufferList *bufferList,NSInteger inNumberFrames) | 采集数据回调给外部用户进行音频前处理,同步处理 |
将处理完的音频裸数据送回来 | -(void)externalInputAudioBufferList:(AudioBufferList *)bufferList inNumberFrames:(NSInteger)inNumberFrames | 用户将外部进行音频前处理好回送给SDK,进行编码发送 |
开始测速 | -(void)startSpeedCalc:(NSString )url success:(void(^)(NSMutableArray array))success fail:(void(^)())fail | 支持直播开始前测速,选择最优链路推流 |
结束测速 | -(void)stopSpeedCalc | 结束此次测速 |
测速之前设置测速次数和上传数据大小 | -(void)setSpeedCacl:(NSInteger)count Capacity:(unsigned long long)capacity | 支持设置测速次数和上传文件大小,建议不超过3次,文件大小不宜过大,否则等待时间较久 |
直播过程中发生错误的回调函数 | void (^onLiveStreamError)(NSError *error) | 直播过程中,由于各种网络原因引起直播发送错误或者直播断开的情况都会通过该回调通知用户 |
得到直播过程中的统计信息 | void (^onStatisticInfoGot)(LSStatisticsObject* statistics) | 直播过程中,实时显示推流的具体信息指标 |
flash摄像头 | BOOL flash | 打开或者关闭摄像头flash |
摄像头变焦功能属性:最大拉伸值 | CGFloat maxZoomScale | iphone4s以及之前的版本,videoMaxZoomFactor=1;不支持拉伸 |
摄像头变焦功能属性:拉伸值 | CGFloat zoomScale | 1,maxZoomScale] iphone4s以及之前的版本,videoMaxZoomFactor=1;不支持拉伸 |
摄像头变焦功能属性:拉伸值变化回调block | void (^onZoomScaleValueChanged)(CGFloat value) | 调整摄像头变焦,实时回调对应的值给用户,用以调整相应的UI |
切换前后摄像头 | - (LSCameraPosition)switchCamera:(LSSwitchModuleVideoCameraPositionBlock)cameraPostionBlock | 前后摄像头切换成功回调告诉用户 |
切换分辨率 | - (BOOL)switchVideoStreamingQuality:(LSVideoStreamingQuality)videoResolution block:(LSVideoStreamingQualityBlock)videoResolutionBlock | 支持直播过程中切换分辨率,切换分辨率,水印将自动清除,需要外部根据分辨率,再次设置水印大小 |
直播推流之前设置如下参数 | - (void)setBitrate:(int)bitrate fps:(int)fps cameraOrientation:(LSCameraOrientation) cameraOrientation | 直播开始推流之前可以再次设置帧率、码率、采集方向 |
切换本地预览镜像 | -(BOOL)changeIsFrontPreViewMirrored | 针对主播,本地观察预览画面左右镜像 |
切换编码镜像 | -(BOOL)changeIsFrontCodeMirrored | 针对拉流端观众,拉流观察画面左右镜像 |
获取视频截图 | - (void)snapShotWithCompletionBlock:(LSFrameCaptureCompletionBlock)completionBlock | 可以实时截取当前画面的一张图片 |
设置滤镜类型 | - (void)setFilterType:(LSGpuImageFilterType)filterType | 设置滤镜类型:黑白、自然、粉嫩、怀旧 |
设置磨皮强度 | - (void)setSmoothFilterIntensity:(float)value | 设置人脸的磨皮效果【0-1】 |
设置美白强度 | - (void)setWhiteningFilterIntensity:(float)value | 设置美白强度【0-1】 |
调节曝光度 | -(void)adjustExposure:(CGFloat)exposure | 调整画面的曝光度(-10.0 - 10.0 ,默认为0.0) |
添加涂鸦 | - (void)addGraffiti:(UIImage*)image rect:(CGRect)rect location:(LSWaterMarkLocation)location | 每次设置一张图片,从而实现涂鸦的一个动态变化,类似可以做一个画板 |
添加静态视频水印 | - (void) addWaterMark: (UIImage*) image rect: (CGRect) rect location: (LSWaterMarkLocation) location | 静态水印一般用作视频版权logo显示 |
关闭本地预览静态水印 | - (void)closePreviewWaterMark:(BOOL)isClosed | 可以关闭本地预览静态水印,但是拉流端还是存在的 |
添加动态视频水印 | - (void) addDynamicWaterMarks: (NSArray*) imageArray fpsCount: (unsigned int)count loop: (BOOL)looped rect: (CGRect) rect location: (LSWaterMarkLocation) location | 动态水印一般用作视频广告推广显示 |
关闭本地预览动态水印 | - (void)closePreviewDynamicWaterMark:(BOOL)isClosed | 可以关闭本地预览动态水印,但是拉流端还是存在的 |
清除水印 | - (void)cleanWaterMark | 清除之前添加的所有涂鸦、静态水印、动态水印 |
总体参数介绍
音视频参数介绍
音频参数说明LSAudioParaCtxConfiguration
参数 | 类型 | 说明 |
---|---|---|
samplerate | NSInteger | 音频的样本采集率:默认44100 |
numOfChannels | NSInteger | 音频采集的通道数:单声道,双声道,默认单声道 |
frameSize | NSInteger | 音频采集的帧大小:默认2048 |
bitrate | NSInteger | 音频编码码率:默认64k:64000 |
isUseExternalCapture | BOOL | 是否使用外部音频采集,默认不开启 |
isUseAudioPreProcess | BOOL | 是否进行音频前处理,默认开启 |
视频参数说明LSVideoParaCtxConfiguration
参数 | 类型 | 说明 |
---|---|---|
fps | NSInteger | 视频的帧率.(0~30],默认为20 |
bitrate | NSInteger | 码率,默认为500000 |
videoStreamingQuality | LSVideoStreamingQuality | 视频分辨率,默认高清 |
cameraPosition | LSCameraPosition | 视频采集前后摄像头,默认前置 |
interfaceOrientation | LSCameraOrientation | 视频采集方向,默认竖屏 |
videoRenderMode | LSVideoRenderScaleMode | 视频显示端比例,默认16:9 |
isCameraFlashEnabled | BOOL | 是否开启摄像头flash功能,默认开启 |
isCameraZoomPinchGestureOn | BOOL | 是否需要打开摄像头收视响应变焦功能,默认开启 |
isFrontCameraMirroredPreView | BOOL | 是否镜像前置摄像头预览.(针对本地预览),默认开启 |
isFrontCameraMirroredCode | BOOL | 是否镜像前置摄像头编码.(针对拉流端),默认不开启 |
isVideoFilterOn | BOOL | 是否打开滤镜支持功能.默认开启 |
filterType | LSGpuImageFilterType | 滤镜类型,默认自然 |
isVideoWaterMarkEnabled | BOOL | 是否打开水印支持.默认开启 |
isQosOn | BOOL | 是否打开qos功能.默认开启 |
isOutputRGB | BOOL | 是否输出RGB数据.默认不开启 |
isUseExternalCapture | BOOL | 是否使用外部视频采集,默认不开启 |
isUseHwBFrame | BOOL | 是否使用硬件编码B帧,只在开启硬件编码的情况下才使用,默认开启 |
音视频参数说明LSLiveStreamingParaCtxConfiguration
参数 | 类型 | 说明 |
---|---|---|
eHaraWareEncType | LSHardWareEncEnable | 是否开启硬件编码类型,默认开启 |
eOutStreamType | LSOutputStreamType | 推流类型:音视频,视频,音频,默认为音视频 |
eOutFormatType | LSOutputFormatType | 推流协议:RTMP,FLV.默认为RTMP |
sLSVideoParaCtx | LSVideoParaCtxConfiguration | 推流视频相关参数 |
sLSAudioParaCtx | LSAudioParaCtxConfiguration | 推流音频相关参数 |
uploadLog | BOOL | 是否上传sdk日志,默认开启 |
syncTimestamp | BOOL | 同步时间戳透传开关,默认关闭,推流类型必须包含视频,同时需要网易云信播放器支持 |
streamTimestampPassthrough | BOOL | 网易云信透传时间戳,但完全透传功能需要联系网易云信开通 |
syncTimestampBaseline | BOOL | 同步时间戳基准:true为从0开始的基准,false为相对机器开机时间基准,默认为true |
privateConfig | BOOL | 私有化配置开关,默认关闭 |
统计信息参数说明LSStatisticsObject
参数 | 类型 | 说明 |
---|---|---|
videoSendFrameRate | unsigned int | 视频发送帧率 |
videoSendBitRate | unsigned int | 视频发送码率 |
videoSendWidth | unsigned int | 视频发送分辨率的宽 |
videoSendHeight | unsigned int | 视频发送分辨率的高 |
videoSetFrameRate | unsigned int | 设置的视频帧率 |
videoSetBitRate | unsigned int | 设置的视频码率 |
videoSetWidth | unsigned int | 设置的分辨率宽 |
videoSetHeight | unsigned int | 设置的分辨率高 |
audioSendBitRate | unsigned int | 音频的发送码率 |
videoEncodeTime | unsigned int | 视频编码一帧的时间 |
videoMuxAndSendTime | unsigned int | 视频发送一帧的时间 |
audioEncodeTime | unsigned int | 音频编码一帧的时间 |
audioMuxAndSendTime | unsigned int | 音频发送一帧的时间 |
writeFrameTime | unsigned int | 如果卡顿累积了数据,则上报卡顿的平均耗时;否则上报非卡顿的平均耗时 |
type | LS_QOSLVL_TYPE | 网络状况类型 |
videoSendBufferQueueCount | unsigned int | 视频发送缓存队列当前大小 |
audioSendBufferQueueCount | unsigned int | 音频发送缓存队列当前大小 |
自定义数据对象参数说明LSCustomDataObject
参数 | 类型 | 说明 |
---|---|---|
sendConetnt | NSString | 发送内容:长度控制在1600,默认为空 |
sendInterval | NSInteger | 发送间隔:表示隔interval帧发一帧自定义数据,最大50,默认为0;如果为0,表示逐帧发送;如果是1,表示隔一帧发送一次;如果是5,表示隔5帧发送一次 |
sendTotalCites | NSInteger | 发送总次数:最大500,默认为10 |
枚举值参数介绍
水印位置LSWaterMarkLocation参数说明
参数 | 说明 |
---|---|
LS_WATERMARK_LOCATION_RECT | 由rect的origin定位置 |
LS_WATERMARK_LOCATION_LEFTUP | 左上角 |
LS_WATERMARK_LOCATION_LEFTDOWN | 左下角 |
LS_WATERMARK_LOCATION_RIGHTUP | 右上角 |
LS_WATERMARK_LOCATION_RIGHTDOWN | 右下角 |
LS_WATERMARK_LOCATION_CENTER | 中间 |
滤镜类型LSGpuImageFilterType参数说明
参数 | 说明 |
---|---|
LS_GPUIMAGE_NORMAL | 无滤镜 |
LS_GPUIMAGE_SEPIA | 黑白 |
LS_GPUIMAGE_ZIRAN | 自然 |
LS_GPUIMAGE_MEIYAN1 | 粉嫩 |
LS_GPUIMAGE_MEIYAN2 | 怀旧 |
摄像头采集方向LSCameraOrientation参数说明
参数 | 说明 |
---|---|
LS_CAMERA_ORIENTATION_PORTRAIT | 画面正向垂直 |
LS_CAMERA_ORIENTATION_UPDOWN | 画面倒向 |
LS_CAMERA_ORIENTATION_RIGHT | 画面向右 |
LS_CAMERA_ORIENTATION_LEFT | 画面向左 |
视频分辨率LSVideoStreamingQuality参数说明
参数 | 说明 |
---|---|
LS_VIDEO_QUALITY_LOW | 低清 352*288 |
LS_VIDEO_QUALITY_MEDIUM | 标清 480*360 |
LS_VIDEO_QUALITY_HIGH | 高清 640*480 |
LS_VIDEO_QUALITY_SUPER | 超清 960*540 |
LS_VIDEO_QUALITY_SUPER_HIGH | 超高清 (1280*720) |
摄像头类型LSCameraPosition参数说明
参数 | 说明 |
---|---|
LS_CAMERA_POSITION_BACK | 后置摄像头 |
LS_CAMERA_POSITION_FRONT | 前置摄像头 |
视频显示模式LSVideoRenderScaleMode参数说明
参数 | 说明 |
---|---|
LS_VIDEO_RENDER_MODE_SCALE_NONE | 采集多大分辨率,则显示多大分辨率 |
LS_VIDEO_RENDER_MODE_SCALE_16x9 | 无论采集多大分辨率,显示比例为16:9 |
硬件编码模式LSHardWareEncEnable参数说明
参数 | 说明 |
---|---|
LS_HRD_NO | 音视频都使用软件编码 |
LS_HRD_AUDIO | 音频使用硬件编码,视频使用软件编码 |
LS_HRD_VIDEO | 视频使用硬件编码,音频使用软件编码 |
LS_HRD_AV | 音视频都使用硬件编码 |
推流协议LSOutputFormatType参数说明
参数 | 说明 |
---|---|
LS_OUT_FMT_FLV | flv协议 |
LS_OUT_FMT_RTMP | rtmp协议 |
推流类型LSOutputStreamType参数说明
参数 | 说明 |
---|---|
LS_HAVE_AUDIO | 只推音频 |
LS_HAVE_VIDEO | 只推视频 |
LS_HAVE_AV | 音视频一起推 |
网络等级类型LS_QOSLVL_TYPE参数说明
参数 | 说明 |
---|---|
LS_QOSLVL_HIGH | 网络好 |
LS_QOSLVL_MIDDLE | 网络一般 |
LS_QOSLVL_LOW | 网络差 |
4 如何使用SDK API接口
- 1.首先init初始化推流实例,然后startVideoPreview打开预览界面
- 2.设置直播过程中由于网络引起的直播出错反馈回调onLiveStreamError
- 3.设置统计数据回调onStatisticInfoGot
- 4.start开始直播(可以调用其他API)
- 5.最后先stop停止推流,再unInit反初始化推流实例释放资源
- 说明:init与unInit,start与stop都要保持匹配使用
4.1 创建推流实例
4.1.1 API介绍
SDK在初始化推流阶段,设置推流地址,配置推流参数,创建推流session 提供的接口有三种,您可以根据是否需要定制直播参数而选择
4.1.2 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
4.1.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
liveStreamingURL | NSString | 推流地址 |
videoParaCtx | LSVideoParaCtxConfiguration | 视频参数 |
configuration | LSLiveStreamingParaCtxConfiguration | 音视频参数 |
4.1.4 示例
LSMediaCapture *mediaCapture = [[LSMediaCapture alloc]initLiveStream:url withLivestreamParaCtxConfiguration:streamparaCtx];
4.1.5 特殊说明
由于相关硬件有可能读取失败的情况,导致无法正常使用推流SDK,所以有可能出现初始化失败的情况,因此需要检测是否初始化成功推流实例。
if (mediaCapture == nil) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@"初始化失败" forKey:NSLocalizedDescriptionKey];
NSError *error = [NSError errorWithDomain:@"LSMediaCaptureErrorDomain" code:0 userInfo:userInfo];
}
4.2 销毁推流实例
4.2.1 API介绍
- 反初始化:释放资源
4.2.2 API原型
/**
反初始化:释放资源
*/
-(void)unInitLiveStream
4.2.3 参数说明
无
4.2.4 示例
[mediaCapture unInitLiveStream];
mediaCapture = nil;
4.2.5 特殊说明
建议在调用unInitLiveStream之后,将mediaCapture实例对象置为空,用于完全释放资源
4.3 预览画面操作
4.3.1 API介绍
- 打开、暂停、恢复视频预览
4.3.2 API原型
/**
* 打开视频预览
*
* @param preview 预览窗口
*/
-(void)startVideoPreview:(UIView*)preview
/**
* @warning 暂停视频预览,如果正在直播,则同时关闭视频预览以及视频推流
*
*/
- (void)pauseVideoPreview
/**
* @warning 继续视频预览,如果正在直播,则开始视频推流
*
*/
- (void)resumeVideoPreview
4.3.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
preview | UIView | 需要显示的预览画面 |
4.3.4 示例
[_mediaCapture startVideoPreview:localPreview];
4.3.5 特殊说明
支持直播过程中改变preview的大小
4.4 直播操作
4.4.1 API介绍
- 打开、停止直播
4.4.2 API原型
/**
* 开始直播
*
* @param completionBlock 具体错误信息
*/
- (void)startLiveStream:(void(^)(NSError *error))completionBlock;
/**
* 结束推流
* @warning 只有直播真正开始后,也就是收到LSLiveStreamingStarted消息后,才可以关闭直播,error为nil的时候,说明直播结束,否则直播过程中发生错误
*/
- (void)stopLiveStream:(void(^)(NSError *error))completionBlock;
4.4.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
completionBlock | void(^)(NSError *error) | 开始和停止直播过程中发生的错误回调,nil说明正常 |
4.4.4 示例
[_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.4.5 特殊说明
无
4.5 音视频推流操作
4.5.1 API介绍
- 中断、恢复视频推流
- 中断、恢复音频推流
4.5.2 API原型
/**
* 重启开始视频推流
* @warning 需要先启动推流startLiveStreamWithError,开启音视频推流,才可以中断视频推流,重启视频推流,
*/
- (void)resumeVideoLiveStream;
/**
* 中断视频推流
* @warning 需要先启动推流startLiveStreamWithError,开启音视频推流,才可以中断视频推流,重启视频推流,
*/
- (void)pauseVideoLiveStream;
/**
* 中断音频推流,
* @warning:需要先启动推流startLiveStreamWithError,开启音视频推流,才可以中断音频推流,重启音频推流,
*/
- (BOOL)pauseAudioLiveStream;
/**
* 重启音频推流,
* @warning:需要先启动推流startLiveStreamWithError,开启音视频推流,才可以中断音频推流,重启音频推流,
*/
- (BOOL)resumeAudioLiveStream;
4.5.3 参数说明
无
4.5.4 示例
- (void)videoBtnTapped:(UIButton *)sender {
if (sender.isSelected) {
[_mediaCapture pauseVideoLiveStream];
}else {
[_mediaCapture resumeVideoLiveStream];
}
}
- (void)audioBtnTapped:(UIButton *)sender {
if (sender.isSelected) {
[_mediaCapture pauseAudioLiveStream];
}else {
[_mediaCapture resumeAudioLiveStream];
}
}
4.5.5 特殊说明
这里的暂停音频流是发送静音帧
4.6 MP4录制操作
4.6.1 API介绍
- 开始mp4录制
- 停止mp4录制
4.6.2 API原型
/**
开始录制并保存本地文件(mp4录制)
@param recordFileName 本地录制的文件全路径
@param videoStreamingQuality 需要录制的mp4文件的分辨率,不能大于采集的分辨率
@return 是否成功
*/
- (BOOL)startRecord:(NSString *)recordFileName videoStreamingQuality:(LSVideoStreamingQuality)videoStreamingQuality;
/**
* 停止本地录制
*/
- (BOOL)stopRecord;
4.6.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
recordFileName | NSString | 本地录制的文件全路径 |
videoStreamingQuality | LSVideoStreamingQuality | 录制的mp4文件的分辨率 |
4.6.4 示例
- (void)recordBtnTapped:(UIButton *)sender {
if (sender.isSelected) {
//以开始录制的时间作为时间戳,作为文件名后缀
NSString *fileName = @"/vcloud_";
NSDate *date = [NSDate date];
NSTimeInterval sec = [date timeIntervalSinceNow];
NSDate *currDate = [[NSDate alloc] initWithTimeIntervalSinceNow:sec];
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:@"yyyyMMddHHmmss"];
NSString *dfStr = [df stringFromDate:currDate];
fileName = [fileName stringByAppendingString:dfStr];
fileName = [fileName stringByAppendingString:@".mp4"];
//存储在Documents路径里
NSArray *arr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = arr[0];
NSString *savePath = [documentsPath stringByAppendingString:fileName];
BOOL isStrated = [_mediaCapture startRecord:savePath videoStreamingQuality:paraCtx.videoStreamingQuality];
if (isStrated) {
_isRecording = YES;
}
}else {
BOOL isStoped = [_mediaCapture stopRecord];
if (isStoped) {
_isRecording = NO;
}
}
}
4.6.5 特殊说明
无
4.7 混音相关操作
4.7.1 API介绍
- 开始、结束、中断、恢复伴音文件;
- 设置混音强度
4.7.2 API原型
/**
* 开始播放混音文件
*
* @param musicURL 音频文件地址/文件名
* @param enableLoop 当前音频文件是否单曲循环
*/
- (BOOL)startPlayMusic:(NSString*)musicURL withEnableSignleFileLooped:(BOOL)enableLoop;
/**
* 结束播放混音文件,释放播放文件
*/
- (BOOL)stopPlayMusic;
/**
* 继续播放混音文件
*/
- (BOOL)resumePlayMusic;
/**
* 中断播放混音文件
*/
- (BOOL)pausePlayMusic;
/**
* 设置混音强度
* @param value 混音强度范围【1-10】
*/
- (void)setMixIntensity:(int)value;
4.7.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
musicURL | NSString | 音频文件地址/文件名 |
enableLoop | BOOL | 前音频文件是否单曲循环 |
value | int | 混音强度范围【1-10】 |
4.7.4 示例
switch (item) {
case 0://无伴音
{
[_mediaCapture stopPlayMusic];//关闭音效
}
break;
case 1://伴音1
{
NSString* musicFileURL = [[NSBundle mainBundle]pathForResource:@"lovest" ofType:@"mp3"];
if (musicFileURL == nil) {
NSLog(@"have not found music file");
return;
}
if (![_mediaCapture startPlayMusic:musicFileURL withEnableSignleFileLooped:YES]) {
NSLog(@"播放音乐文件失败");
return;
};
//从itunes music获取本地音乐作为伴音,该代码仅供参考,具体实现要考虑比较多细节
// [self convertMediaPickerController];
}
break;
case 2://伴音2
{
NSString* musicFileURL = [[NSBundle mainBundle]pathForResource:@"lovest" ofType:@"wav"];
if (musicFileURL == nil) {
NSLog(@"have not found music file");
return;
}
if (![_mediaCapture startPlayMusic:musicFileURL withEnableSignleFileLooped:YES]) {
NSLog(@"播放音乐文件失败");
return;
};
}
break;
default:
[_mediaCapture stopPlayMusic];//关闭音效
break;
}
4.7.5 特殊说明
无
4.8 音视频数据操作
4.8.1 API介绍
- 采集的音视频数据回调给用户
- 用户将前处理好的音视频数据塞回给SDK
4.8.2 API原型
/**
采集模块采集的视频数据回调,交由外部进行自定义前处理,处理完后通过externalInputSampleBuffer发送给sdk
*/
@property(nonatomic, copy) void (^externalCaptureSampleBufferCallback)(CMSampleBufferRef sampleBuffer);
/**
将外部前处理之后的视频数据发送给sdk
@param sampleBuffer 视频数据
*/
-(void)externalInputSampleBuffer:(CMSampleBufferRef)sampleBuffer;
/**
* 麦克风采集到的原始裸数据的回调,交由外部进行自定义处理,同步处理
* param rawData 麦克风采集得到的裸数据,PCM格式
*/
@property (nonatomic,copy) void (^externalCaptureAudioRawData)(AudioBufferList *bufferList,NSInteger inNumberFrames);
/**
用户可以通过这个接口,将第三方采集的音频数据送回来,数据的格式要保持不变,由视频云sdk推流出去
@param bufferList 音频数据
@param inNumberFrames frames数据
*/
-(void)externalInputAudioBufferList:(AudioBufferList *)bufferList inNumberFrames:(NSInteger)inNumberFrames;
4.8.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
sampleBuffer | CMSampleBufferRef | 视频帧 |
bufferList | AudioBufferList * | 音频帧 |
inNumberFrames | NSInteger | frames数据 |
4.8.4 示例
_mediaCapture.externalCaptureSampleBufferCallback = ^(CMSampleBufferRef sampleBuffer)
{
//NSLog(@"做一些视频前处理操作");
//然后塞给 推流sdk
[weakSelf.mediaCapture externalInputSampleBuffer:sampleBuffer];
};
_mediaCapture.externalCaptureAudioRawData = ^(AudioBufferList *bufferList,NSInteger inNumberFrames) {
// NSLog(@"做一些音频前处理操作");
//同步操作
if (!weakSelf.soundTouch) {
weakSelf.soundTouch = [[NESoundTouch alloc] initWithSampleRate:streamparaCtx.sLSAudioParaCtx.samplerate pitchSemiTones:8];
}
[weakSelf.soundTouch processSound:bufferList->mBuffers[0].mData number:inNumberFrames];
};
4.8.5 特殊说明
无
4.9 直播前测速操作
4.9.1 API介绍
- 开始测速
- 结束测速
- 测速之前设置测速次数和上传数据大小
4.9.2 API原型
/**
开始测速
*/
-(void)startSpeedCalc:(NSString *)url success:(void(^)(NSMutableArray *array))success fail:(void(^)())fail;
/**
结束测速
*/
-(void)stopSpeedCalc;
/**
测速之前设置测速次数和上传数据大小
@param count 测速次数(默认为1次),测速之后,取平均值返回结果
@param capacity 上传数据大小(仅限于文件上传类型,经测试,NTS2不能超过500k(含500k)),单位是字节,500k=500*1024,默认为499k(控制最大不超过10M)
*/
-(void)setSpeedCacl:(NSInteger)count Capacity:(unsigned long long)capacity;
4.9.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
url | NSString | 测速地址 |
success | void(^)(NSMutableArray *array) | 测速成功返回的结果列表 |
fail | void(^)() | 测速失败错误回调 |
count | NSInteger | 测速次数(默认为1次),测速之后,取平均值返回结果 |
capacity | unsigned long long | 上传数据大小(仅限于文件上传类型,经测试,NTS2不能超过500k(含500k)),单位是字节,500k=500*1024,默认为499k(控制最大不超过10M) |
4.9.4 示例
- (void)startSpeed:(id)sender
{
//测速之前设置测速次数和上传数据大小500k(默认可以不设):接口android之后会统一
[lsMedia setSpeedCacl:1 Capacity:499*1024];
if ([self.urlText length] > 0 && [self.urlText hasPrefix:@"rtmp://"]) {
[lsMedia startSpeedCalc:self.urlText success:^(NSMutableArray *array) {
NSLog(@"\n success!!! \n");
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"测速结果" message:[NSString stringWithFormat:@"%@",array] delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert showAlertWithCompletionHandler:^(NSInteger i) {}];
});
} fail:^{
NSLog(@"failed");
}];
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"推流地址不正确" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert showAlertWithCompletionHandler:^(NSInteger i) {
if (i == 0) {
NSLog(@"推流地址不正确");
}
}];
}
}
- (void)stopSpeed:(id)sender
{
[lsMedia stopSpeedCalc];
}
4.9.5 特殊说明
测速次数不建议超过3次,上传内容不宜过大,否则等待时间太久
4.10 摄像头操作
4.10.1 API介绍
- 闪光灯
- 变焦
- 前后摄像头切换
- 分辨率切换
- 采集方向(帧率、码率)设置
4.10.2 API原型
/**
* flash摄像头
*
* @return 打开或者关闭摄像头flash
*/
@property (nonatomic, assign)BOOL flash;
/**
* 摄像头变焦功能属性:最大拉伸值,系统最大为:videoMaxZoomFactor
* @warning iphone4s以及之前的版本,videoMaxZoomFactor=1;不支持拉伸
*/
@property (nonatomic, assign, readonly) CGFloat maxZoomScale;
/**
* 摄像头变焦功能属性:拉伸值,[1,maxZoomScale]
* @warning iphone4s以及之前的版本,videoMaxZoomFactor=1;不支持拉伸
*/
@property (nonatomic, assign) CGFloat zoomScale;
/**
* 摄像头变焦功能属性:拉伸值变化回调block
*
* 摄像头响应uigesture事件,而改变了拉伸系数反馈
* @warning iphone4s以及之前的版本,videoMaxZoomFactor=1;不支持拉伸
*/
@property (nonatomic,copy) void (^onZoomScaleValueChanged)(CGFloat value);
/**
* 切换前后摄像头
*
* @return 当前摄像头的位置,前或者后
*/
- (LSCameraPosition)switchCamera:(LSSwitchModuleVideoCameraPositionBlock)cameraPostionBlock;
/**
切换分辨率,支持直播过程中切换分辨率,切换分辨率,水印将自动清除,需要外部根据分辨率,再次设置水印大小
@param videoResolution
@param videoResolutionBlock
*/
- (void)switchVideoStreamingQuality:(LSVideoStreamingQuality)videoResolution block:(LSVideoStreamingQualityBlock)videoResolutionBlock;
/**
直播推流之前设置如下参数
@param bitrate 推流码率 default会按照分辨率设置
@param fps 采集帧率 default = 15
@param cameraOrientation 摄像头采集方向(一般不变)
*/
- (void)setBitrate:(int)bitrate
fps:(int)fps
cameraOrientation:(LSCameraOrientation) cameraOrientation;
4.10.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
flash | BOOL | 打开或者关闭摄像头flash |
maxZoomScale | CGFloat | 摄像头变焦功能属性:最大拉伸值,系统最大为:videoMaxZoomFactor |
zoomScale | CGFloat | 摄像头变焦功能属性:拉伸值,[1,maxZoomScale] |
cameraPostionBlock | LSSwitchModuleVideoCameraPositionBlock | 当前摄像头的位置,前或者后 |
videoResolution | LSVideoStreamingQuality | 分辨率 |
videoResolutionBlock | LSVideoStreamingQualityBlock | 切换摄像头回调 |
bitrate | int | 推流码率 |
fps | int | 采集帧率 |
cameraOrientation | LSCameraOrientation | 摄像头采集方向( |
4.10.4 示例
self.trackSliderView = [[NETrackingSliderView alloc] initWithView:paraCtx tag:^(SliderTag tag,CGFloat value) {
if (tag == zoomTag) {
_mediaCapture.zoomScale = value;
}
}];
_isBackCameraPosition = [_mediaCapture switchCamera:^{
NSLog(@"切换摄像头");
}];
[_mediaCapture switchVideoStreamingQuality:quality block:^(LSVideoStreamingQuality quality1) {
[self addWaterMarkLayer:quality1];
[self addDynamicWaterMark:quality1];
}];
4.10.5 特殊说明
无
4.11 镜像相关操作
4.11.1 API介绍
- 切换本地预览镜像
- 切换编码镜像(针对拉流端观众)
4.11.2 API原型
/**
切换本地预览镜像
@return 当前是否镜像
*/
-(BOOL)changeIsFrontPreViewMirrored;
/**
切换编码镜像(针对拉流端观众)
@return 当前是否镜像
*/
-(BOOL)changeIsFrontCodeMirrored;
4.11.3 参数说明
无
4.11.4 示例
-(void)onActionPreviewMirror:(id)sender{
[_mediaCapture changeIsFrontPreViewMirrored];
}
-(void)onActionCodeMirror:(id)sender{
[_mediaCapture changeIsFrontCodeMirrored];
}
4.11.5 特殊说明
无
4.12 滤视频截图操作
4.12.1 API介绍
- 获取视频截图
4.12.2 API原型
/**
* 获取视频截图,
*
* @param LSFrameCaptureCompletionBlock 获取最新一幅视频图像的回调
*
*/
- (void)snapShotWithCompletionBlock:(LSFrameCaptureCompletionBlock)completionBlock;
4.12.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
completionBlock | LSFrameCaptureCompletionBlock | 获取最新一幅视频图像的回调 |
4.12.4 示例
__weak MediaCaptureViewController *weakSelf = self;
[weakSelf.mediaCapture snapShotWithCompletionBlock:^(UIImage *latestFrameImage) {
UIImageWriteToSavedPhotosAlbum(latestFrameImage, weakSelf, nil, nil);
}];
4.12.5 特殊说明
无
4.13 滤镜相关操作
4.13.1 API介绍
- 设置滤镜类型
- 设置磨皮强度
- 设置美白强度
- 调节曝光度
4.13.2 API原型
/**
* 设置滤镜类型
*
* @param filterType 滤镜类型,目前支持4种滤镜,参考 LSGpuImageFilterType 描述
*
*/
- (void)setFilterType:(LSGpuImageFilterType)filterType;
/**
设置磨皮强度【0-1】
@param value 值
*/
- (void)setSmoothFilterIntensity:(float)value;
/**
设置美白强度【0-1】
@param value 值
*/
- (void)setWhiteningFilterIntensity:(float)value;
/**
调节曝光度(-10.0 - 10.0 ,默认为0.0)
@param exposure 曝光度
*/
-(void)adjustExposure:(CGFloat)exposure;
4.13.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
filterType | LSGpuImageFilterType | 滤镜类型 |
value | float | 磨皮强度【0-1】 |
value | float | 美白强度【0-1】 |
exposure | CGFloat | 曝光度(-10.0 - 10.0 ,默认为0.0) |
4.13.4 示例
[_mediaCapture setFilterType:(LSGpuImageFilterType)type];
self.trackSliderView = [[NETrackingSliderView alloc] initWithView:paraCtx tag:^(SliderTag tag,CGFloat value) {
if (tag == zoomTag) {
_mediaCapture.zoomScale = value;
}else if (tag == ContrastTag){
[_mediaCapture setSmoothFilterIntensity:value];
}else if (tag == WhiteTag){
[_mediaCapture setWhiteningFilterIntensity:value];
}else{
[_mediaCapture adjustExposure:value];
}
}];
4.13.5 特殊说明
无
4.14 水印相关操作
4.14.1 API介绍
- 添加涂鸦
- 添加静态视频水印
- 关闭本地预览静态水印
- 添加动态视频水印
- 关闭本地预览动态水印
- 清除水印
4.14.2 API原型
/**
添加涂鸦
@param image 涂鸦静态图像
@param rect 具体位置和大小(x,y根据location位置,计算具体的位置信息)
@param location 位置
*/
- (void)addGraffiti:(UIImage*)image
rect:(CGRect)rect
location:(LSWaterMarkLocation)location;
/**
添加静态视频水印
@param image 静态图像
@param rect 具体位置和大小(x,y根据location位置,计算具体的位置信息)
@param location 位置
*/
- (void) addWaterMark: (UIImage*) image
rect: (CGRect) rect
location: (LSWaterMarkLocation) location;
/**
关闭本地预览静态水印
*/
- (void)closePreviewWaterMark:(BOOL)isClosed;
/**
添加动态视频水印
@param imageArray 动态图像数组
@param count 播放速度的快慢:count代表count帧显示同一张图
@param looped 是否循环,不循环就显示一次
@param rect 具体位置和大小(x,y根据location位置,计算具体的位置信息)
@param location 位置
*/
- (void) addDynamicWaterMarks: (NSArray*) imageArray
fpsCount: (unsigned int)count
loop: (BOOL)looped
rect: (CGRect) rect
location: (LSWaterMarkLocation) location;
/**
关闭本地预览动态水印
*/
- (void)closePreviewDynamicWaterMark:(BOOL)isClosed;
/**
清除水印
*/
- (void)cleanWaterMark;
4.14.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
image | UIImage | 图像 |
rect | CGRect | 具体位置和大小(x,y根据location位置,计算具体的位置信息) |
location | LSWaterMarkLocation | 位置 |
isClosed | BOOL | 关闭水印 |
imageArray | NSArray | 动态图像数组 |
count | unsigned int | 放速度的快慢:count代表count帧显示同一张图 |
looped | BOOL | 是否循环,不循环就显示一次 |
4.14.4 示例
- (void)addWaterMarkLayer:(LSVideoStreamingQuality)quality {
CGRect rect = CGRectZero;
//自行根据产品定水印在不同分辨率下的大小
switch (quality) {
case LS_VIDEO_QUALITY_LOW:
rect = CGRectMake(10, 10, 100*0.7*0.7*0.7, 54*0.7*0.7*0.7);
break;
case LS_VIDEO_QUALITY_MEDIUM:
rect = CGRectMake(10, 10, 100*0.7*0.7, 54*0.7*0.7);
break;
case LS_VIDEO_QUALITY_HIGH:
rect = CGRectMake(10, 10, 100*0.7, 54*0.7);
break;
case LS_VIDEO_QUALITY_SUPER:
rect = CGRectMake(10, 10, 100, 54);
break;
default:
rect = CGRectMake(10, 10, 100, 54);
break;
}
//添加静态水印
UIImage* image = [UIImage imageNamed:[[[NSBundle mainBundle] bundlePath]stringByAppendingPathComponent:@"logo.png"]];
[_mediaCapture addWaterMark:image rect:rect location:LS_WATERMARK_LOCATION_RIGHTUP];
}
- (void)addDynamicWaterMark:(LSVideoStreamingQuality)quality {
CGRect rect = CGRectZero;
//自行根据产品定水印在不同分辨率下的大小
switch (quality) {
case LS_VIDEO_QUALITY_LOW:
rect = CGRectMake(10, 10, 220*0.7*0.7*0.7, 80*0.7*0.7*0.7);
break;
case LS_VIDEO_QUALITY_MEDIUM:
rect = CGRectMake(10, 10, 220*0.7*0.7, 80*0.7*0.7);
break;
case LS_VIDEO_QUALITY_HIGH:
rect = CGRectMake(10, 10, 220*0.7, 80*0.7);
break;
case LS_VIDEO_QUALITY_SUPER:
rect = CGRectMake(10, 10, 220, 80);
break;
default:
rect = CGRectMake(10, 10, 220, 80);
break;
}
//屏蔽动态水印oppo广告
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = 0; i < 23; i++) {
NSString *str = [NSString stringWithFormat:@"water%@.png",[NSString stringWithFormat:@"%ld",(long)i]];
UIImage* image = [UIImage imageNamed:[[[NSBundle mainBundle] bundlePath]stringByAppendingPathComponent:str]];
[array addObject:image];
}
//图片数量少时,建议2帧一次显示,图片多时,建议1帧一次显示
[_mediaCapture addDynamicWaterMarks:array
fpsCount:2
loop:YES
rect:rect
location:LS_WATERMARK_LOCATION_RIGHTDOWN];
}
switch (item) {
case 0://无水印
paraCtx.isVideoWaterMarkEnabled = NO;
[_mediaCapture cleanWaterMark];
break;
case 1://静态水印
{
paraCtx.isVideoWaterMarkEnabled = YES;
[_mediaCapture cleanWaterMark];
[self addWaterMarkLayer:paraCtx.videoStreamingQuality];
}
break;
case 2:
{
paraCtx.isVideoWaterMarkEnabled = YES;
[_mediaCapture cleanWaterMark];
[self addDynamicWaterMark:paraCtx.videoStreamingQuality];
}
break;
default:
break;
}
4.14.5 特殊说明
无
4.15 直播辅助操作
4.15.1 API介绍
- 直播过程中发生错误的回调函数
- 得到直播过程中的统计信息
- 更新自定义统计数据
- 检查是否正在直播
- 设置日志的level
- 获取当前sdk的版本号
4.15.2 API原型
/**
* 直播过程中发生错误的回调函数
*
* @param error 具体错误信息
*/
@property (nonatomic,copy) void (^onLiveStreamError)(NSError *error);
/**
* 得到直播过程中的统计信息
*
* @param statistics 统计信息结构体
*
*/
@property (nonatomic,copy) void (^onStatisticInfoGot)(LSStatisticsObject* statistics);
/**
更新自定义统计数据
@param customDict 自定义统计数据(key,value)
*/
- (void)updateCutomStatistics:(NSDictionary *)customDict;
/**
检查是否正在直播
@return bool值
*/
- (BOOL)checkIsLiving;
/**
* 设置trace 的level
*
* @param loglevl trace 信息的级别
*/
- (void)setTraceLevel:(LSMediaLog)logLevel;
/**
* 获取当前sdk的版本号
*
*/
+ (NSString*) getSDKVersionID;
4.15.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
customDict | NSDictionary | 自定义统计数据(key,value) |
logLevel | LSMediaLog | 信息的级别 |
4.15.4 示例
_mediaCapture.onLiveStreamError = ^(NSError* error){
if (error != nil) {
[weakSelf LiveStreamErrorInterrup];
}
[weakSelf.selectView.startBtn setBackgroundImage:[UIImage imageNamed:@"restart"] forState:UIControlStateNormal];
};
_mediaCapture.onStatisticInfoGot = ^(LSStatisticsObject* statistics){
if (statistics != nil) {
dispatch_async(dispatch_get_main_queue(),^(void){[weakSelf showStatInfo:statistics];});
}
};
[LSMediaCapture getSDKVersionID];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"1111" forKey:@"uid"];
[dict setObject:@"2222" forKey:@"appKey"];
[_mediaCapture updateCutomStatistics:dict];
4.15.5 特殊说明
无
5 代码示例
- 必须 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;
}
- 必须 初始化推流对象
LSVideoParaCtxConfiguration *paraCtx = [LSVideoParaCtxConfiguration defaultVideoConfiguration:LSVideoParamQuality_Super];//直播推流参数
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.isFrontCameraMirroredPreView = YES; //是否镜像前置摄像头预览
paraCtx.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资源释放,重新从初始化推流
开始。
6 Demo接入Faceunity
- Faceunity的github地址:https://github.com/Faceunity/FULiveDemo
- Demo 已集成Faceunity相关功能,假设你需要在demo中演示相关功能,需要打开demo中的开关,并向Faceunity或者网易云信视频索要具体的证书秘要。
- 具体的操作如下图:
- 打开demo开关:
- 填写具体的证书秘要:
7 API说明
有关API的详细说明,可参见SDK包中docs,打开index.html查看,或者打开下面的在线文档。
网易云信视频直播推流LiveStreaming iOS SDK API详细文档