推流-SDK-开发指南
准备工作
- 开通 百度智能云音视频直播服务,添加推拉流域名并获取推流地址及观看地址。
- 下载最新的Android 推流 SDK。
- 准备 Android 开发环境:安装有 ADT 插件的 Eclipse 开发环境。
- 准备 Android 运行环境:软编码支持Android 4.2及以上的所有系统,硬编码支持Android 4.3 及以上的所有系统
- 适配 CPU 指令集:armv7/armv7a、arm64。
- 添加依赖: 将Baidu-Capture-Android-iOS-x.x.x/libs 目录复制到 Eclipse 工程根目录,注意根据所支持的 arm 版本选择对应的动态链接库。
-
权限声明:请您在 Android App 的 AndroidManifest.xml 中声明如下权限:
初始化 LiveSession
LiveSession是对视频采集、编码、推流等功能模块接口进行封装后的接口类,为您提供友好的编程接口。 LiveSession有两个子类,LiveSessionHW 跟 LiveSessionSW,分别是硬编码和软编码方案对应的实现类。
推流 SDK 使用LiveConfig类完成初始化:
1LiveConfig liveConfig = new LiveConfig.Builder()
2 .setCameraId(LiveConfig.CAMERA_FACING_FRONT) // 选择摄像头为前置摄像头
3 .setCameraOrientation(orientation) // 设置摄像头为竖向
4 .setVideoWidth(mVideoWidth) // 设置推流视频宽度, 需传入长的一边
5 .setVideoHeight(mVideoHeight) // 设置推流视频高度,需传入短的一边
6 .setVideoFPS(mFrameRate) // 设置视频帧率
7 .setInitVideoBitrate(mBitrate) // 设置视频码率,单位为bit per seconds
8 .setAudioBitrate(64 * 1000) // 设置音频码率,单位为bit per seconds
9 .setAudioSampleRate(LiveConfig.AUDIO_SAMPLE_RATE_44100) // 设置音频采样率
10 .setGopLengthInSeconds(2) // 设置I帧间隔,单位为秒
11 .setQosEnabled(true) // 开启码率自适应,默认为true,即默认开启
12 .setMinVideoBitrate(200 * 1000) // 码率自适应,最低码率
13 .setMaxVideoBitrate(1024 * 1000) // 码率自适应,最高码率
14 .setQosSensitivity(5) // 码率自适应,调整的灵敏度,单位为秒,可接受[5, 10]之间的整数值
15 .build();
16Log.d(TAG, "Calling initRTMPSession..." + liveConfig.toString());
17if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
18 mLiveSession = new LiveSessionHW(this, liveConfig);
19} else {
20 mLiveSession = new LiveSessionSW(this, liveConfig);
21}
设置预览 View
初始化成功后,必须为 LiveSession 对象设置预览 View,否则无法启动相机。
以下示例代码演示了通过调用 bindPreviewDisplay 接口设置预览 View。
1SurfaceView cameraView = (SurfaceView) findViewById(R.id.cameraView);
2mLiveSession.bindPreviewDisplay(cameraView.getHolder());
启动音视频采集设备
在开始推流前,我们还需要启动音视频采集设备(即相机和 MIC)。
1mLiveSession.prepareSessionAsync();
开始推流
当采集设备成功启动后(即收到 onSessionPrepared 回调后,参考处理推流 SDK 状态变化事件),可以通过调用 startRtmpSession 方法设置推流地址并开始推流。
以下示例代码使用 startRtmpSession 设置推流路径并开始推流,推流 URL 的具体值为:
rtmp://push.bj.bcelive.com/live/fjqgewdr17gqnuje235
。
1final String url1 = "rtmp://push.bj.bcelive.com/live/fjqgewdr17gqnuje235";
2if (mLiveSession.startRtmpSession(url1)) {
3 Log.d(TAG, "Starting Streaming in right state!");
4} else {
5 Log.e(TAG, "Starting Streaming in wrong state!");
6}
暂停视频预览和推流
成功开启推流后,您随时可以暂停视频预览和推流。
以下示例代码使用 stopPreview 停止预览以及推流。
1mLiveSession.stopPreview();
恢复视频预览和推流
暂停视频预览和推流后,您随时可以恢复视频预览和推流。
以下示例代码使用 startPreview 恢复预览以及推流。
1mLiveSession.startPreview();
结束推流
成功开启推流后,您随时可以结束推流。
以下示例代码使用 stopRtmpSession 结束推流。
1mLiveSession.stopRtmpSession();
处理推流SDK状态变化事件
在推流 SDK 中,我们定义了名为 SessionStateListener 的 interface,您可以实现该接口并将其传递给 LiveSession 对象(通过调用 setStateListener 接口实现),这样就可以实时接收到推流 SDK 的一些属性及状态更新信息。
interface 定义如下:
1public interface SessionStateListener {
2
3 /**
4 * 录制设备准备完毕
5 * @param code 固定为RESULT_CODE_OF_OPERATION_SUCCEEDED
6 */
7 void onSessionPrepared(int code);
8
9 /**
10 * 推流开始后的回调
11 * @param code 固定为RESULT_CODE_OF_OPERATION_SUCCEEDED
12 */
13 void onSessionStarted(int code);
14
15 /**
16 * 推流结束后的回调
17 * @param code 固定为RESULT_CODE_OF_OPERATION_SUCCEEDED
18 */
19 void onSessionStopped(int code);
20
21 /**
22 * 推流 SDK 出错后的回调
23 * @param code 错误类型如下:
24 * ERROR_CODE_OF_OPEN_MIC_FAILED
25 * ERROR_CODE_OF_OPEN_CAMERA_FAILED
26 * ERROR_CODE_OF_PREPARE_SESSION_FAILED
27 * ERROR_CODE_OF_CONNECT_TO_SERVER_FAILED
28 * ERROR_CODE_OF_DISCONNECT_FROM_SERVER_FAILED
29 * ERROR_CODE_OF_UNKNOWN_STREAMING_ERROR
30 * ERROR_CODE_OF_WEAK_CONNECTION_ERROR
31 * ERROR_CODE_OF_SERVER_INTERNAL_ERROR
32 * ERROR_CODE_OF_LOCAL_NETWORK_ERROR
33 */
34 void onSessionError(int code);
35}
注意:prepareSessionAsync、startRtmpSession、stopRtmpSession 均为异步接口,即接口被调用后,不会立即得到结果,需要实现 SessionStateListener interface 侦听回调结果。如果执行成功,onSessionPrepared、onSessionStarted、onSessionStopped 方法将分别被调用,且参数固定为 RESULT_CODE_OF_OPERATION_SUCCEEDED。如果执行失败,只有 onSessionError 方法将被调用,参数及意义如下:
1ERROR_CODE_OF_OPEN_MIC_FAILED // MIC设备无法打开
2ERROR_CODE_OF_OPEN_CAMERA_FAILED // 相机设备无法打开
3ERROR_CODE_OF_PREPARE_SESSION_FAILED // onSessionPrepared 接口调用失败,原因只能是 MIC 或相机打开失败
4ERROR_CODE_OF_CONNECT_TO_SERVER_FAILED // startRtmpSession 接口调用失败,原因通常为连接不上推流服务器
5ERROR_CODE_OF_DISCONNECT_FROM_SERVER_FAILED // stopRtmpSession 接口调用失败,原因通常是网络异常
另外,在推流过程中,如果遇到数据包发送失败的情况时,onSessionError 方法也将被调用,参数及意义如下:
1ERROR_CODE_OF_UNKNOWN_STREAMING_ERROR // 未知的推流错误,建议收到此参数后立即结束推流
2ERROR_CODE_OF_WEAK_CONNECTION_ERROR // 弱网错误,建议收到此参数后提示用户网络不稳定
3ERROR_CODE_OF_SERVER_INTERNAL_ERROR // 服务器错误,建议收到此参数后立即结束推流,并在服务器恢复后再尝试推流
4ERROR_CODE_OF_LOCAL_NETWORK_ERROR // 本地网络连接错误,建议收到此参数后提示用户已经断网
以下示例代码演示了如何实现 SessionStateListener interface 对 LiveSession 状态变化事件进行处理:
1// 其中 mEventHandler 为各 UI 事件处理器
2mStateListener = new SessionStateListener() {
3 @Override
4 public void onSessionPrepared(int code) {
5 if (code == SessionStateListener.RESULT_CODE_OF_OPERATION_SUCCEEDED) {
6 isSessionReady = true;
7 }
8 }
9
10 @Override
11 public void onSessionStarted(int code) {
12 if (code == SessionStateListener.RESULT_CODE_OF_OPERATION_SUCCEEDED) {
13 Log.d(TAG, "Starting Streaming succeeded!");
14 isSessionStarted = true;
15 if (mEventHandler != null) {
16 mEventHandler.sendEmptyMessage(EVENT_RECORDER_STARTED);
17 }
18 } else {
19 Log.e(TAG, "Starting Streaming failed!");
20 }
21 }
22
23 @Override
24 public void onSessionStopped(int code) {
25 if (code == SessionStateListener.RESULT_CODE_OF_OPERATION_SUCCEEDED) {
26 Log.d(TAG, "Stopping Streaming succeeded!");
27 isSessionStarted = false;
28 if (mEventHandler != null) {
29 mEventHandler.sendEmptyMessage(EVENT_RECORDER_STOPPED);
30 }
31 } else {
32 Log.e(TAG, "Stopping Streaming failed!");
33 }
34 }
35
36 @Override
37 public void onSessionError(int code) {
38 switch (code) {
39 case SessionStateListener.ERROR_CODE_OF_OPEN_MIC_FAILED:
40 Log.e(TAG, "Error occurred while opening MIC!");
41 onOpenDeviceFailed();
42 break;
43 case SessionStateListener.ERROR_CODE_OF_OPEN_CAMERA_FAILED:
44 Log.e(TAG, "Error occurred while opening Camera!");
45 onOpenDeviceFailed();
46 break;
47 case SessionStateListener.ERROR_CODE_OF_PREPARE_SESSION_FAILED:
48 Log.e(TAG, "Error occurred while preparing recorder!");
49 onPrepareFailed();
50 break;
51 case SessionStateListener.ERROR_CODE_OF_CONNECT_TO_SERVER_FAILED:
52 Log.e(TAG, "Error occurred while connecting to server!");
53 // As we can not start session successfully, we need to take it as stopped
54 onStartOrStopFailed();
55 break;
56 case SessionStateListener.ERROR_CODE_OF_DISCONNECT_FROM_SERVER_FAILED:
57 Log.e(TAG, "Error occurred while disconnecting from server!");
58 // Although we can not stop session successfully, we still need to take it as stopped
59 onStartOrStopFailed();
60 break;
61 case SessionStateListener.ERROR_CODE_OF_WEAK_CONNECTION_ERROR:
62 Log.e(TAG, "Your network connection is too weak to streaming!");
63 onStreamingError();
64 break;
65 case SessionStateListener.ERROR_CODE_OF_SERVER_INTERNAL_ERROR:
66 Log.e(TAG, "There is something wrong with the server!");
67 onStreamingError();
68 break;
69 case SessionStateListener.ERROR_CODE_OF_LOCAL_NETWORK_ERROR:
70 Log.e(TAG, "Connection Error while Streaming! Please check your network!");
71 onStreamingError();
72 break;
73 default:
74 if (mEventHandler != null) {
75 mEventHandler.sendEmptyMessage(EVENT_RECORDER_UNKNOWN_ERROR);
76 onStreamingError();
77 }
78 break;
79 }
80 }
81};
推流效果控制
在推流过程中,你还可以通过我们的接口灵活控制推流过程中的音视频效果,详情如下:
- 切换摄像头
推流过程中,您可以通过调用 switchCamera 接口来动态切换摄像头,该函数原型如下:
1void switchCamera(int cameraId);
2// 作用:使用 cameraId 所代表的摄像头采集视频
3// 参数:cameraId 只能为 Camera.CameraInfo.CAMERA_FACING_FRONT 或者 Camera.CameraInfo.CAMERA_FACING_BACK
4// 注意:使用该接口前,您需要调用 canSwitchCamera 接口来判断当前设备是否支持切换摄像头,如果不支持,您将无法开始设备,并收到对应的错误消息 ERROR_CODE_OF_OPEN_CAMERA_FAILED
- 判断是否支持切换摄像头
推流过程中,您可以通过调用 canSwitchCamera 接口来判断设备是否支持动态切换摄像头,该函数原型如下:
1boolean canSwitchCamera();
2// 作用:判断设备是否支持动态切换摄像头
3// 返回值:返回值为 true 表示支持切换,否则不支持切换
- 开关闪光灯
推流过程中,您可以通过调用 toggleFlash 接口来动态开关闪光灯,该函数原型如下:
1void toggleFlash(boolean flag);
2// 作用:根据传入的参数值开关闪光灯
3// 参数:flag 为 true 时表示开启闪光灯,为 false 时表示关闭闪光灯
4// 注意:使用该接口前,您需要确认此时的摄像头是拥有闪光灯,如果没有(前置摄像头通常不具备闪光灯),调用该接口将无法开启闪光灯
- 触发自动对焦
推流过程中,您可以通过调用 focusToPosition 接口来触发自动对焦,该函数原型如下:
1void focusToPosition(int x, int y);
2// 作用:触发摄像头自动对焦功能
3// 参数:(x, y) 为对焦中心点在屏幕上的坐标
- 放大视频画面
推流过程中,您可以通过调用 zoomInCamera 接口来放大当前视频画面,该函数原型如下:
1void zoomInCamera();
2// 作用:将摄像头所采集的当前视频画面放大一级(视频原始大小被定义为第0级)
3// 注意:视频被放大后,高宽像素保持不变,超出画面的部分将裁剪掉;如果放大级别超过了最大级别(通过 getMaxZoomFactor 接口获取),调用该接口将不起作用
- 缩小视频画面
推流过程中,您可以通过调用 zoomOutCamera 接口来缩小当前视频画面,该函数原型如下:
1void zoomOutCamera();
2// 作用:将摄像头所采集的当前视频画面缩小一级
3// 注意:视频被缩小后,高宽像素保持不变;如果当前放大级别(通过 getCurrentZoomFactor 接口获取)为第0级,调用该接口将不起作用
- 指定视频画面放大级别
推流过程中,您可以通过调用 setCameraZoomLevel 接口来指定当前视频画面的放大级别,该函数原型如下:
1void setCameraZoomLevel(int zoomlevel);
2// 作用:将摄像头所采集的当前视频画面放大到 zoomlevel 所指定的级别
3// 注意:zoomlevel 的取值不能小于0,也不能大于最大级别(通过 getMaxZoomFactor 接口获取),否则该接口将不起作用
- 取消视频画面放大效果
推流过程中,您可以通过调用 cancelZoomCamera 接口来取消当前视频画面的放大效果,该函数原型如下:
1void cancelZoomCamera();
2// 作用:取消当前视频画面的放大效果
-
使用美颜功能(仅当硬编码时有效)
收到推流 SDK 的 onSessionPrepared 回调后,即可使用 enableDefaultBeautyEffect 和 setBeautyEffectLevel 两个接口设置美颜效果。
-
setBeautyEffectLevel:用于设置美颜效果,参数为 0 表示没有效果,参数为 1 表示最大效果。调用该接口后美颜效果会立即生效,无需再次调用 enableBeautyEffect。函数原型如下:
Plain Text1 /** 2 * 开启或关闭默认美颜效果 3 * 注意:此方法只对LiveSessionHW对象有效 4 * @param isEnable: true 则开启默认美颜效果; false 则关闭所有美颜效果(包括自定义的美颜效果) 5 */ 6 public abstract void enableDefaultBeautyEffect(boolean isEnable);
-
enableDefaultBeautyEffect:用于开启或关闭美颜效果。开启前若未使用 setBeautyEffectLevel 接口设置过美颜参数,则使用默认美颜参数;否则使用最近设置的美颜参数。函数原型如下:
Plain Text1 /** 2 * 设置自定义美颜效果,设置后立即开启 3 * 注意:此方法只对LiveSessionHW对象有效 4 * @param brightLevel: 美白级别,取值范围为[0, 1],0为无效果,1为最大效果 5 * @param smoothLevel: 磨皮级别,取值范围为[0, 1],0为无效果,1为最大效果 6 * @param pinkLevel: 粉嫩级别,取值范围为[0, 1],0为无效果,1为最大效果 7 */ 8 public abstract void setBeautyEffectLevel(float brightLevel, float smoothLevel, float pinkLevel);
-
- 控制音视频输出
推流开始以后,可以通过调用 setAudioEnabled 和 setVideoEnabled 开控制是否推送音频流或者视频流。默认音视频数据都推送。
setAudioEnabled 函数原型如下:
1/**
2 * 开启或关闭音频推流接口
3 * @param isEnableAudio
4 */
5public abstract void setAudioEnabled(boolean isEnableAudio);
setVideoEnabled 函数原型如下:
1/**
2 * 开启或关闭视频推流接口
3 * @param isEnableVideo
4 */
5public abstract void setVideoEnabled(boolean isEnableVideo);