Android直播推流SDK开发集成
1 概述
1.1 SDK简介
1.1.1 SDK业务简介
网易云信直播源自网易多年视频技术沉淀,基于专业的跨平台视频编解码技术和大规模视频内容分发网络,提供稳定流畅、低延时、高并发的直播服务。
网易云信直播推流SDK,用于支持在直播流程中,采集摄像头或自定义音视频数据,进行视频前处理,并进行编码推流到服务器。具有稳定、高效、功能全面的特点。
1.1.2 SDK技术简介
直播推流 SDK 由如下图所示的结构组成。 其中,实线框是直播的主要模块,包括音视频采集、处理、编码和打包发送。虚线框是辅助模块,关闭后不影响直播功能。
网络信息统计功能帮助开发者实现网络状况的实时监测,尤其在弱网络环境下,能够快速准确的探知网络可用带宽等信息,帮助开发者调整产品策略,改善产品的用户体验。
1.2 设备和系统要求:
- 支持Android 4.3及以上系统
1.3 功能特性
- 支持推流到主流 RTMP 服务器
- 支持 H.264 和 AAC 编码
- 支持纯音频或者纯视频推流
- 支持直播中伴音
- 支持直播中单独暂停音频或者视频
- 支持MP4录制
- 支持显示推流统计信息
- 支持自定义YUV、PCM输入
- 支持YUV、PCM回调
- 支持直播前测速
- 支持音视频采集,编码,打包,传输
- 支持 armv7、arm64 架构
- 资源占用率低,库文件小
- 画质清晰,延时低
- 支持闪光灯开启操作(Flash)
- 支持摄像头缩放操作(Zoom)
- 支持前后置摄像头动态切换
- 支持分辨率动态切换
- 支持自动对焦
- 支持视频本地预览镜像操作(主播)
- 支持视频编码镜像操作(观众)
- 支持视频截图
- 支持怀旧、干净、自然、健康、复古等多款滤镜
- 支持磨皮强度调节
- 支持美白强度调节
- 支持曝光度调节
- 支持添加静态水印
- 支持添加动态水印
- 支持添加动态涂鸦
- 支持关闭本地预览静态水印
- 支持关闭本地预览动态水印
- 支持清除水印
- 支持视频流中带入时间戳(直播答题方案能力支持)
- 支持时间戳透传设置开关以及获取当前音视频时间戳的接口
2 开发准备
2.1 准备工作
2.2 集成SDK
本文是根据官网的直播推流 Demo 来介绍 SDK 的集成,可在网易云信官网下载最新的直播推流 Android Demo,来查看更多的实现细节。
2.2.1 组件及资源
开发者需要将直播推流 SDK 集成到应用中,包括静态库文件和相关的头文件。如下图所示:
直播推流 SDK 包含 demo、libs、docs 三个部分,在网易云信视频官网可以下载 Demo 和 SDK 包。
-
demo部分: 里面包含一个示例工程,实现了音视频直播推流功能,有完整的源代码。
-
docs目录: 包括 Livestreaming.jar 依赖包的 javadoc 文档,该文档详细说明了播放器 SDK 各接口 API 类的用法。
-
lib目录: 存放推流 SDK 的 Java 依赖包和底层动态链接库(支持armeabi-v7a、arm64-v8a平台架构),文件列表如下:
objclibs
├── armeabi-v7a
│ ├── liblivestreaming.so
│ ├── libvideoeffect.so
├── arm64-v8a
│ ├── liblivestreaming.so
│ ├── libvideoeffect.so
│
├── VideoEffect-x.x.x.jar (采集以及滤镜Java层代码)
└── Livestreaming-x.x.x.jar (编码推流Java层代码)
- assets/filter目录: 存放滤镜资源文件,包括healthy_mask_1.jpg、filter_map_first.png 等图片文件
将这些文件拷贝到你的工程的对应目录下,同时将 Livestreaming-x.x.x.jar、VideoEffect-x.x.x.jar 加入工程,即可完成配置。
库文件介绍
库 | 说明 |
---|---|
Livestreaming-x.x.x.jar | 直播API封装综合jar库 |
liblivestreaming.so | 编码以及发送相关的so库 |
VideoEffect-x.x.x.jar | 视频融合模块库(视频采集 、视频前处理 ) |
libvideoeffect.so | 滤镜等前处理so库 |
assets/filter | 滤镜依赖资源图片 |
2.2.2 快速集成
-
解压下载的直播推流 SDK 开发包,将jar包so动态库以及滤镜文件都导入工程。具体导入方式,请参考以下的具体说明:
-
SDK包含三部分,一部分是jar包,另一部分是so动态库,最后是滤镜相关的资源图片。其中jar包必须依赖,so动态库分为armeabi-v7a、arm64-v8a两个架构,用户可以根据自身APP支持的架构进行选择,还有一部分assets/filter下的滤镜文件,如果用户需要用到SDK自带的滤镜则必须加入,如不需要可以不添加。
-
具体到工程中的配置可以参考如下SDK demo工程的配置
- 红色框:是Demo依赖SDK的 JAR 文件
- 绿色框:是Demo的Java代码部分
- 橙色框:是Demo依赖SDK的动态链接库文件。目前SDK支持主流的ARMv7a, ARM64v8a芯片体系架构
- 蓝色框:是Demo的布局文件
- 配置AndroidManifest.xml AndroidManifest.xml需要配置直播相关的权限
objc<!-- 权限声明 -->
<!-- 允许挂载和反挂载文件系统 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 允许程序向外部存储设备写数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 允许程序打开网络套接字 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许程序获取网络相关信息 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 允许程序向外部存储设备写数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 允许程序写音频数据 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 允许程序使用PowerManager WakeLocks以防止处理器休眠或者屏幕锁屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 允许程序获取Wifi网络状态信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许程序使用设备的camera -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 允许程序使用闪光灯 -->
<uses-permission android:name="android.permission.FLASHLIGHT" />
<!-- 允许程序获得设备信息 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<!-- 声明程序使用camera和自动对焦功能 -->
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
- 代码混淆配置 为了保证正常使用SDK,请在proguard-project.txt文件中添加以下代码:
objc-keep class com.netease.LSMediaCapture.**{*;}
-keep class com.netease.vcloud.**{*;}
3 API概览
类别 | API名称 | 功能 |
---|---|---|
创建推流实例 | - lsMediaCapture(LsMediaCapturePara lsMediaCapturePara) | 根据LsMediaCapturePara设置SDK上下文Context以及消息回调 |
销毁推流实例 | - (void)uninitLsMediaCapture(boolean uninitNow) | 反初始化:释放资源;true:马上释放,false:等待推流结束后释放。(如推流已开始必须设置为false) |
打开视频预览 | - (void)startVideoPreview | 打开摄像头进行预览,采用SDK提供的超清、高清、标清等模式进行预览 |
打开视频预览(扩展) | - (void)startVideoPreviewEx | 预览扩展接口,如果SDK提供的模板不满足,用户可以自定义设置预览的分辨率以及帧率等参数 |
打开屏幕共享预览 | - (void)startScreenCapture | 打开屏幕共享预览,采用MediaProjection 实现屏幕捕捉 |
切换分辨率 | - (void)changeCaptureFormat | 切换SDK支持的模板分辨率 |
切换分辨率(扩展) | - (void)changeCaptureFormatEx | 切换用户自定义分辨率 |
关闭视频预览 | - (void)stopVideoPreview | 关闭摄像头 |
销毁视频预览 | - (void)destroyVideoPreview | 释放摄像头以及预览显示View等资源 |
初始化推流 | - (boolean)initLiveStream | 设置推流地址以及推流类型等参数 |
开始推流 | - (void)startLiveStreaming | 开始推流,若失败,会在创建实例中的消息回调中返回具体错误码 |
结束推流 | - (void)stopLiveStreaming | 结束推流 |
暂停视频推流 | - (void)pauseVideoLiveStream | 暂停视频推流,不发送视频数据 |
恢复视频推流 | - (void)resumeVideoLiveStream | 恢复视频推流 |
暂停音频推流 | - (void)pauseAudioLiveStream | 暂停音频推流,发送静音数据 |
恢复音频推流 | - (void)resumeAudioLiveStream | 恢复音频推流 |
视频切后台 | - (void)backgroundVideoEncode | 视频推流切换到后台的处理,关闭相机,发送最后一帧画面 |
视频恢复前台 | - (void)resumeVideoEncode | 重新打开相机并推送视频数据 |
音频切后台 | - (void)backgroundAudioEncode | 发送静音帧 |
音频恢复前台 | - (void)resumeAudioEncode | 重新发送音频 |
开始伴音 | - (boolean)startPlayMusic | 支持是否循环播放 |
暂停伴音 | - (boolean)pausePlayMusic | 暂停伴音 |
恢复播放 | - (boolean)resumePlayMusic | 恢复伴音 |
结束伴音 | - (boolean)stopPlayMusic | 结束伴音 |
摄像头切换 | - (void)switchCamera | 前后摄像头动态切换 |
闪光灯开关 | - (void)setCameraFlashPara | 开关闪光灯(若支持) |
摄像头缩放 | - (void)setCameraZoomPara | 设置摄像头缩放比例 |
摄像头曝光度 | - (void)setExposureCompensation | 设置摄像头曝光强度 |
摄像头对焦 | - (void)setCameraFocus | 设置摄像头全屏对焦 |
摄像头自动对焦 | - (void) setCameraAutoFocus | true:自动对焦,false:手动对焦,默认自动对焦 |
横竖屏切换 | - (void)onConfigurationChanged | 通知SDK发送了横竖屏切换,SDK重新计算宽高 |
设置水印 | - (void)setWaterMarkPara | 设置水印,一般用作视频版权logo显示 |
水印是否本地显示 | - (void)setWaterPreview | 设置水印是否本地显示(主播端),默认显示 |
动态水印 | - (void)setDynamicWaterMarkPara | 动态水印,一般用作视频中广告显示 |
动态水印是否本地显示 | - (void)setDynamicWaterPreview | 设置动态水印是否本地显示(主播端),默认显示 |
设置涂鸦 | - (void)setGraffitiPara | 涂鸦,可以中推流过程中实时变化 |
涂鸦是否本地显示 | - (void)setGraffitiPreview | 设置涂鸦是否本地显示(主播端),默认显示 |
摄像头采集数据回调 | - (void)setCaptureRawDataCB | 用于用户集成第三方美颜滤镜使用,SDK已在该接口上创建了openGLContext |
post到openGL线程 | - (void)postOnGLThread | 用于第三方滤镜的部分必须在openGL线程上调用的接口使用 |
麦克风采集数据回调 | - (void)setAudioRawDataCB | 用于用户进行降噪等音频处理 |
设置数据源类型 | - (void)setSourceType | SDK:SDK负责采集 CustomMode:用户自定义采集 |
自定义YUV数据 | - (void)sendCustomYUVData | SDK支持用户自行采集摄像头等设备的YUV输入给SDK进行发送 |
自定义PCM数据 | - (void)sendCustomPCMData | SDK支持用户自行采集麦克风等设备的PCM输入给SDK进行发送 |
设置观众端镜像 | - (void)setVideoMirror | 直播过程中,开关观众端镜像效果(只对前置摄像头有效) |
设置主播端镜像 | - (void)setPreviewMirror | 直播过程中,开关主播端镜像效果(只对前置摄像头有效) |
设置滤镜类型 | - (void)setFilterType | 干净、自然、健康、复古等滤镜 |
设置滤镜强度 | - (void)setFilterStrength | (0 - 1) |
设置磨皮强度 | - (void)setBeautyLevel | (0 - 5) |
截图 | - (void)enableScreenShot | 对当前预览画面进行截图 |
开始测速 | - (void)startSpeedCalc | 支持直播开始前测速,选择最优链路推流 |
结束测速 | - (void)stopSpeedCalc | 结束此次测速 |
发送自定义数据 | - (int)sendCustomData | 数据随视频画面一起发送 |
总体参数介绍
SDK实例参数介绍
SDK实例参数说明LsMediaCapturePara
参数 | 类型 | 说明 |
---|---|---|
setContext | Context | 设置SDK上下文,建议使用ApplicationContext |
setMessageHandler | lsMessageHandler | 设置SDK消息回调接口 |
setLogLevel | lsLogUtil.LogLevel | 设置日志级别(info、warn、error) |
setUploadLog | boolean | 设置是否上传日志 |
初始化推流参数说明LiveStreamingPara
参数 | 类型 | 说明 |
---|---|---|
setStreamType | StreamType | AUDIO:但音频,VIDEO:单视频,AV:音视频双流 |
setFormatType | FormatType | MP4:MP4纯录制,RTMP:RTMP 推流,RTMP_AND_MP4:边推RTMP 边录制MP4 |
setRecordPath | String | 设置本地录制地址,FormatType为MP4或RTMP_AND_MP4有效 |
setQosOn | boolean | true:开启 false:关闭,默认开启Qos |
setAutoRecord | boolean | 当formatType为MP4或RTMP_AND_MP4是否推流开始就自动开始录制,默认自动在上述两种模式下推流一开始就录制,只有需要推流与录制不同时进行的用户才需要关心,正常情况下,用户无需关心 |
setSyncTimestamp(syncTimestamp,absoluteTime) | boolean | syncTimestamp true:发送同步时间戳 false:不发送,默认不发送。 absoluteTime true:绝对时间(unix时间),false:相对于推流的时间(从0开始) |
setStreamTimestampPassthrough | boolean | true:网易云信透传时间戳 false:不透传,默认不透传 |
预览频参数说明
参数 | 类型 | 说明 |
---|---|---|
videoView | NeteaseView | SDK提供的预览显示View,用户可以布局到自己的APP中 |
frontCamera | boolean | 是否默认前置摄像头 |
filter | boolean | 是否使用SDK内置滤镜 |
quality | VideoQuality | MEDIUM:标清 480360,HIGH:高清 640480,SUPER:超清 960540,SUPER_HIGH:超高清 1280720 |
scale_16x9 | boolean | 是否按16:9宽高比例 |
统计信息参数说明Statistics
参数 | 类型 | 说明 |
---|---|---|
videoRealSendBitRate | int | 视频发送码率 |
audioRealSendBitRate | int | 音频发送码率 |
videoEncodeFrameRate | int | 视频编码帧率 |
videoEncodeBitRate | int | 视频编码码率 |
videoEncodeWidth | int | 视频编码宽 |
videoEncodeHeight | int | 视频编码码高 |
videoEncodeTime | int | 视频编码一帧的时间 |
audioEncodeBitRate | int | 音频编码码率 |
videoSetBitRate | int | 设置的视频码率 |
videoSetWidth | int | 设置的分辨率宽 |
videoSetHeight | int | 设置的分辨率高 |
networkLevel | int | 网络状况 1: 好,2:一般,3:差,4:未知 |
videoSendBufferQueueCount | int | 视频发送缓存队列当前大小 |
枚举值参数介绍
推流类型StreamType参数说明
参数 | 说明 |
---|---|
AUDIO | 单音频 |
VIDEO | 单视频 |
AV | 音视频双流 |
推流模式FormatType参数说明
参数 | 说明 |
---|---|
MP4 | MP4纯录制 |
RTMP | RTMP 推流 |
RTMP_AND_MP4 | 边推RTMP 边录制MP4 |
输入源SourceType参数说明
参数 | 说明 |
---|---|
SDK | SDK负责采集 |
CustomAV | 自定义采集音视频 |
CustomAudio | 自定义采集音频 |
CustomVideo | 自定义采集视频 |
视频分辨率VideoQuality参数说明
参数 | 说明 |
---|---|
MEDIUM | 标清 480*360 |
HIGH | 高清 640*480 |
SUPER | 超清 960*540 |
SUPER_HIGH | 超高清 1280*720 |
水印位置VideoEffect.Rect参数说明
参数 | 说明 |
---|---|
leftTop | 左上角 |
leftBottom | 左下角 |
rightTop | 右上角 |
rightBottom | 右下角 |
center | 中间 |
滤镜类型VideoEffect.FilterType参数说明
参数 | 说明 |
---|---|
none | 无滤镜 |
clean | 干净 |
fairytale | 童话 |
nature | 自然 |
healthy | 健康 |
tender | 温柔 |
whiten | 美白 |
SDK消息回调具体状态码
objcpublic static final int MSG_INIT_LIVESTREAMING_ERROR = 0;//初始化直播出错
public static final int MSG_INIT_LIVESTREAMING_VIDEO_ERROR = 1; //初始化视频直播出错
public static final int MSG_INIT_LIVESTREAMING_AUDIO_ERROR = 2; //初始化音频直播出错
public static final int MSG_START_LIVESTREAMING_ERROR = 3;//开始直播出错
public static final int MSG_STOP_LIVESTREAMING_ERROR = 4;//停止直播出错
public static final int MSG_AUDIO_PROCESS_ERROR = 5;//音频编码打包出错
public static final int MSG_VIDEO_PROCESS_ERROR = 6; //视频编码打包出错
public static final int MSG_START_PREVIEW_ERROR = 7;//打开视频预览失败
public static final int MSG_RTMP_URL_ERROR = 8; //RTMP URL连接出错,会进一步调用网络信息报警service,弹出悬浮窗
public static final int MSG_URL_NOT_AUTH = 9; //RTMP URL非法
public static final int MSG_SEND_STATICS_LOG_ERROR = 10; //发送统计日志出错
public static final int MSG_SEND_HEARTBEAT_LOG_ERROR = 11;//发送心跳日志出错
public static final int MSG_AUDIO_RECORD_ERROR = 12;//音频录制权限打开失败
public static final int MSG_AUDIO_SAMPLE_RATE_NOT_SUPPORT_ERROR = 13;//设置的音频采样率不支持
public static final int MSG_AUDIO_PARAMETER_NOT_SUPPORT_BY_HARDWARE_ERROR = 14;//设置的音频硬件编码参数不支持
public static final int MSG_NEW_AUDIORECORD_INSTANCE_ERROR = 15;//音频采集实例创建失败
public static final int MSG_AUDIO_START_RECORDING_ERROR = 16;//音频采集失败
public static final int MSG_QOS_TO_STOP_LIVESTREAMING = 17;//网络QoS较差
public static final int MSG_HW_VIDEO_PACKET_ERROR = 18; //视频硬件编码出错
public static final int MSG_WATERMARK_INIT_ERROR = 19; //视频水印初始化出错
public static final int MSG_WATERMARK_PIC_OUT_OF_VIDEO_ERROR = 20; //视频水印超出原始视频
public static final int MSG_WATERMARK_PARA_ERROR = 21; //视频水印参数出错
public static final int MSG_CAMERA_PREVIEW_SIZE_NOT_SUPPORT_ERROR = 22; //摄像头不支持设置的preview size
public static final int MSG_START_PREVIEW_FINISHED = 23; //开始preview完成
public static final int MSG_START_LIVESTREAMING_FINISHED = 24; //开始直播完成
public static final int MSG_STOP_LIVESTREAMING_FINISHED = 25; //停止直播完成
public static final int MSG_STOP_VIDEO_CAPTURE_FINISHED = 26; //停止视频采集完成
public static final int MSG_STOP_AUDIO_CAPTURE_FINISHED = 28; //停止音频采集完成
public static final int MSG_SWITCH_CAMERA_FINISHED = 30; //切换摄像头完毕
public static final int MSG_SEND_STATICS_LOG_FINISHED = 31; //发送统计信息完毕
public static final int MSG_SERVER_COMMAND_STOP_LIVESTREAMING = 32; //服务器下发停止直播的命令
public static final int MSG_SEND_HEARTBEAT_LOG_FINISHED = 33; //发送心跳信息完毕
public static final int MSG_CAMERA_NOT_SUPPORT_FLASH = 34; //用户所设置的采集分辨率,摄像头并不支持
public static final int MSG_GET_STATICS_INFO = 35; //获得统计信息完毕
public static final int MSG_BAD_NETWORK_DETECT = 36; //连续一分钟视频帧率和码率都是0的消息
public static final int MSG_SCREENSHOT_FINISHED = 37; //直播中视频截图完成消息
public static final int MSG_SET_CAMERA_ID_ERROR = 38; //设置camera id出错(单摄像头设备常见)
public static final int MSG_SET_GRAFFITI_ERROR = 39; //设置视频涂鸦出错
public static final int MSG_MIX_AUDIO_FINISHED = 40: //伴音一首MP3文件结束
public static final int MSG_URL_FORMAT_NOT_RIGHT = 41: //推流URL格式不正确(例如使用拉流url进行推流)
public static final int MSG_URL_IS_EMPTY = 42: //推流URL为空
public static final int MSG_VIDEO_CROP_ERROR = 43; //视频剪裁失败
public static final int MSG_SPEED_CALC_SUCCESS = 44; //测速成功
public static final int MSG_SPEED_CALC_FAIL = 45; //测速失败
同时,需要开发者继承如下接口,处理SDK抛出的事件。
objchandleMessage(int msg, Object object);
4 如何使用SDK API接口
- 1.首先new lsMediaCapture创建推流实例
- 2.调用startVideoPreview打开预览界面
- 3.initLiveStream初始化推流地址
- 4.startLiveStreaming开始推流,之后可以调用其他推流过程中的API
- 5.最后先stopLiveStreaming停止推流,再unInit反初始化推流实例释放资源
- 说明:init与unInit,start与stop都要保持匹配使用
特别说明:如要断线重连,需先调用stopLiveStreaming,等待接受到SDK回调消息 MSG_STOP_LIVESTREAMING_FINISHED之后才能继续调用initLiveStream、startLiveStreaming重新开始推流
4.1 创建推流实例
4.1.1 API介绍
SDK在初始化推流阶段,设置推流地址,配置推流参数,创建推流session,您可以根据是否需要定制直播参数而选择
4.1.2 API原型
- 创建直播实例
objc/**
* 初始化推流实例
* @param lsMediaCapturePara {@link LsMediaCapturePara }初始化参数类型
*/
public lsMediaCapture(LsMediaCapturePara lsMediaCapturePara)
4.1.3 LsMediaCapturePara参数说明
参数 | 类型 | 说明 |
---|---|---|
setContext | Context | 设置SDK上下文,建议使用ApplicationContext |
setMessageHandler | lsMessageHandler | 设置SDK消息回调接口 |
setLogLevel | lsLogUtil.LogLevel | 设置日志级别(info、warn、error) |
setUploadLog | boolean | 设置是否上传日志 |
4.1.4 示例
objc
lsMediaCapture.LsMediaCapturePara lsMediaCapturePara = new lsMediaCapture.LsMediaCapturePara();
lsMediaCapturePara.setContext(getApplicationContext()); //设置SDK上下文(建议使用ApplicationContext)
lsMediaCapturePara.setMessageHandler(this); //设置SDK消息回调
lsMediaCapturePara.setLogLevel(lsLogUtil.LogLevel.INFO); //日志级别
lsMediaCapturePara.setUploadLog(publishParam.uploadLog);//是否上传SDK日志
mLSMediaCapture = new lsMediaCapture(lsMediaCapturePara);
4.2 打开预览画面
4.2.1 API介绍
- 设置摄像头预览参数,并打开摄像头进行预览。提供两种方式:SDK模板预览,用户自定义预览
4.2.2 API原型
objc/**
* 打开视频预览
* @param videoView {@link com.netease.vcloud.video.render.NeteaseView}
* @param frontCamera 是否前置摄像头
* @param filter 是否开启滤镜
* @param quality 视频能力
* @param scale_16x9 是否强制 16:9 模式
*
*/
public void startVideoPreview(NeteaseView videoView,boolean frontCamera,boolean filter,VideoQuality quality,boolean scale_16x9)
objc/**
* 打开视频预览
* @param videoView {@link com.netease.vcloud.video.render.NeteaseView}
* @param frontCamera 是否前置摄像头
* @param filter 是否开启滤镜
* @param para 视频采集以及编码的参数
*/
public void startVideoPreviewEx(NeteaseView videoView,boolean frontCamera,boolean filter,VideoPara para)
4.2.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
videoView | NeteaseView | SDK提供的预览显示View,用户可以布局到自己的APP中 |
frontCamera | boolean | 是否默认前置摄像头 |
filter | boolean | 是否使用SDK内置滤镜 |
quality | VideoQuality | MEDIUM:标清 480360,HIGH:高清 640480,SUPER:超清 960540,SUPER_HIGH:超高清 1280720 |
scale_16x9 | boolean | 是否按16:9宽高比例 |
VideoPara参数说明
参数 | 类型 | 说明 |
---|---|---|
setWidth | int | 设置编码宽 |
setHeight | int | 设置编码高 |
setFps | int | 设置编码帧率 |
setBitrate | int | 设置编码码率 |
4.2.4 示例
objcNeteaseView videoView = (NeteaseView) findViewById(R.id.videoview);
boolean frontCamera = publishParam.frontCamera; // 是否前置摄像头
boolean mScale_16x9 = publishParam.isScale_16x9; //是否强制16:9
lsMediaCapture.VideoQuality videoQuality = publishParam.videoQuality; //视频模板(SUPER_HIGH 1280*720、SUPER 960*540、HIGH 640*480、MEDIUM 480*360、LOW 352*288)
mLSMediaCapture.startVideoPreview(videoView,frontCamera,mUseFilter,videoQuality,mScale_16x9);
// SDK 默认提供 /** 标清 480*360 */MEDIUM, /** 高清 640*480 */HIGH,
// /** 超清 960*540 */SUPER,/** 超高清 (1280*720) */SUPER_HIGH 四个模板,
// 用户如果需要自定义分辨率可以调用startVideoPreviewEx 接口并参考以下参数
// 码率计算公式为 width * height * fps * 9 /100;
// lsMediaCapture.VideoPara para = new lsMediaCapture.VideoPara();
// para.setHeight(720);
// para.setWidth(1280);
// para.setFps(15);
// para.setBitrate(1200*1024);
// mLSMediaCapture.startVideoPreviewEx(videoView,frontCamera,mUseFilter,para);
4.2.5 特殊说明
调用startPreview之后,需要检查SDK回调信息,如果返回MSG_START_PREVIEW_ERROR,则说明打开摄像头失败,建议提示用户检查权限
4.3 开始推流
4.3.1 API介绍
- 初始化推流参数,开始推流
4.3.2 API原型
objc/**
* 初始化推流所需信息
*
* @param paraCtx 推流参数
* @param pushUrl 推流地址
* @return 初始化推流是否成功:true/false
*/
public boolean initLiveStream(LiveStreamingPara paraCtx,String pushUrl)
objc/**
* 开始直播
*
*/
public void startLiveStreaming()
4.3.3 参数说明
初始化推流参数说明LiveStreamingPara
参数 | 类型 | 说明 |
---|---|---|
setStreamType | StreamType | AUDIO:但音频,VIDEO:单视频,AV:音视频双流 |
setFormatType | FormatType | MP4:MP4纯录制,RTMP:RTMP 推流,RTMP_AND_MP4:边推RTMP 边录制MP4 |
setRecordPath | String | 设置本地录制地址,FormatType为MP4或RTMP_AND_MP4有效 |
setQosOn | boolean | true:开启 false:关闭,默认开启Qos |
setAutoRecord | boolean | 当formatType为MP4或RTMP_AND_MP4是否推流开始就自动开始录制,默认自动在上述两种模式下推流一开始就录制,只有需要推流与录制不同时进行的用户才需要关心,正常情况下,用户无需关心 |
setSyncTimestamp(syncTimestamp,absoluteTime) | boolean | syncTimestamp true:发送同步时间戳 false:不发送,默认不发送。 absoluteTime true:绝对时间(unix时间),false:相对于推流的时间(从0开始) |
setStreamTimestampPassthrough | boolean | true:网易云信透传时间戳 false:不透传,默认不透传 |
4.3.4 示例
objcmLiveStreamingPara = new lsMediaCapture.LiveStreamingPara();
mLiveStreamingPara.setStreamType(publishParam.streamType); // 推流类型 AV、AUDIO、VIDEO
mLiveStreamingPara.setFormatType(publishParam.formatType); // 推流格式 RTMP、MP4、RTMP_AND_MP4
mLiveStreamingPara.setRecordPath(publishParam.recordPath);//formatType 为 MP4 或 RTMP_AND_MP4 时有效
mLiveStreamingPara.setQosOn(publishParam.qosEnable);
//mLiveStreamingPara.setSyncTimestamp(true,false);//(直播答题使用)网易云信透传时间戳,不依赖CDN方式,不需要额外开通(必须包含视频流)
//mLiveStreamingPara.setStreamTimestampPassthrough(true); //(直播答题使用)网易云信透传时间戳,但完全透传功能需要联系网易云信开通,支持纯音频
mLSMediaCapture.initLiveStream(mLiveStreamingPara,mliveStreamingURL);
mLSMediaCapture.startLiveStreaming();
4.3.5 特殊说明
调用initLiveStream、startLiveStream之后,需要检查SDK回调信息,如果返回MSG_START_LIVESTREAMING_FINISHED,则说明成功开始推流,如果返回MSG_INIT_LIVESTREAMING_OUTFILE_ERROR、MSG_INIT_LIVESTREAMING_VIDEO_ERROR、MSG_INIT_LIVESTREAMING_AUDIO_ERROR则说明推流失败,用户需要检查推流地址是否有效或者被禁用
4.4 结束推流
4.4.1 API介绍
- 结束推流,释放相机等资源
4.4.2 API原型
objc/**
* 结束推流
*
*/
public void stopLiveStreaming()
objc/**
* 销毁视频预览实例
*/
public void destroyVideoPreview()
objc/**
* 关闭视频预览
*/
public void stopVideoPreview()
objc/**
* 反初始化推流实例
* @param uninitNow 立即反初始化实例的标记
*/
public void uninitLsMediaCapture(boolean uninitNow)
4.4.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
uninitNow | boolean | true:马上释放,false:等待推流结束后释放。(如推流已开始必须设置为false) |
4.4.4 示例
objcmLSMediaCapture.stopLiveStreaming();
mLSMediaCapture.stopVideoPreview();
mLSMediaCapture.destroyVideoPreview();
//反初始化推流实例,当它与stopLiveStreaming连续调用时,参数为false
mLSMediaCapture.uninitLsMediaCapture(false);
4.4.5 特殊说明
uninitLsMediaCapture与stopLiveStreaming连续调用时,参数必须为false,用于SDK异步结束推流释放资源。 如果用户已先调用了stopLiveStreaming,并且等到了MSG_STOP_LIVESTREAMING_FINISHED消息,那可以直接设置为true
自此一个简单的直播推流流程就结束了,用户需要一些高级的操作,可以继续参考以下的API介绍
4.5 音视频推流操作
4.5.1 API介绍
- 中断、恢复视频推流
- 中断、恢复音频推流
4.5.2 API原型
objc/**
* 暂停视频推流
*/
public void pauseVideoLiveStream()
objc/**
* 继续视频推流
*/
public void resumeVideoLiveStream()
objc/**
* 暂停音频推流
*/
public void pauseAudioLiveStream()
objc/**
* 继续音频推流
*/
public void resumeAudioLiveStream()
objc/**
* 程序切后台后继续视频编码,编码最后一帧图像
*/
public void backgroundVideoEncode()
java/**
* 设置垫片(图片),支持以bitmap作为参数,用于替代当前推流内容
* @param bitmap 垫片图,占位图,如果传`null`同`backgroundVideoEncode()`方法
*/
public void backgroundVideoEncode(Bitmap bitmap)
objc/**
* 程序切回前台后恢复视频编码
*/
public void resumeVideoEncode()
objc/**
* 程序切后台后继续音频编码,编码静音帧
*/
public void backgroundAudioEncode()
objc/**
* 程序切回前台后恢复音频编码
*/
public void resumeAudioEncode()
4.5.3 参数说明
无
4.5.4 示例
objc@Override
protected void onPause(){
Log.i(TAG,"Activity onPause");
if(mLSMediaCapture != null) {
if(!m_tryToStopLivestreaming && m_liveStreamingOn)
{
if(mLiveStreamingPara.getStreamType() != AUDIO) {
//推最后一帧图像
mLSMediaCapture.backgroundVideoEncode();
}
else {
//推静音帧
mLSMediaCapture.backgroundAudioEncode();
}
}
}
super.onPause();
}
objc@Override
protected void onResume(){
Log.i(TAG,"Activity onResume");
super.onResume();
if(mLSMediaCapture != null && m_liveStreamingOn) {
if(mLiveStreamingPara.getStreamType() != AUDIO) {
//关闭推流固定图像,正常推流
mLSMediaCapture.resumeVideoEncode();
}
else {
//关闭推流静音帧
mLSMediaCapture.resumeAudioEncode();
}
}
}
4.5.5 特殊说明
这里的暂停与切后台的差别是,暂停不会关闭摄像头只是不继续推流本地预览还在,切后台则会释放摄像头资源并发送最后一帧画面。同时暂停音频流是发送静音帧
4.6 伴音相关操作
4.6.1 API介绍
- 开始、结束、中断、恢复伴音文件;
4.6.2 API原型
objc/**
* 开始播放伴音文件
* @param musicURL 音频文件地址/文件名
* @param loop 是否循环播放
* @return 播放伴音文件成功或者失败
*/
public boolean startPlayMusic(String musicURL,boolean loop)
objc /**
* 结束播放伴音文件,释放播放文件
* @return 停止伴音成功或者失败
*/
public boolean stopPlayMusic()
objc/**
* 暂停播放伴音文件
*
* @return 暂停播放伴音文件成功或者失败
*/
public boolean pausePlayMusic()
objc/**
* 继续播放伴音文件
*
* @return 继续伴音成功或者失败
*/
public boolean resumePlayMusic()
4.7.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
musicURL | String | 音频文件地址 |
loop | boolean | 伴音音频文件是否单曲循环 |
4.7.4 示例
objc//伴音开关的控制
if(audioMixMsg == 1)
{
if(mMixAudioFilePath.isEmpty())
return;
if(mLSMediaCapture != null) {
mLSMediaCapture.startPlayMusic(mMixAudioFilePath,false);
}
}
else if (audioMixMsg == 2)
{
if(mLSMediaCapture != null){
mLSMediaCapture.resumePlayMusic();
}
}
else if(audioMixMsg == 3)
{
if(mLSMediaCapture != null){
mLSMediaCapture.pausePlayMusic();
}
}
else if(audioMixMsg == 4)
{
if(mLSMediaCapture != null){
mLSMediaCapture.stopPlayMusic();
}
}
4.6.5 特殊说明
无
4.7 音视频数据操作
4.7.1 API介绍
- SDK将摄像头或麦克风采集的原始音视频数据回调给用户,用户进行前处理后返还给SDK
- 用户自行进行音视频的采集,然后将采集的音视频数据用SDK进行编码发送
4.7.2 API原型
objc/**
* 设置摄像头采集原始数据回调
* @param callback 裸流回调接口(NV21格式)
*/
public void setCaptureRawDataCB(VideoCallback callback)
objc/**
* 设置麦克风采集原始数据回调
* @param callback 裸流回调接口(PCM格式)
*/
public void setAudioRawDataCB(lsAudioCaptureCallback callback)
objc/**
* 自定义采集的YUV数据(该接口不需要调用 {@link #startVideoPreview})
* @param buffer YUV数据
* @param videoWidth 视频原始宽
* @param videoHeight 视频原始高
* @param bitrate 编码码率
* @param framerate 编码帧率
*/
public void sendCustomYUVData(byte[] buffer,int videoWidth,int videoHeight,int bitrate, int framerate)
objc/**
* 自定义采集的PCM数据
* @param buffer PCM数据
*/
public void sendCustomPCMData(byte[] buffer)
4.7.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
callback | VideoCallback | 视频回调函数 |
callback | lsAudioCaptureCallback | 音频回调函数 |
buffer | byte[] | 视频数据(YUV I420格式) |
videoWidth | int | 视频宽 |
videoHeight | int | 视频高 |
bitrate | int | 视频码率 |
framerate | int | 视频帧率 |
buffer | byte[] | 音频数据(PCM) |
4.7.4 示例
objc//********** 摄像头采集原始数据回调(非滤镜模式下开发者可以修改该数据,美颜增加滤镜等,推出的流便随之发生变化) *************//
if(mVideoCallback){
senseEffect();
mLSMediaCapture.setCaptureRawDataCB(new VideoCallback() {
@Override
/**
* 摄像头采集数据回调
* @param data 摄像头采集的原始数据(NV21格式)
* @param textureId 摄像头采集的纹理ID
* @param width 视频宽
* @param height 视频高
* @param orientation 相机采集角度
* @return 滤镜后的纹理ID (<=0 表示没有进行滤镜或是滤镜库返回的是buffer数据(NV21格式),sdk将会使用buffer数据进行后续处理)
*/
public int onVideoCapture(byte[] data, int textureId, int width, int height, int orientation) {
if(mSenseEffect != null){
//返回纹理方式
return mSenseEffect.effect(textureId,data,width,height,orientation);
}else {
//返回buffer方式
for(int j = 0; j< width * height /4;j++){
data[j] = 0; //data必须还是原来的NV21格式
}
return 0;
}
}
});
}
objc//********** 麦克风采集原始数据回调(开发者可以修改该数据,进行降噪、回音消除等,推出的流便随之发生变化) *************//
if(mAudioCallback){
mLSMediaCapture.setAudioRawDataCB(new lsAudioCaptureCallback() {
int i = 0;
@Override
public void onAudioCapture(byte[] data, int len) {
// 这里将data直接修改,SDK根据修改后的data数据直接推流
if(i % 10 == 0){
for(int j = 0; j< 1000;j++){
data[j] = 0;
}
}
i++;
}
});
}
objc//【示例代码】设置自定义视频采集类型(如果是自定义YUV则不需要调用startVideoPreview接口)
mLSMediaCapture.setSourceType(lsMediaCapture.SourceType.CustomAV);
//自定义输入默认是横屏,正的yuv数据
//【示例代码 customVideo】设置自定义视频采集逻辑 (自定义视频采集逻辑不要调用startPreview,也不用初始化surfaceView)
new Thread() { //视频采集线程
@Override
public void run() {
while (true) {
try {
if(!m_liveStreamingOn){
continue;
}
int width = 352;
int height = 288;
int fps = 20;
int bitrate = width * height * fps * 9 /100;
FileInputStream in = new FileInputStream(String.format(Locale.getDefault(),"/sdcard/dump_%d_%d.yuv",width,height));
int len = width * height * 3 / 2;
byte buffer[] = new byte[len];
int count;
while ((count = in.read(buffer)) != -1) {
if (len == count) {
mLSMediaCapture.sendCustomYUVData(buffer,width,height,bitrate,fps);
} else {
break;
}
sleep(50, 0);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
//【示例代码】结束
//【示例代码2】设置自定义音频采集逻辑(音频采样位宽必须是16)
new Thread() { //音频采集线程
@Override
public void run() {
while (true) {
try {
if(!m_liveStreamingOn){
continue;
}
FileInputStream in = new FileInputStream("/sdcard/dump.pcm");
int len = 2048;
byte buffer[] = new byte[len];
int count;
while ((count = in.read(buffer)) != -1) {
if (len == count) {
mLSMediaCapture.sendCustomPCMData(buffer);
} else {
break;
}
sleep(20, 0);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
//【示例代码】结束
4.7.5 特殊说明
无
4.8 直播前测速操作
4.8.1 API介绍
- 开始测速
- 结束测速
4.8.2 API原型
objc/**
* 开始测速
* @param url 推流地址
* @param bytes 测速文件大小
*/
public void startSpeedCalc(String url, long bytes)
objc/**
* 停止测速
*/
public void stopSpeedCalc()
4.8.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
url | String | 测速地址 |
bytes | long | 上传数据大小(仅限于文件上传类型,经测试,NTS2不能超过500k(含500k)),单位是字节,500k=500*1024,默认为499k(控制最大不超过10M |
4.8.4 示例
objcif(mLSMediaCapture != null) {
if (mSpeedCalcRunning) {
mLSMediaCapture.stopSpeedCalc();
mSpeedCalcRunning = false;
showToast("结束测速");
} else {
showToast("开始测速");
mLSMediaCapture.startSpeedCalc(mliveStreamingURL, 1024 * 500);
mSpeedCalcRunning = true;
}
}
4.8.5 特殊说明
无
4.9 摄像头操作
4.9.1 API介绍
- 闪光灯
- 变焦
- 对焦
- 前后摄像头切换
- 分辨率切换
- 曝光度设置
4.9.2 API原型
objc/**
* 设置闪光灯开关
* @param onFlash 闪光灯开关
*/
public void setCameraFlashPara(boolean onFlash)
objc/**
* 获取当前视频缩放比例
* @return 当前视频缩放比例
*/
public int getCameraZoomValue()
objc/**
* 获取摄像头支持的最大视频缩放比例
* @return 摄像头支持的最大视频缩放比例
*/
public int getCameraMaxZoomValue()
objc/**
* 设置视频缩放相关参数
* @param zoomValue 缩放参数
*/
public void setCameraZoomPara(int zoomValue)
objc /**
* 手动对焦一次
*/
public void setCameraFocus()
objc/**
* 设置是否自动对焦(自动对焦默认开启)
* @param isAutoFocus true:开启自动对焦 false:关闭自动对焦
*/
public void setCameraAutoFocus(boolean isAutoFocus)
objc/**
* 切换前后摄像头
*/
public void switchCamera()
objc/**
* 获取摄像头曝光强度
* @return 摄像头曝光强度
*/
public int getExposureCompensation()
objc/**
* 获取摄像头支持的最小曝光强度
* @return 摄像头支持的最小曝光强度
*/
public int getMinExposureCompensation()
objc/**
* 获取摄像头支持的最大曝光强度
* @return 摄像头支持的最大曝光强度
*/
public int getMaxExposureCompensation()
objc/**
* 设置摄像头曝光强度
* @param value 摄像头曝光强度 (根据获取的最大和最小曝光度进行设置)
*/
public void setExposureCompensation(int value)
objc/**
* 切换分辨率
* @param quality 需要切换的模板
* @param scale_16x9 是否16:9
*/
public void changeCaptureFormat(VideoQuality quality,boolean scale_16x9)
objc/**
* 切换分辨率
* @param videoPara 自定义分辨率
*/
public void changeCaptureFormatEx(lsMediaCapture.VideoPara videoPara)
4.9.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
onFlash | boolean | 打开或者关闭摄像头flash |
zoomValue | int | 摄像头变焦功能属性:拉伸值,[1,maxZoomScale] |
isAutoFocus | boolean | true:开启自动对焦 false:关闭自动对焦 |
value | int | 曝光度 [MinExposureCompensation,MaxExposureCompensation] |
quality | VideoQuality | MEDIUM:标清 480360,HIGH:高清 640480,SUPER:超清 960540,SUPER_HIGH:超高清 1280720 |
scale_16x9 | boolean | 是否按16:9宽高比例 |
VideoPara参数说明
参数 | 类型 | 说明 |
---|---|---|
setWidth | int | 设置编码宽 |
setHeight | int | 设置编码高 |
setFps | int | 设置编码帧率 |
setBitrate | int | 设置编码码率 |
4.9.4 示例
objc//闪光灯
if(mLSMediaCapture != null){
mFlashOn = !mFlashOn;
mLSMediaCapture.setCameraFlashPara(mFlashOn);
if(mFlashOn){
flashBtn.setImageResource(R.drawable.flashstop);
}else {
flashBtn.setImageResource(R.drawable.flashstart);
}
}
objc//曝光度
if(mLSMediaCapture != null){
int max = mLSMediaCapture.getMaxExposureCompensation();
mLSMediaCapture.setExposureCompensation((progress-50) * max /50);
}
objc//切换分辨率
private void changeFormat(){
int index = count % 4;
count ++ ;
boolean is16x9 = true;
switch (index){
case 0:
mLSMediaCapture.changeCaptureFormat(lsMediaCapture.VideoQuality.SUPER_HIGH,is16x9);
break;
case 1:
mLSMediaCapture.changeCaptureFormat(lsMediaCapture.VideoQuality.SUPER,is16x9);
break;
case 2:
mLSMediaCapture.changeCaptureFormat(lsMediaCapture.VideoQuality.HIGH,is16x9);
break;
case 3:
mLSMediaCapture.changeCaptureFormat(lsMediaCapture.VideoQuality.MEDIUM,is16x9);
break;
}
}
4.9.5 特殊说明
无
4.10 镜像相关操作
4.10.1 API介绍
- 切换本地预览镜像
- 切换编码镜像(针对拉流端观众)
4.10.2 API原型
objc/**
* 直播过程中,开关本地预览镜像效果(只对前置摄像头有效)
* @param mirror 是否镜像
*/
public void setPreviewMirror(boolean mirror)
objc/**
* 直播过程中,开关视频推流镜像效果(只对前置摄像头有效)
* @param mirror 是否镜像(观众端)
*/
public void setVideoMirror(boolean mirror)
4.10.3 参数说明
无
4.10.4 示例
objcif(mLSMediaCapture != null){
mLSMediaCapture.setVideoMirror(R.id.live_config_push_mirror_on == checkedId);
}
objcif(mLSMediaCapture != null){
mLSMediaCapture.setWaterPreview(R.id.live_config_water_on == checkedId);
}
4.10.5 特殊说明
无
4.11 视频截图操作
4.11.1 API介绍
- 获取视频截图
4.11.2 API原型
objc/**
* 直播过程中,开启截图
*/
public void enableScreenShot()
4.11.3 参数说明
无
4.11.4 示例
objcprivate void capture(){
if(mLSMediaCapture != null){
mLSMediaCapture.enableScreenShot();
}
}
case MSG_SCREENSHOT_FINISHED://视频截图完成后的消息反馈
{
getScreenShotByteBuffer((Bitmap) object);
break;
}
4.11.5 特殊说明
截图在SDK消息回调中返回,为bitmap类型
4.12 滤镜相关操作
4.12.1 API介绍
- 设置滤镜类型
- 设置磨皮强度
- 设置美白强度
4.12.2 API原型
objc /**
* 设置滤镜类型
* @param filterType 滤镜类型
*/
public void setFilterType(VideoEffect.FilterType filterType)
objc /**
* 设置滤镜强度
* @param filterStrength 滤镜强度 (0 - 1)
*/
public void setFilterStrength(float filterStrength)
objc/**
* 设置磨皮强度
* @param level 磨皮强度 (0 - 5)
*/
public void setBeautyLevel(int level)
4.12.3 参数说明
滤镜类型VideoEffect.FilterType参数说明
参数 | 说明 | |
---|---|---|
none | 无滤镜 | |
clean | 干净 | |
fairytale | 童话 | |
nature | 自然 | |
healthy | 健康 | |
tender | 温柔 | |
whiten | 美白 | |
参数 | 类型 | 说明 |
:-------- | :-------- | :-------- |
filterStrength | float | 滤镜强度 (0 - 1) |
level | int | 磨皮强度 (0 - 5) |
4.12.4 示例
objcswitch (v.getId()){
case R.id.brooklyn:
mLSMediaCapture.setFilterType(VideoEffect.FilterType.brooklyn);
break;
case R.id.clean:
mLSMediaCapture.setFilterType(VideoEffect.FilterType.clean);
break;
case R.id.nature:
mLSMediaCapture.setFilterType(VideoEffect.FilterType.nature);
break;
case R.id.healthy:
mLSMediaCapture.setFilterType(VideoEffect.FilterType.healthy);
break;
case R.id.pixar:
mLSMediaCapture.setFilterType(VideoEffect.FilterType.pixar);
break;
case R.id.tender:
mLSMediaCapture.setFilterType(VideoEffect.FilterType.tender);
break;
case R.id.whiten:
mLSMediaCapture.setFilterType(VideoEffect.FilterType.whiten);
break;
default:
break;
}
objc//滤镜强度
if(mLSMediaCapture != null){
float param;
param = (float)progress/100;
mLSMediaCapture.setFilterStrength(param);
}
//磨皮强度
if(mLSMediaCapture != null){
int param;
param = progress/20;
mLSMediaCapture.setBeautyLevel(param);
}
4.12.5 特殊说明
无
4.13 水印相关操作
4.13.1 API介绍
- 添加涂鸦
- 开关本地预览涂鸦
- 添加静态视频水印
- 开关本地预览静态水印
- 添加动态视频水印
- 开关本地预览动态水印
4.13.2 API原型
objc/**
* 设置涂鸦
* @param bitmap 涂鸦图片
* @param x 水印水平坐标X,整个图像左上角为(0,0)点
* @param y 水印垂直坐标Y,整个图像左上角为(0,0)点
*/
public void setGraffitiPara(Bitmap bitmap, int x, int y)
objc/**
* 是否显示本地涂鸦
* @param preview true:本地显示 false: 本地不显示
*/
public void setGraffitiPreview(boolean preview)
objc/**
* 设置视频水印相关参数
* @param bitmap 水印文件
* @param rect 水印具体位置(上下左右中四个基本位置)
* @param x 距离 rect 的 x 坐标
* @param y 距离 rect 的 y 坐标
*/
public void setWaterMarkPara(Bitmap bitmap, VideoEffect.Rect rect, int x, int y)
objc/**
* 是否显示本地水印
* @param preview true:本地显示 false: 本地不显示
*/
public void setWaterPreview(boolean preview)
objc/**
* 设置视频动态水印相关参数
* @param bitmapArray 水印图片数组
* @param rect 水印具体位置(上下左右中四个基本位置)
* @param x 距离 rect 的 x 坐标
* @param y 距离 rect 的 y 坐标
* @param fps 动态水印的叠加帧率
* @param looped 动态水印是否循环叠加的标志
*/
public void setDynamicWaterMarkPara(Bitmap[] bitmapArray, VideoEffect.Rect rect,int x, int y, int fps, boolean looped)
objc/**
* 是否显示本地动态水印
* @param preview true:本地显示 false: 本地不显示
*/
public void setDynamicWaterPreview(boolean preview)
4.13.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
bitmap | Bitmap | 图像 |
rect | VideoEffect.Rect | 上下左右中四个基本位置 |
x | int | 距离 rect 的 水平坐标 |
y | int | 距离 rect 的 垂直坐标 |
fps | int | 动态水印的叠加帧率 |
looped | int | 动态水印是否循环叠加的标志 |
4.13.4 示例
objcprivate void addWaterMark(){
if(mLSMediaCapture != null){
Bitmap water = BitmapFactory.decodeResource(getResources(),R.drawable.water);
int x = 120;
int y = 60;
mLSMediaCapture.setWaterMarkPara(water, VideoEffect.Rect.leftTop,x,y);
}
}
objcBitmap[] bitmaps;
private void addDynamicWaterMark(){
if(mLSMediaCapture != null){
int x = 0;
int y = 0;
int fps = 1; //水印的帧率
boolean looped = true; //是否循环
String[] waters;
try {
waters = getAssets().list("dynamicWaterMark");
bitmaps = new Bitmap[waters.length];
for(int i = 0; i< waters.length;i++){
waters[i] = "dynamicWaterMark/" + waters[i];
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap tmp = BitmapFactory.decodeStream(getAssets().open(waters[i]));
bitmaps[i] = tmp;
}
mLSMediaCapture.setDynamicWaterMarkPara(bitmaps,VideoEffect.Rect.center,x,y,fps,looped);
} catch (IOException e) {
e.printStackTrace();
}
}
}
objcprivate Thread mGraffitiThread;
private boolean mGraffitiOn = false;
private void addGraffiti(){
if(mGraffitiThread != null){
return;
}
mGraffitiOn = true;
mGraffitiThread = new Thread(){
@Override
public void run() {
int x = 180;
int y = 180;
while (mGraffitiOn && bitmaps != null && mLSMediaCapture != null){
for(Bitmap bitmap:bitmaps){
if(!mGraffitiOn){
break;
}
SystemClock.sleep(1000);
if(mLSMediaCapture != null){
mLSMediaCapture.setGraffitiPara(bitmap,x,y);
}
}
}
}
};
mGraffitiThread.start();
}
4.13.5 特殊说明
无
4.14 直播辅助操作
4.14.1 API介绍
- 直播过程中发生错误的回调函数
- 得到直播过程中的统计信息
- 更新自定义统计数据
- 设置日志的level
- 获取当前sdk的版本号
- 获取当前同步时间戳(与setSyncTimestamp配合使用)
- 获取当前透传时间戳(与setStreamTimestampPassthrough 配合使用)
- 在码率中发送自定义数据
4.14.2 API原型
objclsMediaCapture.LsMediaCapturePara lsMediaCapturePara = new lsMediaCapture.LsMediaCapturePara();
lsMediaCapturePara.setMessageHandler(this); //设置SDK消息回调
objccase MSG_GET_STATICS_INFO://获取统计信息的反馈消息
{
Message message = Message.obtain(mHandler, MSG_GET_STATICS_INFO);
Statistics statistics = (Statistics) object;
Bundle bundle = new Bundle();
bundle.putInt("FR", statistics.videoEncodeFrameRate);
bundle.putInt("VBR", statistics.videoRealSendBitRate);
bundle.putInt("ABR", statistics.audioRealSendBitRate);
bundle.putInt("TBR", statistics.totalRealSendBitRate);
bundle.putInt("networkLevel", statistics.networkLevel);
bundle.putString("resolution", statistics.videoEncodeWidth + " x " + statistics.videoEncodeHeight);
message.setData(bundle);
if(mHandler != null) {
mHandler.sendMessage(message);
}
break;
}
objc/**
* 更新自定义统计数据
* @param jsonObject 自定义统计数据
*/
public void updateCustomStatistics(JSONObject jsonObject)
objclsMediaCapturePara.setLogLevel(lsLogUtil.LogLevel.INFO); //日志级别
objc/**
* 获取SDK版本号
* @return SDK版本号
*/
public String getSDKVersion()
objc/**
* 获取当前推流时间戳,对应 setSyncTimestamp
* @return 当前推流的时间戳(毫秒)
*/
public long currentSyncTimestamp()
objc/**
* 获取当前时间戳,对应setStreamTimestampPassthrough 一起使用
* @return 当前同步时间戳(毫秒)
*/
public long currentStreamTimestamp()
objc/**
* 在码流中发送自定义数据
* @param customData 数据内容
* @return 0:发送成功,1: 参数长度和值域校验失败,2: 超过并发数限制(5个)
*/
public int sendCustomData(CustomData customData)
4.14.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
jsonObject | JSONObject | 自定义统计数据(key,value) |
logLevel | lsLogUtil.LogLevel | 信息的级别 |
4.14.4 示例
objctry {
JSONObject jsonObject = new JSONObject();
jsonObject.put("appkey","1111");
jsonObject.put("uid","2222");
mLSMediaCapture.updateCustomStatistics(jsonObject);
}catch (Exception e){
e.printStackTrace();
}
4.14.5 特殊说明
无
4.15 屏幕共享
4.15.1 API介绍
- 屏幕共享预览,使用
MediaProjection
实现屏幕共享,与摄像头预览对应,需要调用stopVideoPreview()
方法结束屏幕共享预览
4.15.2 API原型
java/**
* 打开视频预览
* @param quality 视频能力
* @param mediaProjectionPermissionResultData MediaProjection权限申请成功后获得的intent
* @param quality 视频能力
* @param scale_16x9 是否强制 16:9 模式
*
*/
public void startScreenCapture(NeteaseView videoView, Intent mediaProjectionPermissionResultData, VideoQuality quality, boolean scale_16x9);
4.15.3 参数说明
参数 | 类型 | 说明 |
---|---|---|
videoView | NeteaseView | SDK提供的预览显示View,用户可以布局到自己的APP中,也支持传null 适应屏幕共享无预览场景 |
mediaProjectionPermissionResultData | Intent | MediaProjection权限申请成功后获得的intent |
quality | VideoQuality | MEDIUM:标清 480360,HIGH:高清 640480,SUPER:超清 960540,SUPER_HIGH:超高清 1280720 |
scale_16x9 | boolean | 是否按16:9宽高比例 |
4.15.4 示例
java// 在某Activity中
private static final int CAPTURE_PERMISSION_REQUEST_CODE = 11;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_capture);
// 申请屏幕捕捉
requestScreenCapturer(CAPTURE_PERMISSION_REQUEST_CODE);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected void requestScreenCapturer(int requestCode) {
// Toast.makeText(this, "5.0 以上系统才能支持录屏", Toast.LENGTH_LONG).show();
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, requestCode);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAPTURE_PERMISSION_REQUEST_CODE) {
if (resultCode != Activity.RESULT_OK || data == null) {
showToastErr("你拒绝了录屏请求");
return;
}
NeteaseView neteaseView = (NeteaseView) findViewById(R.id.videoview);
startScreenCapture(neteaseView, data);
}
}
// sdk接口调用
void startScreenCapture(NeteaseView neteaseView, Intent data) {
boolean mScale_16x9 = mPublishParam.isScale_16x9; //是否强制16:9
// 视频模板(SUPER_HIGH 1280*720、SUPER 960*540、HIGH 640*480、MEDIUM 480*360、LOW 352*288)
lsMediaCapture.VideoQuality videoQuality = mPublishParam.videoQuality;
mLSMediaCapture.startScreenCapture(neteaseView, data, videoQuality, mScale_16x9);
}
4.15.5 特殊说明
- 调用
startScreenCapture
之后,需要检查SDK回调信息,如果返回MSG_START_PREVIEW_ERROR,则说明打开屏幕共享失败 - 由于
MediaProjection
限制,此接口仅支持Android 5.0
及以上设备
5 代码示例
- 必须 SDK涉及到麦克风,摄像头的采集,需要事先打开使用权限,申请权限代码如下。
objc/** 6.0权限处理 **/
private boolean bPermission = false;
private final int WRITE_PERMISSION_REQ_CODE = 100;
private boolean checkPublishPermission() {
if (Build.VERSION.SDK_INT >= 23) {
List<String> permissions = new ArrayList<>();
if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(ConfigActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(ConfigActivity.this, Manifest.permission.CAMERA)) {
permissions.add(Manifest.permission.CAMERA);
}
if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(ConfigActivity.this, Manifest.permission.RECORD_AUDIO)) {
permissions.add(Manifest.permission.RECORD_AUDIO);
}
if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(ConfigActivity.this, Manifest.permission.READ_PHONE_STATE)) {
permissions.add(Manifest.permission.READ_PHONE_STATE);
}
if (permissions.size() != 0) {
ActivityCompat.requestPermissions(ConfigActivity.this,
(String[]) permissions.toArray(new String[0]),
WRITE_PERMISSION_REQ_CODE);
return false;
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case WRITE_PERMISSION_REQ_CODE:
for (int ret : grantResults) {
if (ret != PackageManager.PERMISSION_GRANTED) {
return;
}
}
bPermission = true;
break;
default:
break;
}
}
- 必须 一次推流过程
objc//以下为SDK调用主要步骤,请用户参考使用
//1、创建直播实例
lsMediaCapture.LsMediaCapturePara lsMediaCapturePara = new lsMediaCapture.LsMediaCapturePara();
lsMediaCapturePara.setContext(getApplicationContext()); //设置SDK上下文(建议使用ApplicationContext)
lsMediaCapturePara.setMessageHandler(this); //设置SDK消息回调
lsMediaCapturePara.setLogLevel(lsLogUtil.LogLevel.INFO); //日志级别
lsMediaCapturePara.setUploadLog(publishParam.uploadLog);//是否上传SDK日志
mLSMediaCapture = new lsMediaCapture(lsMediaCapturePara);
//2、设置直播参数
mLiveStreamingPara = new lsMediaCapture.LiveStreamingPara();
mLiveStreamingPara.setStreamType(publishParam.streamType); // 推流类型 AV、AUDIO、VIDEO
mLiveStreamingPara.setFormatType(publishParam.formatType); // 推流格式 RTMP、MP4、RTMP_AND_MP4
mLiveStreamingPara.setRecordPath(publishParam.recordPath);//formatType 为 MP4 或 RTMP_AND_MP4 时有效
mLiveStreamingPara.setQosOn(publishParam.qosEnable);
mLiveStreamingPara.setQosEncodeMode(publishParam.qosEncodeMode); //1:流畅优先, 2:清晰优先 默认流畅优先
//3、 预览参数设置
NeteaseView videoView = (NeteaseView) findViewById(R.id.videoview);
boolean frontCamera = publishParam.frontCamera; // 是否前置摄像头
boolean mScale_16x9 = publishParam.isScale_16x9; //是否强制16:9
if(publishParam.streamType != AUDIO){ //开启预览画面
lsMediaCapture.VideoQuality videoQuality = publishParam.videoQuality; //视频模板(SUPER_HIGH 1280*720、SUPER 960*540、HIGH 640*480、MEDIUM 480*360、LOW 352*288)
mLSMediaCapture.startVideoPreview(videoView,frontCamera,mUseFilter,videoQuality,mScale_16x9);
}
m_startVideoCamera = true;
if(mUseFilter){ //demo中默认设置为干净滤镜
mLSMediaCapture.setBeautyLevel(5); //磨皮强度为5,共5档,0为关闭
mLSMediaCapture.setFilterStrength(0.5f); //滤镜强度
mLSMediaCapture.setFilterType(publishParam.filterType);
}
private boolean startAV(){
//6、初始化直播
m_liveStreamingInitFinished = mLSMediaCapture.initLiveStream(mLiveStreamingPara,mliveStreamingURL);
if(mLSMediaCapture != null && m_liveStreamingInitFinished) {
//7、开始直播
mLSMediaCapture.startLiveStreaming();
m_liveStreamingOn = true;
if(mNeedWater){
//8、设置视频水印参数(可选)
addWaterMark();
//9、设置视频动态水印参数(可选)
addDynamicWaterMark();
}
if(mNeedGraffiti){
//10、设置视频涂鸦参数(可选)
addGraffiti();
}
return true;
}
return m_liveStreamingInitFinished;
}
//停止直播调用相关API接口
if(mLSMediaCapture != null && m_liveStreamingOn) {
//停止直播,释放资源
mLSMediaCapture.stopLiveStreaming();
//如果音视频或者单独视频直播,需要关闭视频预览
if(m_startVideoCamera)
{
mLSMediaCapture.stopVideoPreview();
//消耗第三方滤镜
releaseSenseEffect();
mLSMediaCapture.destroyVideoPreview();
}
//反初始化推流实例,当它与stopLiveStreaming连续调用时,参数为false
mLSMediaCapture.uninitLsMediaCapture(false);
mLSMediaCapture = null;
}
- 非必须 断线重连
objc//1、调用停止直播接口
if(mLSMediaCapture != null){
mLSMediaCapture.stopLiveStreaming();
}
//2、等待SDK消息回调中的停止直接结束消息
case MSG_STOP_LIVESTREAMING_FINISHED://停止直播完成
{
Log.i(TAG, "test: MSG_STOP_LIVESTREAMING_FINISHED");
showToast("停止直播已完成");
m_liveStreamingOn = false;
startPauseResumeBtn.setClickable(true);
break;
}
//3、重新初始化推流地址并直播
mLSMediaCapture.initLiveStream(mLiveStreamingPara,mliveStreamingURL);
mLSMediaCapture.startLiveStreaming();
6 API说明
有关API的详细说明,可参见SDK包中docs,打开index.html查看,或者打开下面的在线文档。