ショートビデオSDKは、既存のサンプルビデオとカメラで撮影されているビデオで構成されるデュエットを録画するためのAliyunIMixRecorderクラスを提供します。 2つのビデオは、左右分割画面、上下分割画面、またはピクチャ・イン・ピクチャ (PiP) などの指定されたレイアウトで配置されます。 デュエット録画機能は、新しいローカルビデオトラックを追加するビデオ録画機能のアップグレード版です。
サポートされているエディション
エディション | 対応 |
Professional | 必須 |
標準 | 必須 |
基本 | 選択可能 |
用語
このセクションでは、デュエットレコーディング機能をよりよく理解するのに役立つ用語について説明します。 詳細については、「デュエット録音」、「トラック」、および「トラックレイアウト」をご参照ください。
関連クラス
クラス | 説明 |
録画、プレビュー設定、エフェクト設定、コールバック設定など、録画機能を定義するコアクラス。 | |
デュエット録音インスタンスの作成に使用されるファクトリクラス。 | |
トラック配置パラメータと出力パスパラメータを含むデュエット録音のパラメータを定義するクラス。 | |
トラックのレイアウト情報やレイアウト階層など、デュエット録音用のトラックを定義するクラス。 | |
ビデオの幅と高さ、エンコーダの種類、フレームレートなど、記録パラメータを定義するクラス。 | |
記録完了コールバック、記録進行コールバック、および記録エラーコールバックを含む、記録コールバックを定義するクラス。 | |
選択したプレビュー解像度のコールバック、カメラでキャプチャされたフレームデータのコールバック、カメラの有効化に失敗したときに発生するエラーのコールバックなど、データキャプチャのコールバックを定義するクラス。 | |
PCM形式のオーディオデータのコールバックを定義するクラス。 | |
たとえば、ビデオクリップを管理するクラスは、ビデオクリップを削除し、録画時間を設定します。 |
デュエット録音プロセス
デュエット録音には、カメラとマイクの権限が必要です。 さもなければ、記録は失敗する。
デュエット録画を設定する手順は、ビデオ録画を設定する手順と同様です。 主な違いは、設定する必要がある入出力パラメータとプレビュー設定にあります。
設定 | ステップ | 説明 | サンプルコード |
基本設定 | 1 | 録画インスタンスを作成および破棄し、録画パラメータを設定します。 | |
2 | コールバックを設定します。 | ||
3 | プレビュービューを設定し、プレビューを有効にします。 | ||
4 | ビデオクリップの録画を開始、キャンセル、または停止します。 | ||
5 | 記録を停止し、設定情報を生成します。 | ||
詳細構成 | 6 | カメラ制御とビデオクリップ管理のパラメーターを設定します。 カメラ制御のパラメータには、カメラタイプとフラッシュモードがあります。 ビデオクリップ管理のパラメータには、最大または最小の録画時間、ビデオクリップを削除する方法、ビデオクリップの数を照会する方法が含まれます。 ビジネス要件に基づいてこれらのパラメーターを設定します。 | |
7 | レタッチやフィルターなどの録音効果を設定します。 | ||
8 | 写真撮影または顔認識を設定します。 |
AliyunIMixRecorderクラスの初期化とパラメーターの設定
AliyunIMixRecorderクラスを初期化し、録音インスタンスを作成し、録音パラメーターを設定します。 コードで使用されるパラメーターの詳細については、「関連クラス」をご参照ください。
クラスの初期化
// Create a recording instance.
AliyunIMixRecorder recorder = AliyunMixRecorderCreator.createAlivcMixRecorderInstance(context);
// Destroy the recording instance.
// Destroy the recording instance if you no longer need to use the SDK, or before you exit the program. Do not destroy the recording instance during usage.
AliyunIMixRecorder.release();録画パラメータ
// Configure the quality of a recorded video.
AliyunIMixRecorder.setVideoQuality(quality);
// Configure the bitrate of the recorded video.
AliyunIMixRecorder.setVideoBitrate(int bitrate);// Unit: Kbit/s.
// Configure output parameters for the recorded video.
// inputMediaInfo indicates the parameters of the produced video, including track arrangement and output video. outputInfo indicates the information about the output video.
AliyunIMixRecorder.setMixMediaInfo(AliyunMixMediaInfoParam inputMediaInfo, MediaInfo outputInfo);// For more information, see AliyunMixMediaInfoParam and MediaInfo in the SDK references.
// Configure the output path of the recorded video.
AliyunIMixRecorder.setOutputPath(String path);
// Set the output group of pictures (GOP) of the recorded video.
AliyunIMixRecorder.setGop(int gop);// Unit: frames.コールバックの設定
コールバックを設定して、オーディオとビデオの処理の進行状況とステータスをタイムリーに取得できます。 コードで使用されるパラメーターの詳細については、「関連クラス」をご参照ください。
// Configure the recording callback.
AliyunIMixRecorder.setRecordCallBack(RecordCallback callBack);
// Configure the callback for video frame collection.
AliyunIMixRecorder.setOnFrameCallback(OnFrameCallBack callback);
// Configure the audio collection callback.
AliyunIMixRecorder.setOnAudioCallback(OnAudioCallBack callback);プレビューの有効化
プレビュー中に、SurfaceViewを設定する必要があります。 同時に、Activity/FragmentのonResume() でstartPreviewを行い、onPause() でstopPreviewを行います。 コードで使用されるパラメーターの詳細については、「関連クラス」をご参照ください。
// Configure the preview View.
// The cameraView parameter is the view of the camera, and the videoView parameter is the view of the local video.
AliyunIMixRecorder.setDisplayView(SurfaceView cameraView, Surface videoView);
// Start the preview.
AliyunIMixRecorder.startPreview();
// Stop the preview.
// Perform stopPreview in onPause() of Activity/Fragment.
AliyunIMixRecorder.stopPreview();録音を開始
実際の録画プロセスでは、必要な完全なビデオを録画するまで、ビデオを停止、キャンセル、再録画する必要があります。 録画を停止すると、ビデオクリップが生成されます。 ただし、録画をキャンセルした場合、現在のビデオクリップは保持されません。 コードで使用されるパラメーターの詳細については、「関連クラス」をご参照ください。
録音を開始
// Start recording.
AliyunIMixRecorder.startRecording();ビデオクリップ
// Start recording.
AliyunIMixRecorder.startRecording();
// Stop recording. A video clip is generated.
AliyunIMixRecorder.stopRecording();
AliyunIMixRecorder.startRecording();
// Cancel recording. The current video clip is not saved.
AliyunIMixRecorder.cancelRecording();
// Continue to record the next video clip.
AliyunIMixRecorder.startRecording();
AliyunIMixRecorder.stopRecording();録音を停止する
録画を停止すると、録画されたビデオクリップがビデオにマージされるか、録画されたビデオクリップに関する設定情報が生成されます。 コードで使用されるパラメーターの詳細については、「関連クラス」をご参照ください。
// Stop recording and merge the recorded video clips into one video.
AliyunIMixRecorder.finishRecording();
// Stop recording and generate the configuration information about the recorded video clips without merging the video clips.
AliyunIMixRecorder.finishRecordingForEdit();カメラの設定とビデオクリップの管理
このセクションでは、カメラ制御およびビデオクリップ管理のパラメーターを設定する方法について説明します。 カメラ制御のパラメータには、カメラタイプとフラッシュモードがあります。 ビデオクリップ管理のパラメータには、最大または最小の録画時間、ビデオクリップを削除する方法、ビデオクリップの数を照会する方法が含まれます。 ビジネス要件に基づいてこれらのパラメーターを設定します。 コードで使用されるパラメーターの詳細については、「関連クラス」をご参照ください。
カメラ
// Obtain the number of cameras.
AliyunIMixRecorder.getCameraCount();
// Configure the camera type.
AliyunIMixRecorder.setCamera(cameraType);
// Specify whether to mute the audio during recording.
AliyunIMixRecorder.setMute(boolean isMute);
// Configure the angle of the sensor.
// This configuration is very important. We recommend that you read the SDK references.
AliyunIMixRecorder.setRotation(int rotation);
// Configure the angle at which a video is recorded.
// This configuration is very important. We recommend that you read the SDK references.
AliyunIMixRecorder.setRecordRotation(int rotation);
// Configure the camera parameters during preview, including the flash mode, focus mode, zoom factor, and exposure level. You can also configure the preview parameters separately by using the following methods:
AliyunIMixRecorder.setCameraParam(CameraParam cameraParam);
// Switch between the front and rear cameras.
AliyunIMixRecorder.switchCamera();
// Configure the flash mode.
AliyunIMixRecorder.setLight(FlashType flashType);
// Configure the zoom factor.
AliyunIMixRecorder.setZoom(float rate);
// Configure the exposure level.
AliyunIMixRecorder.setExposureCompensationRatio(float value);
// Configure the focus mode.
AliyunIMixRecorder.setFocusMode(int mode);
// Configure manual focus.
AliyunIMixRecorder.setFocus(float xRatio, float yRatio);ビデオクリップ
// Obtain the clip manager.
AliyunIClipManager manager = AliyunIRecorder.getClipManager();
// Configure the maximum recording duration, which is the total duration of all video clips instead of a single video clip.
manager.setMaxDuration(int maxDurationMs);
// Configure the minimum recording duration, which is the total duration of all video clips instead of a single video clip.
manager.setMinDuration(int minDurationMs);
// Delete the last video clip.
manager.deletePart();
// Delete the specified video clip.
manager.deletePart(int index);
// Delete all video clips.
manager.deleteAllPart();
// Obtain the total duration of video clips.
manager.getDuration();
// Obtain the total number of video clips.
manager.getPartCount();
// Obtain the paths of video clips.
manager.getVideoPathList();エフェクトの設定
このセクションでは、レタッチやフィルターなどの記録効果を設定する方法について説明します。 コードで使用されるパラメーターの詳細については、「関連クラス」をご参照ください。
フィルター
カスタムフィルターを作成できます。 詳細については、「フィルターとトランジション」をご参照ください。
// Apply a filter.
AliyunIMixRecorder.applyFilter(effectFilter);
// Remove a filter.
// If the setting is the same as the following, the filter effect is removed.
AliyunIMixRecorder.applyFilter(new EffectFilter(null));アニメーションフィルター
// Apply an animated filter.
AliyunIMixRecorder.applyAnimationFilter(effectFilter);
// Remove an animated filter.
AliyunIMixRecorder.removeAnimationFilter(effctFilter);記録速度
// Configure the recording speed.
AliyunIMixRecorder.setRate(float rate);静的ステッカーと静的透かし
// Add a static watermark or a static sticker.
AliyunIMixRecorder.addImage(effctImage);
// Remove a static watermark or a static sticker.
AliyunIMixRecorder.removeImage(effctImage);
// Update the position of a static watermark or a static sticker.
AliyunIMixRecorder.setEffectView(float xRatio,float yRatio,float widthRatio,float heightRatio,EffectBase effectBase);アニメーションステッカー
カスタムアニメーションステッカーを作成できます。 詳細については、「アニメーション」をご参照ください。
// Add an animated sticker.
AliyunIMixRecorder.addPaster(effectPaster,float sx,float sy,float sw,float sh,float rotation,boolean flip);
// Remove an animated sticker.
AliyunIMixRecorder.removePaster(effectPaster);
// Update the position of an animated sticker.
AliyunIMixRecorder.setEffectView(float xRatio,float yRatio,float widthRatio,float heightRatio,effectBase);高度なレタッチ
ビデオ録画モジュールは、基本的な組み込みレタッチ機能を提供するだけでなく、Alibaba Cloud Queen SDKやFaceUnityなどのレタッチSDKの使用もサポートしています。 組み込みのレタッチ機能を使用して、レタッチレベルのみを設定できます。 レタッチSDKは、顔のレタッチ、顔の整形、メイクアップ、フィルター、ステッカーなど、豊富なレタッチ効果を提供します。
レタッチ
// Enable or disable retouching. AliyunIMixRecorder.setBeautyStatus(boolean on); // Configure the retouching level. AliyunIMixRecorder.setBeautyLevel(int level);SDKのレタッチ
レタッチSDKが提供するエフェクトをショートビデオSDKで使用するには、最初にレタッチSDKの権限を取得し、レタッチSDKをショートビデオSDKに統合する必要があります。
カメラテクスチャIDとカメラローフレームは、レタッチ効果を実装するためにSDKをレタッチするために必要です。 次のサンプルコードでは、カメラテクスチャIDとカメラrawフレームの取得方法の例を示します。
カメラテクスチャID
AliyunIMixRecorder.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() { // For a version of the short video SDK that is earlier than V3.7.8, you can destroy gl resources for third-party custom rendering by using GLSurfaceView.queueEvent in GLSurfaceView. For a version of the short video SDK that is V3.7.8 or later than V3.7.8, we recommend that you destroy gl resources in this callback. if (mBeautyInterface != null) { mBeautyInterface.release(); mBeautyInterface = null; } } });カメラのrawフレーム
AliyunIMixRecorder.setOnFrameCallback(new OnFrameCallBack() { @Override public void onFrameBack(byte[] bytes, int width, int height, Camera.CameraInfo info) { // The data type of the callback raw data is NV21. The obtained raw data is used by 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 (ビットマップ) またはRecordCallback.onPictureDataBack(byte[]) を使用してデータが返されます。
// Take a photo with effects enabled.
AliyunIMixRecorder.takePhoto(boolean needBitmap);
// Take a photo by using the default camera settings. The default camera settings do not support effects.
AliyunIMixRecorder.takePicture(boolean needBitmap);
// Configure the size of a photo. This method is supported only if you take a photo by using the default camera settings.
AliyunIMixRecorder.setPictureSize(Camera.Size size);顔認識
顔認識を使用する場合は、アプリケーションの組み込み顔認識モデルにアクセスする必要があります。 参考のために顔認識モデルのデモをダウンロードできます。
// Specify whether to enable facial recognition.
AliyunIMixRecorder.needFaceTrackInternal(boolean need);
// Configure the path of the facial recognition model file.
AliyunIMixRecorder.setFaceTrackInternalModelPath(String path);
// Configure the angle at which facial recognition is performed.
// This configuration is very important. We recommend that you read the SDK references.
AliyunIMixRecorder.setFaceDetectRotation(int rotation);
// Configure the maximum number of faces that can be recognized at the same time.
// Configure the maximum number of faces that can be recognized at the same time. Maximum value: 3.
AliyunIMixRecorder.setFaceTrackInternalMaxFaceCount(int maxFaceCount);
// Add an animated face sticker.
AliyunIMixRecorder.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.common.VideoDisplayMode
import com.aliyun.svideosdk.common.struct.encoder.VideoCodecs
import com.aliyun.svideosdk.common.struct.recorder.MediaInfo
import com.aliyun.svideosdk.mixrecorder.AliyunIMixRecorder
import com.aliyun.svideosdk.mixrecorder.AliyunMixMediaInfoParam
import com.aliyun.svideosdk.mixrecorder.AliyunMixRecorderDisplayParam
import com.aliyun.svideosdk.mixrecorder.AliyunMixTrackLayoutParam
import com.aliyun.svideosdk.mixrecorder.impl.AliyunMixRecorderCreator
import com.aliyun.svideosdk.recorder.RecordCallback
/**
* Sample code for video recording
*/
class MixRecordActivity : AppCompatActivity() {
enum class RecordStatus {
Idle,
Recording
}
private lateinit var mAliyunRecord : AliyunIMixRecorder
private lateinit var mVideoPreviewView : SurfaceView
private lateinit var mCameraPreviewView : SurfaceView
private lateinit var mRecordBtn : ImageView
private var mRecordStatus = RecordStatus.Idle
companion object {
const val TAG = "MixRecordActivity"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mixrecord)
mVideoPreviewView = findViewById(R.id.videoPreviewView)
mCameraPreviewView = findViewById(R.id.cameraPreviewView)
mRecordBtn = findViewById(R.id.btnRecordControl)
// Start recording.
mRecordBtn.setOnClickListener {
if(mRecordStatus == RecordStatus.Recording) {
mAliyunRecord.finishRecording()
Toast.makeText(this@MixRecordActivity, "Stop recording", Toast.LENGTH_SHORT).show()
updateRecordStatus(RecordStatus.Idle)
} else {
val curTime = System.currentTimeMillis()
mAliyunRecord.setOutputPath("/storage/emulated/0/DCIM/Camera/svideo_mixrecord_video_$curTime.mp4")
mAliyunRecord.startRecording()
Toast.makeText(this@MixRecordActivity, "Start recording", Toast.LENGTH_SHORT).show()
updateRecordStatus(RecordStatus.Recording)
}
}
mAliyunRecord = AliyunMixRecorderCreator.createAlivcMixRecorderInstance(this)
val videoDisplayParam = AliyunMixRecorderDisplayParam.Builder()
.displayMode(VideoDisplayMode.FILL)
.layoutParam(
AliyunMixTrackLayoutParam.Builder()
.centerX(0.25f)
.centerY(0.5f)
.widthRatio(0.5f)
.heightRatio(1.0f)
.build()
)
.build()
val cameraDisplayParam = AliyunMixRecorderDisplayParam.Builder()
.displayMode(VideoDisplayMode.FILL)
.layoutParam(AliyunMixTrackLayoutParam.Builder()
.centerX(0.75f)
.centerY(0.5f)
.widthRatio(0.5f)
.heightRatio(1.0f)
.build())
.build()
val mixMediaParam = AliyunMixMediaInfoParam.Builder()
.streamStartTimeMills(0L)
.streamEndTimeMills(0L) // If you set streamStartTimeMills and streamEndTimeMills to 0L, the duration of the video is automatically used.
.mixVideoFilePath("/storage/emulated/0/DCIM/Camera/VID_20210317_174802.mp4")
.mixDisplayParam(videoDisplayParam)
.recordDisplayParam(cameraDisplayParam)
.build()
val mediaInfo = MediaInfo()
mediaInfo.fps = 30
mediaInfo.crf = 6
mediaInfo.videoWidth = 720
mediaInfo.videoHeight = 1080
mediaInfo.videoCodec = VideoCodecs.H264_SOFT_OPENH264
mAliyunRecord.setMixMediaInfo(mixMediaParam, mediaInfo)
mAliyunRecord.setDisplayView(mCameraPreviewView, mVideoPreviewView)
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")
mAliyunRecord.clipManager.deleteAllPart()
}
override fun onProgress(progress: Long) {
Log.i(TAG, "onProgress : $progress")
}
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")
}
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.release()
}
}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">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<SurfaceView
android:id="@+id/videoPreviewView"
android:layout_width="0dp"
android:layout_height="400dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="0dp" />
<SurfaceView
android:id="@+id/cameraPreviewView"
android:layout_width="0dp"
android:layout_height="400dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline3"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:id="@+id/btnRecordControl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="50dp"
android:src="@mipmap/alivc_svideo_bg_record_start"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
</ImageView>
</androidx.constraintlayout.widget.ConstraintLayout>