智汇云以SDK形式提供视频拍摄采集,可以帮助开发者快速实现视频拍摄能力。SDK包括开发文档、开发demo、SDK
JAR文件以及SO库文件。开发者可参考文档或demo,将JAR文件和SO文件加入APP的工程中,完成相关配置,调用相关的API即可完成Android的音视频直播采集录制服务。
系统特性 | 支持内容 |
---|---|
系统版本 | Android 4.0及以上 |
硬件特性 | armeabi-v7a、arm64-v8a |
属性 | 支持内容 |
参数设置 | 自定义采集分辨率、码率、帧率、关键帧间隔等 |
编码方式 | H264、AAC |
设备驱动 | 摄像头、声音开关 |
功能列表 |
---|
多种屏比拍摄 |
拍摄控制 |
变速控制 |
分段拍摄 |
断点拍摄 |
背景音乐 |
实时滤镜 |
…… |
从这里下载 SDK Demo。
demo: 示例工程,演示本SDK主要接口功能的使用
libs/[armeabi-v7a|arm64-v8a|x86]: 各平台的so库
libs/qhvc_shoot_sdk.jar: 拍摄SDK jar包
src/main/assets/videorecord/shader 滤镜功能用到的资源文件
videosdk_recorder.jar放到工程libs目录下,在build.gradle中配置:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
}
将下载的.so放到工程src/main/jniLibs/armeabi-v7a/目录下,在build.gradle中配置:
android {
defaultConfig {
ndk {
// 设置支持的CPU架构,目前只支持armeabi-v7a架构(该架构兼容armeabi、arm64-v8a、x86、x86_64架构)
abiFilters 'armeabi-v7a'
}
}
}
权限配置
在AndroidManifest.xml文件中申请相应权限:
<uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
recordKit = new QHVCRecordKit(this);
recordKit.setOrientation(QHVCRecordConstants.Orientation.ORIENTATION_PORTRAIT);
videoRecordConfig = new QHVCVideoRecordConfig.Builder().setVideoWidth(360).setVideoHeight(640).build();
audioRecordConfig = new QHVCAudioRecordConfig.Builder().setSampleRate(QHVCRecordConstants.RecordAudioSampleRate.audio_sample_22050HZ).build());
recordKit.initRecordConfing(videoRecordConfig,audioRecordConfig);
recordKit.setRecordSavePath(videoPath, videoSegmentFolder, new QHVCRecordCallBack() {
@Override
public void onstart(int recordId) {
RecordLogger.i(TAG, TAG + "setRecordSavePath:onstart()" + recordId);
recordTime = 0;
if (recordKit != null) {
SegmentInfo segmentInfo = new SegmentInfo();
recordKit.getRecordInfo(recordId, segmentInfo);
RecordLogger.i(TAG, TAG + "setRecordSavePath:onstart():segmentInfo:" + segmentInfo.toString());
}
}
@Override
public void onProcess(int recordId, long duration) {
RecordLogger.i(TAG, TAG + "setRecordSavePath:onProcess():---recordId:" + recordId
+ "----duration:" + duration);
recordTime = (int) duration;
}
@Override
public void onStop(int recordId, long duration, int errorCode) {
RecordLogger.i(TAG, TAG + "setRecordSavePath:onStop():---recordId" + recordId+"----duration:" + duration);
recordTotalTime = recordTotalTime + (int)duration;
runOnUiThread(new Runnable() {
@Override
public void run() {
if(deleteLastPath.get()){
deleteLastReocord();
deleteLastPath.set(false);
}
recordSeekBar.setProgress(recordTotalTime);
}
});
recordTime = 0;
}
@Override
public void onError(int errorCode, final String message) {
RecordLogger.e(TAG, TAG + "setRecordSavePath:onError():---errorCode" + errorCode + ",message:" + message);
switch (errorCode) {
case ERROR_CODE_SEND_VIDEO_DATA:
case ERROR_CODE_SEND_AUDIO_DATA:
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(RecordActivity.this, message, Toast.LENGTH_LONG).show();
if (isRecord.get()) {/*先停止拍摄*/
deleteLastPath.set(true);
startOrStopRecord();
}
deleteLastReocord();
}
});
break;
}
}
recordKit.setVideoDataCallBack(new QHVCVideoDataCallBack() {
@Override
public void onRawData(byte[] recordData, int width, int height) {
// RecordLogger.i(TAG,TAG+"Video:onRawData():---recordData"+recordData.length);
if(beautyShader!=null){
beautyShader.catchPoints(recordData,recordKit.isUseFrontCamera()?
Camera.CameraInfo.CAMERA_FACING_FRONT:Camera.CameraInfo.CAMERA_FACING_BACK,width,height);
}
}
@Override
public void onPostData(SurfaceTexture surfaceTexture) {
}
@Override
public void onEncodeData(byte[] recordData, int length, long pts, int frameType) {
// RecordLogger.i(TAG,TAG+"Video:onEncodeData():---recordData"+recordData.length);
}
@Override
public void onYUVonPostData(byte[] yData, int yStride, byte[] uData, int uStride, byte[] vData, int vStride, long pts, int frameType) {
// RecordLogger.i(TAG,TAG+"Video:onYUVonPostData():---yData:"+yData.length);
}
});
recordKit.setAudioDataCallback(new QHVCAudioDataCallBack() {
@Override
public void onRawData(byte[] recordData, int length, int datatype) {
}
@Override
public void onEncodeData(byte[] recordData, int length, int pts) {
}
});
recordKit.setDisplayPreview(surfaceview);
recordKit.setEncodeMethod(QHVCRecordConstants.EncodeMethod.ENCODE_HARDWARE);
recordKit.startPreview();
recordKit.startRecord();
recordKit.stopRecord();
recordKit.deleteLastPath();
recordKit.deleteLastSegmentByMS(deleteTime);
recordKit.addShader(GPVideoRecorderShaderType.Shader[shaderSelect], 0);
recordKit.switchCameraFacing();
recordKit.openFlashLight(flashLightOpen);
recordKit.setRecordSpeed(Float.parseFloat(speed));
recordKit.setMute(true);
recordKit.joinAllSegment(new QHVCJoinRecordCallBack() {
@Override
public void onStart() {
runOnUiThread(new Runnable() {
@Override
public void run() {
joinProcessDialog();
}
});
}
@Override
public void onProcess(final float process) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mExitDialog != null && mExitDialog.isShowing()) {
DecimalFormat decimalFormat = new DecimalFormat(".0");//构造方法的字符格式这里如果小数不足2位,会以0补足.
String p = decimalFormat.format(process);//format 返回的是字符串
mExitDialog.setMsgText("当前进度:" + p + "%");
}
}
});
}
@Override
public void onFinish(final SegmentInfo[] segmentInfos, final RecordFileInfo recordFileInfo) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Logger.e(TAG,"SegmentInfos:"+ Arrays.toString(segmentInfos)+
",--recordFileInfo:"+recordFileInfo.toString()+",--totleTime:"+recordTotalTime);
insertVideoToMediaStore(RecordActivity.this, videoPath, System.currentTimeMillis(), videoRecordConfig.getVideoWidth(), videoRecordConfig.getVideoHeight(),
recordTotalTime);
if (mExitDialog != null && mExitDialog.isShowing()) {
mExitDialog.dismiss();
}
Intent intent = new Intent(RecordActivity.this, ShowCombineRecordActivity.class);
intent.putExtra("videoPath", videoPath);
startActivity(intent);
finish();
}
});
}
@Override
public void onError() {
RecordLogger.i(TAG, TAG + "joinAllSegment:onError()");
}
@Override
public void onCancel() {
}
});
recordKit.cancelJoin();
recordKit.release();
更多详细接口请参考API接口文档及Demo
值 | 对应消息 |
---|---|
-999 | 时间戳错误 |
-998 | 调用不对 |
-997 | 配置参数不对 |
-899 | 参数错误 |
-797 | 创建线程错误 |
-794 | 打开编码器失败 |
-791 | 写文件失败 |
-786 | 音频数据错误 |
为便于接入时定位问题,在开发版本中已记录关键日志,推流相关的日志TAG为”QHVCRecordKit”。
-keepclasseswithmembernames class * {
native <methods>;
}
-keep class com.qihoo.livecloud.recordkit.** {
<fields>;
<methods>;
}
只需完成注册与实名认证,即可体验我们的贴心服务
4000052360
试用小安,请确保该账户已通过智汇云实名认证 前往认证中心>>