短视频SDK提供基础视频录制,同时支持添加配乐,变速录制,人脸贴纸等录制效果。

版本支持

版本 是否支持
专业版 支持
标准版 支持
基础版 支持

相关类功能

类名 功能
AliyunIRecorder 录制功能核心类,包括录制、设置预览、设置特效、设置回调等核心录制功能。
AliyunRecorderCreator 工厂类,用于获取录制实例。
MediaInfo 录制参数配置类,包括设置视频的宽高、编码器类型、录制采集帧率等录制参数。
RecordCallback 录制回调接口,包括设置录制完成回调、录制进度回调及录制错误回调等。
OnFrameCallBack 相机采集数据回调接口,包括选择预览分辨率的回调、采集帧回调及摄像头开启失败的回调。
OnAudioCallBack 音频回调接口,设置音频pcm数据回调。
AliyunIClipManager 视频录制片段管理接口,包括删除片段、设置录制时长等。

录制流程

说明 录制功能需要获取摄像头和麦克风权限,否则无法录制。
阶段 流程 说明 代码示例
基础 1 创建及销毁录制接口,并配置录制参数。 初始化及参数配置
2 回调设置。 回调设置
3 创建开始预览和结束预览。 开启预览
4 创建开始录制片段、取消录制片段、停止录制片段。 开始录制
5 创建结束录制相关信息。 结束录制
进阶 6 配置录制相机控制相关参数(设置摄像头类型、设置闪光灯模式等)及录制片段管理相关参数(配置录制最大或最小时长、删除录制片段、获取录制片段数量等),可按需配置。 录制控制及管理
7 配置美颜、滤镜、背景音乐等录制特效,可按需配置。 设置特效
8 设置拍照或人脸识别。 其他功能

初始化及参数配置

初始化AliyunIRecorder类,创建录制接口,并配置录制参数。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

初始化
//创建录制接口
AliyunIRecorder recorder = AliyunRecorderCreator.getRecorderInstance(context);//参数context为当前页面的上下文

//销毁录制接口
//不再使用SDK或者程序退出前销毁录制接口,请务必保证不要中途销毁
recorder.destroy();
配置录制参数
//设置录制视频的质量
recorder.setVideoQuality(quality);

//设置录制视频的码率
recorder.setVideoBitrate(int bitrate);//单位:Kbps

//设置录制视频输出参数
recorder.setMediaInfo(mediaInfo);//相关参数描述请参考MediaInfo的接口文档

//设置录制视频的输出路径
recorder.setOutputPath(string path);

//设置录制视频的输出GOP
recorder.setGop(int gop);//单位:帧数

回调设置

通过设置回调,及时获取音视频处理的进展和状态。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

//设置录制回调
recorder.setRecordCallBack(RecordCallback callBack);

//设置视频帧采集回调
recorder.setOnFrameCallback(OnFrameCallBack callback);

//设置音频采集数据的回调
recorder.setOnAudioCallback(OnAudioCallBack callback);

开启预览

预览时,需要设置相对应的SurfaceView容器,同时,在Activity/Fragment的onResume()时进行startPreview,在onPause()进行stopPreview。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

//设置预览View
recorder.setDisplayView(SurfaceView displayView);

//开始预览
recorder.startPreview();

//结束预览
//在Activity/Fragment的onPause()时进行stopPreview
recorder.stopPreview();

开始录制

在实际录制过程中,常常不能一次就能录制完成所需视频,而总是不断的停止、取消和重新录制。停止录制时会生成一个视频片段,而取消录制则不会保留当前录制的视频片段。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

开始录制
//开始录制
recorder.startRecording();
录制片段
//开始录制
recorder.startRecording();

//停止录制,生成一个视频片段
recorder.stopRecording();

recorder.startRecording();
// 取消录制,当前的视频片段不会保存
recorder.cancelRecording();

//继续录制下一个视频片段
recorder.startRecording();
recorder.stopRecording();

结束录制

结束录制时可生成一个片段拼接的视频或只生成片段视频的配置信息。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

//结束录制,并且将录制片段视频拼接成一个视频
recorder.finishRecording();

//结束录制,生成片段视频的配置信息(不拼接片段)
recorder.finishRecordingForEdit();

录制控制及管理

配置录制相机控制相关参数(设置摄像头类型、设置闪光灯模式等)及录制片段管理相关参数(配置录制最大或最小时长、删除录制片段、获取录制片段数量等),可按需配置。

