推流-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类完成初始化:
LiveConfig liveConfig = new LiveConfig.Builder()
.setCameraId(LiveConfig.CAMERA_FACING_FRONT) // 选择摄像头为前置摄像头
.setCameraOrientation(orientation) // 设置摄像头为竖向
.setVideoWidth(mVideoWidth) // 设置推流视频宽度, 需传入长的一边
.setVideoHeight(mVideoHeight) // 设置推流视频高度,需传入短的一边
.setVideoFPS(mFrameRate) // 设置视频帧率
.setInitVideoBitrate(mBitrate) // 设置视频码率,单位为bit per seconds
.setAudioBitrate(64 * 1000) // 设置音频码率,单位为bit per seconds
.setAudioSampleRate(LiveConfig.AUDIO_SAMPLE_RATE_44100) // 设置音频采样率
.setGopLengthInSeconds(2) // 设置I帧间隔,单位为秒
.setQosEnabled(true) // 开启码率自适应,默认为true,即默认开启
.setMinVideoBitrate(200 * 1000) // 码率自适应,最低码率
.setMaxVideoBitrate(1024 * 1000) // 码率自适应,最高码率
.setQosSensitivity(5) // 码率自适应,调整的灵敏度,单位为秒,可接受[5, 10]之间的整数值
.build();
Log.d(TAG, "Calling initRTMPSession..." + liveConfig.toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mLiveSession = new LiveSessionHW(this, liveConfig);
} else {
mLiveSession = new LiveSessionSW(this, liveConfig);
}
设置预览 View
初始化成功后,必须为 LiveSession 对象设置预览 View,否则无法启动相机。
以下示例代码演示了通过调用 bindPreviewDisplay 接口设置预览 View。
SurfaceView cameraView = (SurfaceView) findViewById(R.id.cameraView);
mLiveSession.bindPreviewDisplay(cameraView.getHolder());
启动音视频采集设备
在开始推流前,我们还需要启动音视频采集设备(即相机和 MIC)。
mLiveSession.prepareSessionAsync();
开始推流
当采集设备成功启动后(即收到 onSessionPrepared 回调后,参考处理推流 SDK 状态变化事件),可以通过调用 startRtmpSession 方法设置推流地址并开始推流。
以下示例代码使用 startRtmpSession 设置推流路径并开始推流,推流 URL 的具体值为:
rtmp://push.bj.bcelive.com/live/fjqgewdr17gqnuje235
。
final String url1 = "rtmp://push.bj.bcelive.com/live/fjqgewdr17gqnuje235";
if (mLiveSession.startRtmpSession(url1)) {
Log.d(TAG, "Starting Streaming in right state!");
} else {
Log.e(TAG, "Starting Streaming in wrong state!");
}
暂停视频预览和推流
成功开启推流后,您随时可以暂停视频预览和推流。
以下示例代码使用 stopPreview 停止预览以及推流。
mLiveSession.stopPreview();
恢复视频预览和推流
暂停视频预览和推流后,您随时可以恢复视频预览和推流。
以下示例代码使用 startPreview 恢复预览以及推流。
mLiveSession.startPreview();
结束推流
成功开启推流后,您随时可以结束推流。
以下示例代码使用 stopRtmpSession 结束推流。
mLiveSession.stopRtmpSession();
处理推流SDK状态变化事件
在推流 SDK 中,我们定义了名为 SessionStateListener 的 interface,您可以实现该接口并将其传递给 LiveSession 对象(通过调用 setStateListener 接口实现),这样就可以实时接收到推流 SDK 的一些属性及状态更新信息。
interface 定义如下:
public interface SessionStateListener {
/**
* 录制设备准备完毕
* @param code 固定为RESULT_CODE_OF_OPERATION_SUCCEEDED
*/
void onSessionPrepared(int code);
/**
* 推流开始后的回调
* @param code 固定为RESULT_CODE_OF_OPERATION_SUCCEEDED
*/
void onSessionStarted(int code);
/**
* 推流结束后的回调
* @param code 固定为RESULT_CODE_OF_OPERATION_SUCCEEDED
*/
void onSessionStopped(int code);
/**
* 推流 SDK 出错后的回调
* @param code 错误类型如下:
* ERROR_CODE_OF_OPEN_MIC_FAILED
* ERROR_CODE_OF_OPEN_CAMERA_FAILED
* ERROR_CODE_OF_PREPARE_SESSION_FAILED
* ERROR_CODE_OF_CONNECT_TO_SERVER_FAILED
* ERROR_CODE_OF_DISCONNECT_FROM_SERVER_FAILED
* ERROR_CODE_OF_UNKNOWN_STREAMING_ERROR
* ERROR_CODE_OF_WEAK_CONNECTION_ERROR
* ERROR_CODE_OF_SERVER_INTERNAL_ERROR
* ERROR_CODE_OF_LOCAL_NETWORK_ERROR
*/
void onSessionError(int code);
}
注意:prepareSessionAsync、startRtmpSession、stopRtmpSession 均为异步接口,即接口被调用后,不会立即得到结果,需要实现 SessionStateListener interface 侦听回调结果。如果执行成功,onSessionPrepared、onSessionStarted、onSessionStopped 方法将分别被调用,且参数固定为 RESULT_CODE_OF_OPERATION_SUCCEEDED。如果执行失败,只有 onSessionError 方法将被调用,参数及意义如下:
ERROR_CODE_OF_OPEN_MIC_FAILED // MIC设备无法打开
ERROR_CODE_OF_OPEN_CAMERA_FAILED // 相机设备无法打开
ERROR_CODE_OF_PREPARE_SESSION_FAILED // onSessionPrepared 接口调用失败,原因只能是 MIC 或相机打开失败
ERROR_CODE_OF_CONNECT_TO_SERVER_FAILED // startRtmpSession 接口调用失败,原因通常为连接不上推流服务器
ERROR_CODE_OF_DISCONNECT_FROM_SERVER_FAILED // stopRtmpSession 接口调用失败,原因通常是网络异常
另外,在推流过程中,如果遇到数据包发送失败的情况时,onSessionError 方法也将被调用,参数及意义如下:
ERROR_CODE_OF_UNKNOWN_STREAMING_ERROR // 未知的推流错误,建议收到此参数后立即结束推流
ERROR_CODE_OF_WEAK_CONNECTION_ERROR // 弱网错误,建议收到此参数后提示用户网络不稳定
ERROR_CODE_OF_SERVER_INTERNAL_ERROR // 服务器错误,建议收到此参数后立即结束推流,并在服务器恢复后再尝试推流
ERROR_CODE_OF_LOCAL_NETWORK_ERROR // 本地网络连接错误,建议收到此参数后提示用户已经断网
以下示例代码演示了如何实现 SessionStateListener interface 对 LiveSession 状态变化事件进行处理:
// 其中 mEventHandler 为各 UI 事件处理器
mStateListener = new SessionStateListener() {
@Override
public void onSessionPrepared(int code) {
if (code == SessionStateListener.RESULT_CODE_OF_OPERATION_SUCCEEDED) {
isSessionReady = true;
}
}
@Override
public void onSessionStarted(int code) {
if (code == SessionStateListener.RESULT_CODE_OF_OPERATION_SUCCEEDED) {
Log.d(TAG, "Starting Streaming succeeded!");
isSessionStarted = true;
if (mEventHandler != null) {
mEventHandler.sendEmptyMessage(EVENT_RECORDER_STARTED);
}
} else {
Log.e(TAG, "Starting Streaming failed!");
}
}
@Override
public void onSessionStopped(int code) {
if (code == SessionStateListener.RESULT_CODE_OF_OPERATION_SUCCEEDED) {
Log.d(TAG, "Stopping Streaming succeeded!");
isSessionStarted = false;
if (mEventHandler != null) {
mEventHandler.sendEmptyMessage(EVENT_RECORDER_STOPPED);
}
} else {
Log.e(TAG, "Stopping Streaming failed!");
}
}
@Override
public void onSessionError(int code) {
switch (code) {
case SessionStateListener.ERROR_CODE_OF_OPEN_MIC_FAILED:
Log.e(TAG, "Error occurred while opening MIC!");
onOpenDeviceFailed();
break;
case SessionStateListener.ERROR_CODE_OF_OPEN_CAMERA_FAILED:
Log.e(TAG, "Error occurred while opening Camera!");
onOpenDeviceFailed();
break;
case SessionStateListener.ERROR_CODE_OF_PREPARE_SESSION_FAILED:
Log.e(TAG, "Error occurred while preparing recorder!");
onPrepareFailed();
break;
case SessionStateListener.ERROR_CODE_OF_CONNECT_TO_SERVER_FAILED:
Log.e(TAG, "Error occurred while connecting to server!");
// As we can not start session successfully, we need to take it as stopped
onStartOrStopFailed();
break;
case SessionStateListener.ERROR_CODE_OF_DISCONNECT_FROM_SERVER_FAILED:
Log.e(TAG, "Error occurred while disconnecting from server!");
// Although we can not stop session successfully, we still need to take it as stopped
onStartOrStopFailed();
break;
case SessionStateListener.ERROR_CODE_OF_WEAK_CONNECTION_ERROR:
Log.e(TAG, "Your network connection is too weak to streaming!");
onStreamingError();
break;
case SessionStateListener.ERROR_CODE_OF_SERVER_INTERNAL_ERROR:
Log.e(TAG, "There is something wrong with the server!");
onStreamingError();
break;
case SessionStateListener.ERROR_CODE_OF_LOCAL_NETWORK_ERROR:
Log.e(TAG, "Connection Error while Streaming! Please check your network!");
onStreamingError();
break;
default:
if (mEventHandler != null) {
mEventHandler.sendEmptyMessage(EVENT_RECORDER_UNKNOWN_ERROR);
onStreamingError();
}
break;
}
}
};
推流效果控制
在推流过程中,你还可以通过我们的接口灵活控制推流过程中的音视频效果,详情如下:
- 切换摄像头
推流过程中,您可以通过调用 switchCamera 接口来动态切换摄像头,该函数原型如下:
void switchCamera(int cameraId);
// 作用:使用 cameraId 所代表的摄像头采集视频
// 参数:cameraId 只能为 Camera.CameraInfo.CAMERA_FACING_FRONT 或者 Camera.CameraInfo.CAMERA_FACING_BACK
// 注意:使用该接口前,您需要调用 canSwitchCamera 接口来判断当前设备是否支持切换摄像头,如果不支持,您将无法开始设备,并收到对应的错误消息 ERROR_CODE_OF_OPEN_CAMERA_FAILED
- 判断是否支持切换摄像头
推流过程中,您可以通过调用 canSwitchCamera 接口来判断设备是否支持动态切换摄像头,该函数原型如下:
boolean canSwitchCamera();
// 作用:判断设备是否支持动态切换摄像头
// 返回值:返回值为 true 表示支持切换,否则不支持切换
- 开关闪光灯
推流过程中,您可以通过调用 toggleFlash 接口来动态开关闪光灯,该函数原型如下:
void toggleFlash(boolean flag);
// 作用:根据传入的参数值开关闪光灯
// 参数:flag 为 true 时表示开启闪光灯,为 false 时表示关闭闪光灯
// 注意:使用该接口前,您需要确认此时的摄像头是拥有闪光灯,如果没有(前置摄像头通常不具备闪光灯),调用该接口将无法开启闪光灯
- 触发自动对焦
推流过程中,您可以通过调用 focusToPosition 接口来触发自动对焦,该函数原型如下:
void focusToPosition(int x, int y);
// 作用:触发摄像头自动对焦功能
// 参数:(x, y) 为对焦中心点在屏幕上的坐标
- 放大视频画面
推流过程中,您可以通过调用 zoomInCamera 接口来放大当前视频画面,该函数原型如下:
void zoomInCamera();
// 作用:将摄像头所采集的当前视频画面放大一级(视频原始大小被定义为第0级)
// 注意:视频被放大后,高宽像素保持不变,超出画面的部分将裁剪掉;如果放大级别超过了最大级别(通过 getMaxZoomFactor 接口获取),调用该接口将不起作用
- 缩小视频画面
推流过程中,您可以通过调用 zoomOutCamera 接口来缩小当前视频画面,该函数原型如下:
void zoomOutCamera();
// 作用:将摄像头所采集的当前视频画面缩小一级
// 注意:视频被缩小后,高宽像素保持不变;如果当前放大级别(通过 getCurrentZoomFactor 接口获取)为第0级,调用该接口将不起作用
- 指定视频画面放大级别
推流过程中,您可以通过调用 setCameraZoomLevel 接口来指定当前视频画面的放大级别,该函数原型如下:
void setCameraZoomLevel(int zoomlevel);
// 作用:将摄像头所采集的当前视频画面放大到 zoomlevel 所指定的级别
// 注意:zoomlevel 的取值不能小于0,也不能大于最大级别(通过 getMaxZoomFactor 接口获取),否则该接口将不起作用
- 取消视频画面放大效果
推流过程中,您可以通过调用 cancelZoomCamera 接口来取消当前视频画面的放大效果,该函数原型如下:
void cancelZoomCamera();
// 作用:取消当前视频画面的放大效果
-
使用美颜功能(仅当硬编码时有效)
收到推流 SDK 的 onSessionPrepared 回调后,即可使用 enableDefaultBeautyEffect 和 setBeautyEffectLevel 两个接口设置美颜效果。
-
setBeautyEffectLevel:用于设置美颜效果,参数为 0 表示没有效果,参数为 1 表示最大效果。调用该接口后美颜效果会立即生效,无需再次调用 enableBeautyEffect。函数原型如下:
/** * 开启或关闭默认美颜效果 * 注意:此方法只对LiveSessionHW对象有效 * @param isEnable: true 则开启默认美颜效果; false 则关闭所有美颜效果(包括自定义的美颜效果) */ public abstract void enableDefaultBeautyEffect(boolean isEnable);
-
enableDefaultBeautyEffect:用于开启或关闭美颜效果。开启前若未使用 setBeautyEffectLevel 接口设置过美颜参数,则使用默认美颜参数;否则使用最近设置的美颜参数。函数原型如下:
/** * 设置自定义美颜效果,设置后立即开启 * 注意:此方法只对LiveSessionHW对象有效 * @param brightLevel: 美白级别,取值范围为[0, 1],0为无效果,1为最大效果 * @param smoothLevel: 磨皮级别,取值范围为[0, 1],0为无效果,1为最大效果 * @param pinkLevel: 粉嫩级别,取值范围为[0, 1],0为无效果,1为最大效果 */ public abstract void setBeautyEffectLevel(float brightLevel, float smoothLevel, float pinkLevel);
-
- 控制音视频输出
推流开始以后,可以通过调用 setAudioEnabled 和 setVideoEnabled 开控制是否推送音频流或者视频流。默认音视频数据都推送。
setAudioEnabled 函数原型如下:
/**
* 开启或关闭音频推流接口
* @param isEnableAudio
*/
public abstract void setAudioEnabled(boolean isEnableAudio);
setVideoEnabled 函数原型如下:
/**
* 开启或关闭视频推流接口
* @param isEnableVideo
*/
public abstract void setVideoEnabled(boolean isEnableVideo);