このトピックでは、カスタムビデオレンダリングを実装する方法について説明します。
機能説明
Alibaba Real-Time Communication (ARTC) には、市場で実績のあるビデオレンダリングモジュールが含まれています。組み込みモジュールは、安定した効率的なビデオ再生体験を提供します。
成熟した自社開発のレンダリングモジュールがある場合や、色精度やフレームレート制御に特定の要件がある場合、ARTC SDK は柔軟なインターフェイスを提供します。これらのインターフェイスを使用すると、カスタムビデオレンダリングモジュールを統合して、ビジネスニーズを満たすことができます。
前提条件
ビデオ設定を構成する前に、次の前提条件が満たされていることを確認してください。
有効な Alibaba Cloud アカウントで ApsaraVideo Real-time Communication アプリケーションを作成済みであること。詳細については、「アプリケーションの作成」をご参照ください。また、アプリケーション管理コンソールから App ID と App Key を取得する必要があります。
ARTC SDK をプロジェクトに統合し、基本的な音声・映像コミュニケーション機能を実装済みであること。SDK の統合に関する詳細については、「SDK のダウンロードと統合」をご参照ください。音声・映像通話の実装方法については、「音声・映像通話の実装」をご参照ください。
仕組み
リモートビデオレンダリング
バッファーベースのローカルビデオレンダリング
テクスチャ ID ベースのローカルビデオレンダリング
実装
Android の実装
1. オブザーバーの登録
まず、AliRtcEngine の registerVideoSampleObserver メソッドを呼び出して、カスタム処理オブザーバーを登録します。次に、AliRtcEngine.AliRtcVideoObserver 抽象クラスのメソッドを実装します。これにより、AliRtcEngine 処理パイプライン全体でレタッチを適用できます。
AliRtcVideoObserver の登録例:
mAliRtcEngine.registerVideoSampleObserver(mAliRtcVideoObserver);必要に応じて抽象インターフェイスを実装します。ARTC は、ローカルビデオキャプチャ後、ローカルエンコーディング前、リモートビデオデコーディング後の3つの段階でカスタム処理をサポートしています。
public enum AliRtcVideoObserPosition{
/*! キャプチャされたビデオデータ。onLocalVideoSample コールバックに対応します。*/
AliRtcPositionPostCapture(1),
/*! レンダリングされたビデオデータ。onRemoteVideoSample コールバックに対応します。*/
AliRtcPositionPreRender(2),
/*! エンコーディング前のビデオデータ。onPreEncodeVideoSample コールバックに対応します。*/
AliRtcPositionPreEncoder(4);
}public static abstract class AliRtcVideoObserver {
// サブスクライブしたローカルビデオキャプチャデータのコールバック。
public boolean onLocalVideoSample(AliRtcVideoSourceType sourceType, AliRtcVideoSample videoSample){
// TODO: ローカルビデオキャプチャ中にレタッチやエフェクトが必要な場合は、ここで処理します。
}
// サブスクライブしたリモートビデオデータのコールバック。
public boolean onRemoteVideoSample(String callId,AliRtcVideoSourceType sourceType, AliRtcVideoSample videoSample){
// TODO: リモートエンドからプルしたフレームを表示する前にレタッチやエフェクトが必要な場合は、ここで処理します。
}
// エンコーディング前のローカルビデオデータのコールバック。
public boolean onPreEncodeVideoSample(AliRtcVideoSourceType sourceType, AliRtcVideoSample videoRawData){
// TODO: ローカルビデオフレームをエンコーディングする前にレタッチやエフェクトが必要な場合は、ここで処理します。
}
...
public int onGetObservedFramePosition(){
// TODO: ビジネスニーズに基づいてコールバックのタイミングを指定します。上記で定義された AliRtcVideoObserPosition の値を使用します。
// 例えば、キャプチャ前とレンダリング前にカスタム処理を実行するには、次の値を定義します。
// return AliRtcVideoObserPosition.AliRtcPositionPostCapture.getValue() | AliRtcVideoObserPosition.AliRtcPositionPreRender.getValue();
}
}Queen SDK を使用するには、対応するインターフェイスでビデオストリームを処理する必要があります。
リスナーの登録解除
カスタム処理が不要になった場合は、リスナーの登録を解除して SDK レイヤーからの呼び出しを減らし、処理効率を向上させ、メモリリークを防ぎます。
// TODO: リソース解放タスクを実行します。
mAliRtcEngine.unRegisterVideoSampleObserver()2. カスタム処理の実装
前述のコールバックインターフェイスは、handleBeautyProcess メソッドを呼び出すことで実装できます。
private boolean handleBeautyProcess(AliRtcEngine.AliRtcVideoSample videoSample) {
if (!isAdvanceBeautifyOn) { // レタッチを有効にするかどうかを指定します。
return false;
}
if (mQueenBeautyImp == null) {
mQueenBeautyImp = new QueenBeautyImp(getContext(), videoSample.glContex);
}
return mQueenBeautyImp.onBeautyProcess(videoSample);
}QueenBeautyImp は QueenBeautyEffector のシンプルなラッパークラスです。
レタッチプロセッサの作成
プロセッサは次のように作成します。
// 複数作成を防ぐために同期ロックを追加します。
private synchronized void ensureQueenEngine(Context context, long glShareContext) {
if (mQueenBeautyEffector == null) {
try {
QueenConfig queenConfig = new QueenConfig();
bool isNeedCreateNewThread = glShareContext != 0; // 別のスレッドを作成するかどうかを指定します。テクスチャモードでは true、バッファーモードでは false に設定することを推奨します。
bool isNeedCreateNewGLContext = true; // GL コンテキストを作成するかどうかを指定します。テクスチャモードでは、この値を isNeedCreateNewThread と一致させてください。バッファーモードでは、true に設定することを推奨します。
queenConfig.withNewGlThread = isNeedCreateNewThread;
queenConfig.withContext = isNeedCreateNewGLContext;
queenConfig.shareGlContext = glShareContext;
// queenConfig.enableDebugLog = true; // デバッグ機能:ログを有効にします。
mQueenBeautyEffector = new QueenBeautyEffector(context, queenConfig);
// 高度なレタッチデバッグ機能。
// mQueenBeautyEffector.getEngine().enableFacePointDebug(true); // 顔のランドマークデバッグを有効にします。
// mQueenBeautyEffector.getEngine().enableFaceDetectGPUMode(false); // 顔認識の GPU モードを無効にします。
} catch (Exception ex) {
ex.printStackTrace();
}
}
}レタッチパラメーターの設定
private void updateQueenEngineParams() {
mQueenBeautyEffector.onUpdateParams(() -> {
QueenEngine queenEngine = mQueenBeautyEffector.getEngine();
// 肌の平滑化とシャープ化は1つのスイッチを共有します。
queenEngine.enableBeautyType(BeautyFilterType.kSkinBuffing, true); // 肌の平滑化スイッチ。
queenEngine.setBeautyParam(com.aliyun.android.libqueen.models.BeautyParams.kBPSkinBuffing, 0.85f); // 肌の平滑化。有効な値:[0,1]。
queenEngine.setBeautyParam(com.aliyun.android.libqueen.models.BeautyParams.kBPSkinSharpen, 0.2f); // シャープ化。有効な値:[0,1]。
// 美白と血色は1つのスイッチを共有します。
queenEngine.enableBeautyType(BeautyFilterType.kSkinWhiting, true); // 美白スイッチ。
queenEngine.setBeautyParam(BeautyParams.kBPSkinWhitening, 0.5f); // 美白。有効な値:[0,1]。
// 目の拡大と顔痩せ。
queenEngine.enableBeautyType(BeautyFilterType.kFaceShape, true);
queenEngine.updateFaceShape(FaceShapeType.typeBigEye,1.0f);
queenEngine.updateFaceShape(FaceShapeType.typeCutFace,1.0f);
});
}フレームの処理
コールバックデータの型に基づいて、データをテクスチャまたはバッファーとして処理します。
// マルチスレッド環境で mQueenBeautyEffector が破棄されるのを防ぐために同期ロックを追加します。
public synchronized boolean onBeautyProcess(AliRtcEngine.AliRtcVideoSample videoSample) {
// レタッチパラメーターを更新します。
updateQueenEngineParams();
boolean result = false;
if (videoSample.glContex != 0 && videoSample.textureid > 0) {
// テクスチャモード。
result = onProcessBeautyTexture(videoSample);
} else {
// バッファーモード。
result = onProcessBeautyBuffer(videoSample);
}
return result;
}テクスチャコールバックの処理:
private boolean onProcessBeautyTexture(AliRtcEngine.AliRtcVideoSample videoSample) {
boolean result = false;
boolean isOesTexture = videoSample.format == AliRtcEngine.AliRtcVideoFormat.AliRtcVideoFormatTextureOES;
// Android カメラでキャプチャされたテクスチャは、デフォルトで270度回転した横長の画像です。Queen SDK は幅と高さを自動的に入れ替えます。
// ただし、videoSample コールバックの幅と高さは ARTC SDK によってすでに修正されています。そのため、ここで手動で幅と高さを入れ替える必要があります。
int w = isOesTexture ? videoSample.height : videoSample.width;
int h = isOesTexture ? videoSample.width : videoSample.height;
int newTextId = mQueenBeautyEffector.onProcessTexture((int)videoSample.textureid, isOesTexture, videoSample.matrix, w, h, 270, 0, 0);
if (newTextId != videoSample.textureid) { // 0 は QueenResult.QUEEN_OK を示します。
// テクスチャ ID を変更します。
videoSample.textureid = newTextId;
videoSample.format = AliRtcEngine.AliRtcVideoFormat.AliRtcVideoFormatTexture2D;
result = true;
}
return result;
}バッファーコールバックの処理:
private boolean onProcessBeautyBuffer(AliRtcEngine.AliRtcVideoSample videoSample) {
boolean result = false;
int queenResult = mQueenBeautyEffector.onProcessDataBuf(videoSample.data, videoSample.data, ImageFormat.I420, videoSample.width, videoSample.height, 0, 0, 0, 0);
if (queenResult == 0) {
result = true;
}
return result;
}3. 終了とリソースの破棄
会議から退出するか、ビデオ通話インターフェイスを終了するときは、カスタム処理エンジンを速やかに破棄してください。
// マルチスレッド環境で mQueenBeautyEffector が破棄されるのを防ぐために同期ロックを追加します。
public synchronized void release() {
if (mQueenBeautyEffector != null) {
mQueenBeautyEffector.onReleaseEngine();
mQueenBeautyEffector = null;
}
}