代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

录制摄像头控制
//获取摄像头数量
AliyunIRrecorder.getCameraCount();

//设置摄像头类型
AliyunIRecorder.setCamera(cameraType);

//设置静音录制
AliyunIRecorder.setMute(boolean isMute);

//设置传感器角度值
//(非常重要,建议仔细阅读接口文档) 
AliyunIRecorder.setRotation(int rotation);

//设置录制视频的角度
//(非常重要,建议仔细阅读接口文档) 
AliyunIRecorder.setRecordRotation(int rotation);

//设置摄像头预览参数(闪光灯、对焦模式、Zoom、曝光度),也可参考下面的接口单独设置各预览参数
AliyunIRecorder.setCameraParam(CameraParam cameraParam);

//切换摄像头
AliyunIRecorder.switchCamera();

//设置闪光灯模式
AliyunIRecorder.setLight(flashType);

//设置Zoom 
AliyunIRecorder.setZoom(float rate);

//设置曝光度 
AliyunIRecorder.setExposureCompensationRatio(float value);

//设置对焦模式 
AliyunIRecorder.setFocusMode(int mode);

//手动对焦 
AliyunIRecorder.setFocus(float xRatio, float yRatio);
录制片段管理
//获取片段管理器
AliyunIClipManager manager = AliyunIRecorder.getClipManager();

//设置最大录制时长(总录制时长,非单个片段的最大时长)
manager.setMaxDuration(int maxDurationMs);

//设置最小录制时长(总录制时长,非单个片段的最小时长)
manager.setMinDuration(int minDurationMs);

//删除最后一段片段
manager.deletePart();

//删除指定的片段
manager.deletePart(int index);

//删除所有片段
manager.deleteAllPart();

//获取片段总时长
manager.getDuration();

//获取总的片段数量
manager.getPartCount();

//获取片段路径列表
manager.getVideoPathList();

设置特效

配置美颜、滤镜、背景音乐等录制特效,可按需配置。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

滤镜

支持自定义滤镜,滤镜的制作方法请参见滤镜及转场
//设置滤镜
AliyunIRecorder.applyFilter(EffectFilter effectFilter);//参数路径设置为null表示移除滤镜效果

//移除滤镜
AliyunIRecorder.applyFilter(new EffectFilter(null));
动效滤镜
//设置动效滤镜
AliyunIRecorder.applyAnimationFilter(EffectFilter effectFilter);

//移除动效滤镜
AliyunIRecorder.removeAnimationFilter(EffectFilter effctFilter);
背景音乐
//设置背景音乐
AliyunIRecorder.setMusic(String path,long startTime,long duration);

//移除背景音乐
AliyunIRecorder.setMusic(null, 0, 0);
变速
//设置录制速度
AliyunIRecorder.setRate(float rate);
静态贴纸/水印
//添加静态贴纸/水印
AliyunIRecorder.addImage(EffectImage effctImage);

//移除静态贴纸/水印
AliyunIRecorder.removeImage(EffectImage effctImage);

//更新静态贴纸/水印位置
AliyunIRecorder.setEffectView(float xRatio,float yRatio,float widthRatio,float heightRatio,EffectBase effectBase);

动态贴纸

支持自定义动态贴纸,动态贴纸的制作方法请参见动图
//添加动态贴纸
AliyunIRecorder.addPaster(EffectPaster effectPaster,float sx,float sy,float sw,float sh,float rotation,boolean flip);

//移除动态贴纸
AliyunIRecorder.removePaster(EffectPaster effectPaster);

//更新动态贴纸位置
AliyunIRecorder.setEffectView(float xRatio,float yRatio,float widthRatio,float heightRatio,EffectBase effectBase);

高级美颜

