リアルタイムコミュニケーション (RTC) セッション中に、SDK からの生ビデオデータを処理したり、処理パイプラインのさまざまな段階でデータにアクセスしたりできます。このトピックでは、ビデオオブザーバーを使用してこのデータにアクセスし、処理する方法について説明します。
ユースケース
カスタムビデオデータ処理の一般的なユースケースは次のとおりです。
カスタムレタッチ: ローカルビデオストリームを取得し、サードパーティのレタッチ SDK を使用して処理してから、チャンネル内の他のユーザーに送信します。
カスタムビデオ編集: 特殊効果、ウォーターマーク、トリミング、クリッピングの追加など、処理パイプラインのさまざまな段階でビデオストリームを編集します。変更されたストリームは、ブロードキャストまたは保存できます。
ストリームのプレビューまたはモニタリング: ローカルまたはクラウドベースのモニタリングとプレビューのために、処理パイプラインのさまざまな段階でビデオストリームを取得します。ビデオストリームのコンテンツ、品質、ステータスをリアルタイムで監視して、適切な伝送と再生を確保できます。
始める前に
次の準備が完了していることを確認してください。
ARTC アプリケーションを作成し、ApsaraVideo Live コンソールから AppID と AppKey を取得します。
仕組み
ビデオキャプチャ:
デコードとレンダリング:
ARTC SDK は、ビデオ処理パイプラインのさまざまな段階でオブザベーションポイントを提供します。
オブザベーションポイントは、次のコールバックに対応しています。
オブザベーションポイント 1: キャプチャ直後に
onCaptureVideoSample(iOS) またはonLocalVideoSample(Android) を介して、スケーリングされていない元のビデオフレームデータを取得します。オブザベーションポイント 2:
onPreEncodeVideoSampleを介してエンコード前のデータを取得します。オブザベーションポイント 3:
onRemoteVideoSampleを介してデコードされたデータを取得します。オブザベーションポイント 4:
onTextureCreateを介して OpenGL コンテキスト (glcontext) を取得し、レタッチモジュールにバインドします。オブザベーションポイント 5:
onTextureUpdateを介して更新されたテクスチャデータを受信し、効果を適用します。オブザベーションポイント 6:
onTextureDestroyを介してglcontextを解放する通知を受信します。
観測ポイント 1、2、および 3 の場合、
trueを返すと、データを変更したことを示します。falseを返すと、元のデータは変更されません。観測ポイント 5 の場合、メソッドは有効な
textureIdを返す必要があります。新しいtextureIdを返すと、SDK は変更されたテクスチャをエンコーディングと処理に使用するように指示します。カスタム処理を実行しない場合は、元のtextureIdを返します。
実装
Android
ビデオフレームコールバック
1. コールバックの登録
生ビデオデータを受信するには、AliRtcEngine.AliRtcVideoObserver インターフェイスを実装し、registerVideoSampleObserver() メソッドを呼び出してインスタンスを登録します。
public abstract void registerVideoSampleObserver(AliRtcVideoObserver observer);2. オブザベーションポイントの指定
SDK は、このメソッドから返されるビットマスクに基づいて、トリガーするコールバックを決定します。
public enum AliRtcVideoObserPosition{
/*! ローカルでキャプチャされたビデオデータ、onLocalVideoSample コールバックに対応 */
AliRtcPositionPostCapture(1),
/*! デコードされたリモートビデオデータ、onRemoteVideoSample コールバックに対応 */
AliRtcPositionPreRender(2),
/*! エンコード前のビデオデータ、onPreEncodeVideoSample コールバックに対応 */
AliRtcPositionPreEncoder(4);
}
public int onGetObservedFramePosition(){
return AliRtcVideoObserPosition.AliRtcPositionPostCapture.getValue() | AliRtcVideoObserPosition.AliRtcPositionPreRender.getValue();
}3. 出力フォーマットの指定
/**
* @brief ビデオデータ形式
*/
public enum AliRtcVideoFormat{
AliRtcVideoFormatUNKNOW(-1),
AliRtcVideoFormatBGRA(0),
AliRtcVideoFormatI420(1),
AliRtcVideoFormatNV21(2),
AliRtcVideoFormatNV12 (3),
AliRtcVideoFormatRGBA(4),
AliRtcVideoFormatI422 (5),
AliRtcVideoFormatARGB(6),
AliRtcVideoFormatABGR (7),
AliRtcVideoFormatRGB24(8),
AliRtcVideoFormatBGR24(9),
AliRtcVideoFormatRGB565(10),
AliRtcVideoFormatTextureOES(11),
AliRtcVideoFormatTexture2D(12),
AliRtcVideoFormatH264(13),
AliRtcVideoFormatH265(14),
AliRtcVideoFormatFile(15);
};
/*
* SDK は AliRtcEngine::registerVideoSampleObserver を呼び出した後にこのメソッドを呼び出します。
*/
/**
* @brief ビデオデータの出力フォーマット
* @return 目的のビデオ出力フォーマット。{@link AliRtcVideoFormat} をご参照ください。
*/
public AliRtcVideoFormat onGetVideoFormatPreference(){
return AliRtcVideoFormat.AliRtcVideoFormatI420;
}4. メモリ配置の指定
public enum AliRtcVideoObserAlignment{
/*! 元のビデオ幅を維持 (デフォルト) */
AliRtcAlignmentDefault(0),
/*! ストライドを 2 バイトの倍数に配置 */
AliRtcAlignmentEven(1),
/*! ストライドを 4 バイトの倍数に配置 */
AliRtcAlignment4(2),
/*! ストライドを 8 バイトの倍数に配置 */
AliRtcAlignment8(3),
/*! ストライドを 16 バイトの倍数に配置 */
AliRtcAlignment16(4);
};
/*
* SDK は AliRtcEngine::registerVideoSampleObserver を呼び出した後にこのメソッドを呼び出します。
*/
public int onGetVideoAlignment(){
return AliRtcVideoObserAlignment.AliRtcAlignmentDefault.getValue();
}5. ミラー効果を適用するかどうかの指定
public boolean onGetObserverDataMirrorApplied(){
return false;
}6. コールバックの実装
/*
* 変更を SDK の処理パイプラインに書き戻すには true を返します。
* これは AliRtcVideoSample.data を変更する場合に必要です。
*/
@Override
public boolean onLocalVideoSample(AliRtcEngine.AliRtcVideoSourceType sourceType, AliRtcEngine.AliRtcVideoSample videoSample) {
boolean ret = false;
/*
* ローカルでキャプチャされたデータを処理します。
*/
return ret;
}
@Override
public boolean onRemoteVideoSample(String userId, AliRtcEngine.AliRtcVideoSourceType sourceType, AliRtcEngine.AliRtcVideoSample videoSample) {
/*
* リモートユーザーからデコードされたデータを処理します。
*/
return false;
}
@Override
public boolean onPreEncodeVideoSample(AliRtcEngine.AliRtcVideoSourceType aliVideoSourceType, AliRtcEngine.AliRtcVideoSample videoSample) {
boolean ret = false;
/*
* エンコード前のデータを処理します。
*/
return false ;
}7. コールバックの登録解除
ビデオフレームを監視する必要がなくなったら、オブザーバーの登録を解除して不要な処理を回避します。
unregisterVideoSampleObserverテクスチャ処理
テクスチャ関連のすべてのコールバックは、同じ専用の OpenGL スレッドで呼び出されます。これらを使用するには、AliRtcTextureObserver インターフェイスを実装します。
前提条件
エンジンを初期化するときに次のオプションを設定して、テクスチャキャプチャとテクスチャエンコーディングを有効にします。
String extras = "{\"user_specified_camera_texture_capture\":\"TRUE\",\"user_specified_texture_encode\":\"TRUE\" }";
_engine = AliRtcEngine.getInstance(getApplicationContext(), extras);
1. テクスチャコールバックの登録
public abstract void registerLocalVideoTextureObserver(AliRtcTextureObserver observer);2. コールバックの実装
OpenGL コンテキスト作成後のコールバック
@Override
public void onTextureCreate(long context) {
context_ = context ;
Log.d(TAG, "texture context: "+context_+" create!") ;
}OpenGL テクスチャ更新コールバック
@Override
public int onTextureUpdate(int textureId, int width, int height, AliRtcEngine.AliRtcVideoSample videoSample) {
/*
* textureid を処理します。
*/
++log_ref ;
return textureId;
} OpenGL コンテキスト破棄コールバック
@Override
public void onTextureDestroy() {
Log.d(TAG, "texture context: "+context_+" destory!") ;
}3. テクスチャコールバックの登録解除
public abstract void unRegisterLocalVideoTextureObserver();iOS
ビデオフレームコールバック
1. コールバックの登録
AliRtcEngineDelegate を実装し、registerVideoSampleObserver を呼び出してビデオフレームコールバックを登録します。
registerVideoSampleObserver2. オブザベーションポイントの指定
SDK は、このメソッドから返されるビットマスクに基づいて、トリガーするコールバックを決定します。
/**
* @brief ビデオデータ出力位置
*/
typedef NS_ENUM(NSInteger, AliRtcVideoObserPosition) {
/** キャプチャされたビデオデータ、onCaptureVideoSample コールバックに対応 */
AliRtcPositionPostCapture = 1 << 0,
/** デコードされたリモートビデオデータ、onRemoteVideoSample コールバックに対応 */
AliRtcPositionPreRender = 1 << 1,
/** エンコード前のビデオデータ、onPreEncodeVideoSample コールバックに対応 */
AliRtcPositionPreEncoder = 1 << 2,
};
/*
* SDK は AliRtcEngine::registerVideoSampleObserver を呼び出した後にこのメソッドを呼び出します。
*/
- (NSInteger)onGetVideoObservedFramePosition;3. 出力フォーマットの指定
ビデオデータを CVPixelBuffer として受信するには、エンジンを作成するときに extra フィールドで user_specified_native_buffer_observer オプションを TRUE に設定します。
/**
* @brief ビデオデータ形式
*/
typedef NS_ENUM(NSInteger, AliRtcVideoFormat) {
AliRtcVideoFormat_UNKNOW = -1,
AliRtcVideoFormat_BGRA = 0,
AliRtcVideoFormat_I420,
AliRtcVideoFormat_NV21,
AliRtcVideoFormat_NV12,
AliRtcVideoFormat_RGBA,
AliRtcVideoFormat_I422,
AliRtcVideoFormat_ARGB,
AliRtcVideoFormat_ABGR,
AliRtcVideoFormat_RGB24,
AliRtcVideoFormat_BGR24,
AliRtcVideoFormat_RGB565,
AliRtcVideoFormat_TextureOES,
AliRtcVideoFormat_Texture2D,
AliRtcVideoFormat_H264,
AliRtcVideoFormat_H265,
AliRtcVideoFormat_File,
AliRtcVideoFormat_cvPixelBuffer,
};
/*
* SDK は AliRtcEngine::registerVideoSampleObserver を呼び出した後にこのメソッドを呼び出します。
*/
- (AliRtcVideoFormat)onGetVideoFormatPreference {
return AliRtcVideoFormat_I420;
}4. メモリ配置の指定
/**
* @brief ビデオ出力幅の配置
*/
typedef enum {
/** 元のビデオ幅を維持 (デフォルト) */
AliRtcAlignmentDefault = 0,
/** ストライドを 2 バイトの倍数に配置 */
AliRtcAlignmentEven = 1,
/** ストライドを 4 バイトの倍数に配置 */
AliRtcAlignment4 = 2,
/** ストライドを 8 バイトの倍数に配置 */
AliRtcAlignment8 = 3,
/** ストライドを 16 バイトの倍数に配置 */
AliRtcAlignment16 = 4,
} AliRtcVideoObserAlignment;
/*
* SDK は AliRtcEngine::registerVideoSampleObserver を呼び出した後にこのメソッドを呼び出します。
*/
- (AliRtcVideoObserAlignment)onGetVideoAlignment {
return AliRtcAlignmentDefault;
}5. ミラー効果を適用するかどうかの指定
/**
* @brief 出力ビデオデータをミラーリングするかどうかを指定します。
* @return
* - YES: ミラーリング
* - NO: ミラーリングしない (デフォルト)
*/
/*
* SDK は AliRtcEngine::registerVideoSampleObserver を呼び出した後にこのメソッドを呼び出します。
*/
- (BOOL)onGetObserverDataMirrorApplied {
return FLASE ;
}6. コールバックの実装
/**
* @brief サブスクライブされたローカルビデオデータのコールバック。
* @param videoSource ビデオストリームのタイプ。
* @param videoSample 生ビデオデータ。
* @return
* - YES: 変更されたデータを SDK に書き戻します。iOS および macOS では、YES を返すことによるデータの書き戻しは、I420 および CVPixelBuffer フォーマットでのみサポートされます。
* - NO: データを SDK に書き戻しません。
*/
- (BOOL)onCaptureVideoSample:(AliRtcVideoSource)videoSource videoSample:(AliRtcVideoDataSample *_Nonnull)videoSample {
/*
* 処理...
*/
return FALSE ;
}
/**
* @brief サブスクライブされたローカルのエンコード前ビデオデータのコールバック。
* @param videoSource ビデオストリームのタイプ。
* @param videoSample 生ビデオデータ。
* @return
* - YES: 変更されたデータを SDK に書き戻します。iOS および macOS では、YES を返すことによるデータの書き戻しは、I420 および CVPixelBuffer フォーマットでのみサポートされます。
* - NO: データを SDK に書き戻しません。
*/
- (BOOL)onPreEncodeVideoSample:(AliRtcVideoSource)videoSource videoSample:(AliRtcVideoDataSample *_Nonnull)videoSample {
/*
* 処理...
*/
return FALSE ;
}
/**
* @brief サブスクライブされたリモートビデオデータのコールバック。
* @param uid ユーザー ID。
* @param videoSource ビデオストリームのタイプ。
* @param videoSample 生ビデオデータ。
* @return
* - YES: 変更されたデータを SDK に書き戻します。iOS および macOS では、YES を返すことによるデータの書き戻しは、I420 および CVPixelBuffer フォーマットでのみサポートされます。
* - NO: データを SDK に書き戻しません。
*/
- (BOOL)onRemoteVideoSample:(NSString *_Nonnull)uid videoSource:(AliRtcVideoSource)videoSource videoSample:(AliRtcVideoDataSample *_Nonnull)videoSample {
/*
* 処理...
*/
return TRUE ;
}
7. コールバックの登録解除
ビデオフレームを監視する必要がなくなったら、オブザーバーの登録を解除して不要な処理を回避します。
unregisterVideoSampleObserverテクスチャ処理
テクスチャ関連のすべてのコールバックは、同じ専用の OpenGL スレッドで呼び出されます。
1. テクスチャコールバックの登録
registerLocalVideoTexture2. コールバックの実装
OpenGL コンテキスト作成後のコールバック
/**
* @brief OpenGL コンテキスト作成のコールバック。
* @param context OpenGL コンテキスト。
* @note このコールバックは、SDK の内部 OpenGL コンテキストが作成されたときにトリガーされます。
*/
- (void)onTextureCreate:(void *_Nullable)context {
[[beautifyMoudle_ shared] create];
}OpenGL テクスチャ更新コールバック
/**
* @brief OpenGL テクスチャ更新のコールバック。
* @param textureId OpenGL テクスチャの ID。
* @param width テクスチャの幅。
* @param height テクスチャの高さ。
* @param videoSample ビデオフレームデータ、{@link AliRtcVideoDataSample} をご参照ください。
* @return 処理された OpenGL テクスチャの ID。
* @note
* - このコールバックは、SDK が現在のビデオフレームを GPU テクスチャにアップロードした後に呼び出されます。OpenGL テクスチャオブザーバーを登録した場合、テクスチャを処理し、処理後にダウンストリームで使用されるテクスチャ ID を返すことができます。
* - 有効なテクスチャ ID を返す必要があります。テクスチャを変更しない場合は、受信した textureId を変更せずに返します。
* コールバックの textureId は AliRtcVideoFormat_Texture2D フォーマットです。
*/
- (int)onTextureUpdate:(int)textureId width:(int)width height:(int)height videoSample:(AliRtcVideoDataSample *_Nonnull)videoSample {
if ( [[beautifyMoudle_ shared] enabled] == NO) {
return textureId;
}
int texId = [[beautifyMoudle_ shared] processTextureToTexture:textureId Width:width Height:height];
if(texId<0) {
texId = textureId;
}
return texId;
}OpenGL コンテキスト破棄コールバック
- (void)onTextureDestory
{
if (self.settingModel.chnnelType == ChannelTypePrimary) {
[[beautifyMoudle_ shared] destroy];
}
}3. テクスチャコールバックの登録解除
unregisterLocalVideoTexture