Android拍摄 SDK开发文档

Android拍摄 SDK简单介绍

智汇云以SDK形式提供视频拍摄采集,可以帮助开发者快速实现视频拍摄能力。SDK包括开发文档、开发demo、SDK
JAR文件以及SO库文件。开发者可参考文档或demo,将JAR文件和SO文件加入APP的工程中,完成相关配置,调用相关的API即可完成Android的音视频直播采集录制服务。

功能说明:

系统特性 支持内容
系统版本 Android 4.0及以上
硬件特性 armeabi-v7a、arm64-v8a
属性 支持内容
参数设置 自定义采集分辨率、码率、帧率、关键帧间隔等
编码方式 H264、AAC
设备驱动 摄像头、声音开关
功能列表
多种屏比拍摄
拍摄控制
变速控制
分段拍摄
断点拍摄
背景音乐
实时滤镜
……

SDK集成方法介绍:

下载Demo工程

从这里下载 SDK Demo

下载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中配置:

  1. dependencies {
  2. compile fileTree(include: ['*.jar'], dir: 'libs')
  3. }

将下载的.so放到工程src/main/jniLibs/armeabi-v7a/目录下,在build.gradle中配置:

  1. android {
  2. defaultConfig {
  3. ndk {
  4. // 设置支持的CPU架构,目前只支持armeabi-v7a架构(该架构兼容armeabi、arm64-v8a、x86、x86_64架构)
  5. abiFilters 'armeabi-v7a'
  6. }
  7. }
  8. }

权限配置

在AndroidManifest.xml文件中申请相应权限:

  1. <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  3. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  4. <uses-permission android:name="android.permission.FLASHLIGHT" />
  5. <uses-permission android:name="android.permission.WAKE_LOCK"/>
  6. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  7. <uses-permission android:name="android.permission.RECORD_VIDEO"/>
  8. <uses-permission android:name="android.permission.RECORD_AUDIO"/>
  9. <uses-permission android:name="android.permission.CAMERA"/>
  10. <uses-feature android:glEsVersion="0x00020000" android:required="true"/>
  11. <uses-feature android:name="android.hardware.camera"/>
  12. <uses-feature android:name="android.hardware.camera.autofocus"/>
  13. <uses-permission android:name="android.permission.READ_LOGS"/>
  14. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
  15. <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

SDK接口使用流程说明:

接口调用流程图

image

初始化拍摄类
  1. recordKit = new QHVCRecordKit(this);
  2. recordKit.setOrientation(QHVCRecordConstants.Orientation.ORIENTATION_PORTRAIT);

设置拍摄推流参数

视频相关参数
  1. videoRecordConfig = new QHVCVideoRecordConfig.Builder().setVideoWidth(360).setVideoHeight(640).build();
音频相关参数
  1. audioRecordConfig = new QHVCAudioRecordConfig.Builder().setSampleRate(QHVCRecordConstants.RecordAudioSampleRate.audio_sample_22050HZ).build());
设置音视频参数
  1. recordKit.initRecordConfing(videoRecordConfig,audioRecordConfig);