视频录制模块,提供了基础的内置美颜功能,同时也支持使用外置的美颜SDK功能,如阿里云美颜特效SDK、相芯科技(FaceUnity)等美颜SDK。内置美颜功能相对比较简单,仅能设置不同的美颜等级;外置美颜SDK通常提供了更为丰富的美颜、美型、美妆美化、滤镜贴纸等功能。
  • 内置美颜
    //设置美颜开关
    AliyunIRecorder.setBeautyStatus(boolean on);
    
    //设置美颜程度
    AliyunIRecorder.setBeautyLevel(int level);
  • 外置美颜SDK
    想要在短视频SDK中使用外置美颜SDK所提供的特效,则需要提前获取相应外置美颜SDK的权限并将外置美颜SDK集成接入到短视频SDK中。
    • 阿里云美颜特效SDK的集成接入等相关操作请参见美颜特效SDK。特效设置代码示例请参见使用示例
    • FaceUnity的购买、集成、使用等相关操作,请参见FaceUnity
    外置美颜SDK需要获取两个数据用于实现美颜功能:相机纹理ID和相机原始帧数据。以下代码展示如何获取相机纹理ID和相机原始帧数据。
    • 获取相机纹理ID数据
      AliyunIRecorder.setOnTextureIdCallback(new OnTextureIdCallBack() {
                  @Override
                  public int onTextureIdBack(int textureId, int textureWidth, int textureHeight, float[] matrix) {
                      if (mBeautyInterface != null) {
                          return mBeautyInterface.onTextureIdBack(textureId, textureWidth, textureHeight, matrix, mControlView.getCameraType().getType());
                      }
                      return textureId;
                  }
      
                  @Override
                  public int onScaledIdBack(int scaledId, int textureWidth, int textureHeight, float[] matrix) {
      
                      return scaledId;
                  }
      
                  @Override
                  public void onTextureDestroyed() {
                      //关于自定义渲染(第三方渲染)销毁gl资源,SDK3.7.8之前版本,GLSurfaceView时可以通过GLSurfaceView.queueEvent来销毁gl资源;SDK3.7.8及之后版本开始,推荐在此回调中统一销毁gl资源
                      if (mBeautyInterface != null) {
                          mBeautyInterface.release();
                          mBeautyInterface = null;
                      }
                  }
              });
    • 获取相机原始帧数据
      AliyunIRecorder.setOnFrameCallback(new OnFrameCallBack() {
                  @Override
                  public void onFrameBack(byte[] bytes, int width, int height, Camera.CameraInfo info) {
                      //原始数据回调NV21,此处获取原始数据主要是提供给FaceUnity高级美颜使用
                      if (mBeautyInterface != null) {
                          mBeautyInterface.onFrameBack(bytes, width, height, info);
                      }
                  }
      
                  @Override
                  public Camera.Size onChoosePreviewSize(List<Camera.Size> supportedPreviewSizes,
                                                         Camera.Size preferredPreviewSizeForVideo) {
                      return null;
                  }
      
                  @Override
                  public void openFailed() {
                      
                  }
              });

其他功能

支持录制视频时拍照及人脸识别。代码中需要使用的参数详情,请参考接口文档。接口链接请参见相关类功能

拍照

拍照分为带特效拍照及系统拍照(不带特效),拍照后会通过RecordCallback.onPictureBack(Bitmap)或者RecordCallback.onPictureDataBack(byte[]) 返回数据。
//带特效拍照
AliyunIRecorder.takePhoto(boolean needBitmap);

//系统拍照(不带特效)
AliyunIRecorder.takePicture(boolean needBitmap);

//设置系统拍照的照片大小(仅系统拍照支持,带特效拍照不支持)
AliyunIRecorder.setPictureSize(Camera.Size size);

人脸识别

人脸识别时,需要接入APP自行内置的人脸识别模型文件 ,可参考人脸识别模型文件Demo来设置。
//开启人脸识别
AliyunIRecorder.needFaceTrackInternal(boolean need);

//设置人脸识别模型文件
AliyunIRecorder.setFaceTrackInternalModelPath(String path);

//设置人脸识别角度
//(非常重要,建议仔细阅读接口文档) 
AliyunIRecorder.setFaceDetectRotation(int rotation);

//设置人脸识别数量
//设置内置人脸识别的最大识别数,最大为3个
AliyunIRecorder.setFaceTrackInternalMaxFaceCount(int maxFaceCount);

//添加人脸动图
AliyunIRecorder.addPaster(EffectPaster effectPaster);

基础录制代码示例

import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.aliyun.svideosdk.common.struct.recorder.MediaInfo;
import com.aliyun.svideosdk.recorder.AliyunIRecorder;
import com.aliyun.svideosdk.recorder.RecordCallback;
import com.aliyun.svideosdk.recorder.impl.AliyunRecorderCreator;
import com.svideo.guide.R;
import java.io.FileOutputStream;

/**
 * 视频录制Example
 */
class RecordActivity : AppCompatActivity() {

