AOQ Client SDK でサポートされている 2 つのカスタムビデオ入力モード (ローフレームモードとエンコード済みフレームモード) について、それぞれの設定とコード例を説明します。
概要
AOQ クライアント SDK の内蔵ビデオモジュールは、基本的なビデオニーズに対応しますが、一部のシナリオでは内蔵のキャプチャモジュールでは不十分な場合があります。カスタムビデオキャプチャは、次のような場合に役立ちます:
- カメラデバイスの競合や互換性の問題を回避する場合。
- カスタムキャプチャシステムやビデオファイルのビデオデータを SDK に入力して伝送する場合。
- AI が生成したフレーム、スクリーン録画、または仮想カメラのコンテンツを SDK 経由で公開する場合。
AOQ クライアント SDK は、2 つのカスタムビデオ入力モードをサポートしています:
- RAW フレームモード : BGRA、I420、NV12、または NV21 などの形式で RAW ビデオフレームをキャプチャし、
pushExternalVideoCapturedFrameを使って SDK にプッシュします。 SDK は内部でエンコーディングと伝送を処理します。 - エンコード済みフレームモード : 自身でビデオフレーム (現在は JPEG のみ) をエンコードし、エンコード済みのデータを
pushExternalVideoEncodedFrameを使って SDK に直接プッシュすることで、SDK の内部エンコーダーをバイパスします。
サンプルコード
近日公開。
前提条件
createEngineを呼び出してエンジンインスタンスが作成されていること。- サーバーへの接続が確立されていること (
onConnectionStatusChangeコールバックがAoqConnectionStatusConnectedを報告済み )。
実装
ユースケースに基づいて、2 つのモードのいずれかを選択してください。2 つのモードを同時に使用することはできません。一度にアクティブにできるのは、1 つのプッシュインターフェイスのみです。
モード 1:ローフレームモード
BGRA、I420、NV12、NV21 などの形式でロービデオフレームをキャプチャし、エンコーディングと伝送のために SDK にプッシュします。SDK は、エンコードから伝送までのパイプライン全体を内部で処理します。
1. ビデオエンコーディングパラメーターの設定
SDK の内部エンコーダーが、プッシュされたローフレームをエンコードします。ユースケースに合わせてエンコーディングパラメーターを調整します。
AoqClientEngine.AoqVideoCodecConfig config = new AoqClientEngine.AoqVideoCodecConfig();
config.width = 1280;
config.height = 720;
config.fps = 2;
config.bitrate = 500000; // 開始ビットレート:500 kbps
config.minBitrate = 128000; // 最小ビットレート:128 kbps
config.keyframeInterval = 2;
// isExternal はデフォルトの false のままにします。SDK が内部でエンコーディングを処理します。
engine.setVideoEncoderConfig(config);
パラメーター:
パラメーター | タイプ | デフォルト | 説明 |
|---|---|---|---|
trackType | AoqTrackType | AoqTrackTypeVideo | ビデオトラックタイプ |
codecType | AoqEncoderType | AoqEncoderTypeVideoH264 | エンコーダータイプ |
width | int | 720 | エンコード幅 (ピクセル) |
height | int | 1280 | エンコード高さ (ピクセル) |
fps | int | 2 | フレームレート |
bitrate | int | 500000 | 開始ビットレート (bps) |
minBitrate | int | 128000 | 最小ビットレート (bps) |
keyframeInterval | int | 2 | キーフレーム間隔 (秒) |
isExternal | boolean | false | ローフレームモードでは false のままにします。 |
mirrorMode | AoqMirrorMode | AoqMirrorModeDisabled | ミラーモード |
orientationMode | AoqOrientationMode | AoqOrientationModeAuto | オリエンテーションモード |
2. 外部キャプチャモードでのビデオキャプチャの開始
isExternal=true を指定して startVideoCapture を呼び出すと、SDK はカメラを開かず、外部ソースからのフレームを受け取るようになります。これはローフレームモードで必須です。この呼び出しを省略すると、SDK はプッシュされたフレームを処理しません。
AoqClientEngine.AoqVideoCaptureConfig config = new AoqClientEngine.AoqVideoCaptureConfig();
config.isExternal = true; // カメラを開きません。外部ソースがフレームをプッシュします。
// isExternal=true の場合、width/height/fps は無効です。実際の解像度とフレームレートは、
// プッシュされるデータによって決まります。
int ret = engine.startVideoCapture(config);
パラメーター:
パラメーター | タイプ | デフォルト | 説明 |
|---|---|---|---|
width | int | 1280 | キャプチャ幅 ( |
height | int | 720 | キャプチャ高さ ( |
fps | int | 15 | キャプチャフレームレート ( |
isExternal | boolean | false | true:カメラを開きません。外部ソースがフレームを提供します。 |
cameraDirection | AoqCameraDirection | AoqCameraDirectionFront | カメラの向き ( |
3. ロービデオフレームのプッシュ
pushExternalVideoCapturedFrame を呼び出して、キャプチャしたローフレームを SDK にプッシュします。SDK がエンコーディングと伝送を処理します。
サポートされている形式:BGRA、I420、NV12、NV21、RGBA。Apple プラットフォームでは、CVPixelBuffer のゼロコピーもサポートされています。
3.1 BGRA 形式
BGRA は、1 ピクセルあたり 4 バイト (Blue、Green、Red、Alpha) のパックフォーマットです。フレームサイズ = width × height × 4 バイトです。
// BGRA ビデオフレームを作成します
AoqClientEngine.AoqVideoFrame frame = new AoqClientEngine.AoqVideoFrame();
frame.format = AoqClientEngine.AoqVideoPixelFormat.AoqVideoPixelFormatBGRA;
frame.width = 1280;
frame.height = 720;
frame.data = bgraBytes; // byte[], length = width * height * 4
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoCapturedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
3.2 I420 形式
I420 は、3 つの独立したプレーン (Y、U、V) を持つプレーナーフォーマットです。Y プレーンサイズ = width × height、U と V の各プレーンは (width/2) × (height/2) です。
// I420 ビデオフレームを作成します
AoqClientEngine.AoqVideoFrame frame = new AoqClientEngine.AoqVideoFrame();
frame.format = AoqClientEngine.AoqVideoPixelFormat.AoqVideoPixelFormatI420;
frame.width = 1280;
frame.height = 720;
frame.dataY = yPlane; // byte[], length = width * height
frame.dataU = uPlane; // byte[], length = (width/2) * (height/2)
frame.dataV = vPlane; // byte[], length = (width/2) * (height/2)
frame.strideY = 1280; // Y プレーンの行ストライド (バイト)
frame.strideU = 640; // U プレーンの行ストライド (バイト)
frame.strideV = 640; // V プレーンの行ストライド (バイト)
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoCapturedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
3.3 NV12 / NV21 形式
NV12 と NV21 は、Y プレーンとインターリーブされた UV プレーンで構成されるセミプレーナーフォーマットです。NV12 は UV の順でインターリーブし、NV21 は VU の順でインターリーブします。フレームサイズ = width × height × 3 / 2 バイトで、data フィールドにパックされます。
// NV12 ビデオフレームを作成します (NV21 も同様です。format フィールドを変更するだけです)
AoqClientEngine.AoqVideoFrame frame = new AoqClientEngine.AoqVideoFrame();
frame.format = AoqClientEngine.AoqVideoPixelFormat.AoqVideoPixelFormatNV12;
frame.width = 1280;
frame.height = 720;
frame.data = nv12Bytes; // byte[], length = width * height * 3 / 2
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoCapturedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
3.4 CVPixelBuffer 形式 (Apple プラットフォーム)
iOS と macOS では、CVPixelBufferRef をゼロコピーで直接渡すことができます。これにより、メモリコピーによるパフォーマンスオーバーヘッドを回避できます。
// iOS / macOS
let frame = AoqVideoFrame()
frame.format = .cvPixelBuffer
frame.width = 1280
frame.height = 720
frame.pixelBuffer = pixelBuffer // CVPixelBufferRef
frame.timeStamp = Int64(Date().timeIntervalSince1970 * 1000)
// SDK は pixelBuffer を非同期に保持します。参照カウントを +1 して保持してください。
// SDK は処理完了後に解放します。
let _ = Unmanaged.passRetained(pixelBuffer)
engine.pushExternalVideoCapturedFrame(.video, frame: frame)
4. ローフレームキャプチャの停止
フレームのプッシュが不要になったら、最初にプッシュタイマーを停止し、その後 stopVideoCapture を呼び出してビデオキャプチャを停止します。
// 1. フレームプッシュタイマーを停止します
stopExternalFramePush();
// 2. ビデオキャプチャを停止します
engine.stopVideoCapture();
モード 2:エンコードフレームモード
ビデオフレームを自身でエンコード (現時点では JPEG のみ) し、内部エンコーダーをバイパスして、エンコード済みデータを SDK に直接プッシュします。このモードでは、startVideoCapture やその他のキャプチャ関連 API を呼び出す必要は ありません。
1. ビデオエンコーディングパラメーターの設定と外部エンコーディングの有効化
isExternal=true を指定して setVideoEncoderConfig を呼び出すと、SDK は内部エンコーダーをスキップし、外部からのエンコード済みデータを受け取るようになります。
AoqClientEngine.AoqVideoCodecConfig config = new AoqClientEngine.AoqVideoCodecConfig();
config.width = 1280;
config.height = 720;
config.fps = 2;
config.isExternal = true; // 内部エンコーディングをスキップします。外部ソースがエンコード済みフレームを提供します。
engine.setVideoEncoderConfig(config);
設定後は、すぐにエンコード済みフレームをプッシュできます。startVideoCapture を呼び出す必要はありません。
2. エンコード済みビデオフレームのプッシュ
pushExternalVideoEncodedFrame を呼び出して、エンコード済みビデオデータを SDK に直接渡します。現時点でサポートされているエンコーディングは JPEG のみです。
// Bitmap から JPEG データを生成します
android.graphics.Bitmap bmp = android.graphics.Bitmap.createBitmap(
width, height, android.graphics.Bitmap.Config.ARGB_8888);
// ... ここで Bitmap のコンテンツを書き込みます ...
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
bmp.compress(android.graphics.Bitmap.CompressFormat.JPEG, 85, baos);
bmp.recycle();
// エンコード済みフレームを作成してプッシュします
AoqClientEngine.AoqVideoEncodedFrame frame = new AoqClientEngine.AoqVideoEncodedFrame();
frame.codec = AoqClientEngine.AoqVideoCodecType.AoqVideoCodecTypeJPEG;
frame.data = baos.toByteArray();
frame.width = width;
frame.height = height;
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoEncodedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
AoqVideoEncodedFrame パラメーター:
パラメーター | タイプ | デフォルト | 説明 |
|---|---|---|---|
codec | AoqVideoCodecType | AoqVideoCodecTypeJPEG | エンコード形式。現時点では JPEG のみがサポートされています。 |
data | byte[] | null | エンコード済みフレームデータ |
width | int | 0 | フレーム幅 (ピクセル) |
height | int | 0 | フレーム高さ (ピクセル) |
timeStamp | long | 0 | タイムスタンプ (ミリ秒)。0 の場合、SDK はローカルクロックを使用します。 |
3. エンコード済みフレームのプッシュ停止
エンコードフレームモードではキャプチャデバイスを使用しないため、停止するにはプッシュタイマーを停止するだけです。
stopExternalFramePush();
関連ドキュメント
AoqVideoFrame (ローフレームモード)
フィールド | タイプ | 説明 |
|---|---|---|
format | AoqVideoPixelFormat | ピクセルフォーマット |
width | int | フレーム幅 (ピクセル) |
height | int | フレーム高さ (ピクセル) |
data | byte[] | パックフォーマットデータ (NV12/NV21/BGRA/RGBA) |
dataY | byte[] | I420 の Y プレーンデータ |
dataU | byte[] | I420 の U プレーンデータ |
dataV | byte[] | I420 の V プレーンデータ |
strideY | int | I420 の Y プレーンの行ストライド (バイト) |
strideU | int | I420 の U プレーンの行ストライド (バイト) |
strideV | int | I420 の V プレーンの行ストライド (バイト) |
textureId | int | Android テクスチャ ID (TextureOES/Texture2D) |
transformMatrix | float[] | テクスチャ変換行列 (4×4、行優先) |
eglContext | EGLContext | Android 共有 EGL コンテキスト (テクスチャモード用) |
pixelBuffer | CVPixelBufferRef | Apple ゼロコピー CVPixelBuffer (iOS/macOS のみ) |
timeStamp | long | タイムスタンプ (ミリ秒)。0 の場合、SDK はローカルクロックを使用します。 |
AoqVideoPixelFormat enum 値
列挙値 | 数値 | 説明 |
|---|---|---|
AoqVideoPixelFormatUnknown | 0 | 不明な形式 |
AoqVideoPixelFormatI420 | 1 | I420 プレーナーフォーマット |
AoqVideoPixelFormatNV12 | 2 | NV12 セミプレーナーフォーマット (UV インターリーブ) |
AoqVideoPixelFormatNV21 | 3 | NV21 セミプレーナーフォーマット (VU インターリーブ) |
AoqVideoPixelFormatBGRA | 4 | BGRA パックフォーマット |
AoqVideoPixelFormatRGBA | 5 | RGBA パックフォーマット |
AoqVideoPixelFormatCVPixelBuffer | 6 | Apple CVPixelBuffer (iOS/macOS のみ) |
AoqVideoPixelFormatTextureOES | 7 | Android OES 外部テクスチャ |
AoqVideoPixelFormatTexture2D | 8 | Android 2D テクスチャ |
AoqVideoEncodedFrame (エンコードフレームモード)
フィールド | タイプ | 説明 |
|---|---|---|
codec | AoqVideoCodecType | エンコード形式 |
data | byte[] | エンコード済みフレームデータ |
width | int | フレーム幅 (ピクセル) |
height | int | フレーム高さ (ピクセル) |
timeStamp | long | タイムスタンプ (ミリ秒)。0 の場合、SDK はローカルクロックを使用します。 |
AoqVideoCodecType enum 値
列挙値 | 数値 | 説明 |
|---|---|---|
AoqVideoCodecTypeJPEG | 0 | JPEG エンコード形式 |
重要な注意事項
- ローフレームモード:フレームをプッシュする前に、
startVideoCapture(isExternal=true)を呼び出す必要があります。この呼び出しを省略すると、SDK はパラメーターエラーを返します。 - エンコードフレームモード:
setVideoEncoderConfig(isExternal=true)を呼び出してすぐにプッシュします。startVideoCaptureの呼び出しは 不要 です。 - ローフレームモードとエンコードフレームモードは同時に使用できません。同時に有効にできるプッシュインターフェイスは 1 つだけです。
- エンコードフレームモードは、現時点では JPEG のみをサポートしています。
- フレームをプッシュすると、SDK がライフサイクルを内部で管理します。プッシュ呼び出しの完了後は、データを保持する必要はありません。