设置保存路径及录制回调信息
  1. recordKit.setRecordSavePath(videoPath, videoSegmentFolder, new QHVCRecordCallBack() {
  2. @Override
  3. public void onstart(int recordId) {
  4. RecordLogger.i(TAG, TAG + "setRecordSavePath:onstart()" + recordId);
  5. recordTime = 0;
  6. if (recordKit != null) {
  7. SegmentInfo segmentInfo = new SegmentInfo();
  8. recordKit.getRecordInfo(recordId, segmentInfo);
  9. RecordLogger.i(TAG, TAG + "setRecordSavePath:onstart():segmentInfo:" + segmentInfo.toString());
  10. }
  11. }
  12. @Override
  13. public void onProcess(int recordId, long duration) {
  14. RecordLogger.i(TAG, TAG + "setRecordSavePath:onProcess():---recordId:" + recordId
  15. + "----duration:" + duration);
  16. recordTime = (int) duration;
  17. }
  18. @Override
  19. public void onStop(int recordId, long duration, int errorCode) {
  20. RecordLogger.i(TAG, TAG + "setRecordSavePath:onStop():---recordId" + recordId+"----duration:" + duration);
  21. recordTotalTime = recordTotalTime + (int)duration;
  22. runOnUiThread(new Runnable() {
  23. @Override
  24. public void run() {
  25. if(deleteLastPath.get()){
  26. deleteLastReocord();
  27. deleteLastPath.set(false);
  28. }
  29. recordSeekBar.setProgress(recordTotalTime);
  30. }
  31. });
  32. recordTime = 0;
  33. }
  34. @Override
  35. public void onError(int errorCode, final String message) {
  36. RecordLogger.e(TAG, TAG + "setRecordSavePath:onError():---errorCode" + errorCode + ",message:" + message);
  37. switch (errorCode) {
  38. case ERROR_CODE_SEND_VIDEO_DATA:
  39. case ERROR_CODE_SEND_AUDIO_DATA:
  40. runOnUiThread(new Runnable() {
  41. @Override
  42. public void run() {
  43. Toast.makeText(RecordActivity.this, message, Toast.LENGTH_LONG).show();
  44. if (isRecord.get()) {/*先停止拍摄*/
  45. deleteLastPath.set(true);
  46. startOrStopRecord();
  47. }
  48. deleteLastReocord();
  49. }
  50. });
  51. break;
  52. }
  53. }
设置视频数据回调
  1. recordKit.setVideoDataCallBack(new QHVCVideoDataCallBack() {
  2. @Override
  3. public void onRawData(byte[] recordData, int width, int height) {
  4. // RecordLogger.i(TAG,TAG+"Video:onRawData():---recordData"+recordData.length);
  5. if(beautyShader!=null){
  6. beautyShader.catchPoints(recordData,recordKit.isUseFrontCamera()?
  7. Camera.CameraInfo.CAMERA_FACING_FRONT:Camera.CameraInfo.CAMERA_FACING_BACK,width,height);
  8. }
  9. }
  10. @Override
  11. public void onPostData(SurfaceTexture surfaceTexture) {
  12. }
  13. @Override
  14. public void onEncodeData(byte[] recordData, int length, long pts, int frameType) {
  15. // RecordLogger.i(TAG,TAG+"Video:onEncodeData():---recordData"+recordData.length);
  16. }
  17. @Override
  18. public void onYUVonPostData(byte[] yData, int yStride, byte[] uData, int uStride, byte[] vData, int vStride, long pts, int frameType) {
  19. // RecordLogger.i(TAG,TAG+"Video:onYUVonPostData():---yData:"+yData.length);
  20. }
  21. });
设置音频数据回调
  1. recordKit.setAudioDataCallback(new QHVCAudioDataCallBack() {
  2. @Override
  3. public void onRawData(byte[] recordData, int length, int datatype) {
  4. }
  5. @Override
  6. public void onEncodeData(byte[] recordData, int length, int pts) {
  7. }
  8. });
设置预览View
  1. recordKit.setDisplayPreview(surfaceview);
编码方式
  1. recordKit.setEncodeMethod(QHVCRecordConstants.EncodeMethod.ENCODE_HARDWARE);
开启预览
  1. recordKit.startPreview();
开始录制
  1. recordKit.startRecord();
停止录制
  1. recordKit.stopRecord();
删除最后分段视频
  1. recordKit.deleteLastPath();
删除最后N秒
  1. recordKit.deleteLastSegmentByMS(deleteTime);
加入自定义效果
  1. recordKit.addShader(GPVideoRecorderShaderType.Shader[shaderSelect], 0);
切换摄像头
  1. recordKit.switchCameraFacing();
开启闪光灯
  1. recordKit.openFlashLight(flashLightOpen);
设置倍速
  1. recordKit.setRecordSpeed(Float.parseFloat(speed));
设置静音
  1. recordKit.setMute(true);
合成多段视频
  1. recordKit.joinAllSegment(new QHVCJoinRecordCallBack() {
  2. @Override
  3. public void onStart() {
  4. runOnUiThread(new Runnable() {
  5. @Override
  6. public void run() {
  7. joinProcessDialog();
  8. }
  9. });
  10. }
  11. @Override
  12. public void onProcess(final float process) {
  13. runOnUiThread(new Runnable() {
  14. @Override
  15. public void run() {
  16. if (mExitDialog != null && mExitDialog.isShowing()) {
  17. DecimalFormat decimalFormat = new DecimalFormat(".0");//构造方法的字符格式这里如果小数不足2位,会以0补足.
  18. String p = decimalFormat.format(process);//format 返回的是字符串
  19. mExitDialog.setMsgText("当前进度:" + p + "%");
  20. }
  21. }
  22. });
  23. }
  24. @Override
  25. public void onFinish(final SegmentInfo[] segmentInfos, final RecordFileInfo recordFileInfo) {
  26. runOnUiThread(new Runnable() {
  27. @Override
  28. public void run() {
  29. Logger.e(TAG,"SegmentInfos:"+ Arrays.toString(segmentInfos)+
  30. ",--recordFileInfo:"+recordFileInfo.toString()+",--totleTime:"+recordTotalTime);
  31. insertVideoToMediaStore(RecordActivity.this, videoPath, System.currentTimeMillis(), videoRecordConfig.getVideoWidth(), videoRecordConfig.getVideoHeight(),
  32. recordTotalTime);
  33. if (mExitDialog != null && mExitDialog.isShowing()) {
  34. mExitDialog.dismiss();
  35. }
  36. Intent intent = new Intent(RecordActivity.this, ShowCombineRecordActivity.class);
  37. intent.putExtra("videoPath", videoPath);
  38. startActivity(intent);
  39. finish();
  40. }
  41. });
  42. }
  43. @Override
  44. public void onError() {
  45. RecordLogger.i(TAG, TAG + "joinAllSegment:onError()");
  46. }
  47. @Override
  48. public void onCancel() {
  49. }
  50. });
取消合成
  1. recordKit.cancelJoin();
释放资源
  1. recordKit.release();

更多详细接口请参考API接口文档及Demo

错误信息

对应消息
-999 时间戳错误
-998 调用不对
-997 配置参数不对
-899 参数错误
-797 创建线程错误
-794 打开编码器失败
-791 写文件失败
-786 音频数据错误

sdk文件日志

为便于接入时定位问题,在开发版本中已记录关键日志,推流相关的日志TAG为”QHVCRecordKit”。

打包混淆

  1. -keepclasseswithmembernames class * {
  2. native <methods>;
  3. }
  4. -keep class com.qihoo.livecloud.recordkit.** {
  5. <fields>;
  6. <methods>;
  7. }
即刻开始使用

只需完成注册与实名认证,即可体验我们的贴心服务