    enum class RecordStatus {
        Idle,
        Recording
    }

    private lateinit var mAliyunRecord : AliyunIRecorder
    private lateinit var mCameraViiew : SurfaceView
    private lateinit var mRecordBtn : ImageView
    private var mRecordStatus = RecordStatus.Idle

    companion object {
        const val TAG = "RecordActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_record)

        mCameraViiew = findViewById(R.id.cameraPreviewView)
        mRecordBtn = findViewById(R.id.btnRecordControl)
        //录制按钮
        mRecordBtn.setOnClickListener {
            if(mRecordStatus == RecordStatus.Recording) {
                mAliyunRecord.stopRecording()
                Toast.makeText(this@RecordActivity, "结束录制", Toast.LENGTH_SHORT).show()
                updateRecordStatus(RecordStatus.Idle)
            } else {

                mAliyunRecord.takePhoto(true)
            }

        }

        mRecordBtn.setOnLongClickListener {
            if(mRecordStatus == RecordStatus.Idle) {
                val curTime = System.currentTimeMillis()
                mAliyunRecord.setOutputPath("/storage/emulated/0/DCIM/Camera/svideo_record_video_$curTime.mp4")
                mAliyunRecord.startRecording()
                Toast.makeText(this@RecordActivity, "开始录制", Toast.LENGTH_SHORT).show()
                updateRecordStatus(RecordStatus.Recording)
            }
            true
        }

        mAliyunRecord = AliyunRecorderCreator.getRecorderInstance(this)
        val mediaInfo = MediaInfo()
        mediaInfo.fps = 30
        mediaInfo.crf = 6
        mediaInfo.videoWidth = 720
        mediaInfo.videoHeight = 1080

        mAliyunRecord.setMediaInfo(mediaInfo)
        mAliyunRecord.setDisplayView(mCameraViiew)

        mAliyunRecord.setRecordCallBack(object : RecordCallback {
            override fun onComplete(validClip: Boolean, clipDuration: Long) {
                Log.i(TAG, "onComplete")
            }

            override fun onFinish(outputPath: String?) {
                Log.i(TAG, "onFinish path : $outputPath")
            }

            override fun onProgress(duration: Long) {
            }

            override fun onMaxDuration() {
                Log.i(TAG, "onMaxDuration")
            }

            override fun onError(errorCode: Int) {
                Log.i(TAG, "onError : $errorCode")
            }

            override fun onInitReady() {
                Log.i(TAG, "onInitReady")
            }

            override fun onDrawReady() {
                Log.i(TAG, "onDrawReady")
            }

            override fun onPictureBack(bitmap: Bitmap?) {
                Log.i(TAG, "onPictureBack")
                val curTime = System.currentTimeMillis()
                val outputFile = "/storage/emulated/0/DCIM/Camera/svideo_record_photo_$curTime.png"
                val outputStream = FileOutputStream(outputFile)
                bitmap?.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
                outputStream.flush()
                outputStream.close()

                runOnUiThread {
                    Toast.makeText(this@RecordActivity, "图片已保存到相册", Toast.LENGTH_SHORT).show()
                }
            }

            override fun onPictureDataBack(p0: ByteArray?) {
                Log.i(TAG, "onPictureDataBack")
            }

        })



    }

    private fun updateRecordStatus(recordStatus: RecordStatus)
    {
        mRecordStatus = recordStatus
        when(recordStatus) {
            RecordStatus.Idle -> {
                mRecordBtn.setImageResource(R.mipmap.alivc_svideo_bg_record_start)
            }
            RecordStatus.Recording -> {
                mRecordBtn.setImageResource(R.mipmap.alivc_svideo_bg_record_storp)
            }
        }
    }

    override fun onResume() {
        super.onResume()
        mAliyunRecord.startPreview()
    }

    override fun onPause() {
        super.onPause()
        mAliyunRecord.stopPreview()
    }

    override fun onDestroy() {
        super.onDestroy()
        mAliyunRecord.destroy()
    }
}

XML文件配置示例

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <SurfaceView
        android:id="@+id/cameraPreviewView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </SurfaceView>

    <ImageView
        android:id="@+id/btnRecordControl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="50dp"
        android:src="@mipmap/alivc_svideo_bg_record_storp"
        android:visibility="visible">

    </ImageView>


</androidx.constraintlayout.widget.ConstraintLayout>