Menjelaskan dua mode input video kustom yang didukung oleh AOQ Client SDK—mode raw frame dan mode encoded frame—serta konfigurasi dan contoh kode untuk masing-masing.
Ikhtisar
Modul video bawaan AOQ Client SDK mencakup kebutuhan video dasar, tetapi dalam beberapa skenario modul tangkapan bawaan mungkin tidak mencukupi. Tangkapan video kustom berguna ketika Anda perlu:
- Mengatasi konflik atau masalah kompatibilitas perangkat kamera.
- Memasukkan data video dari sistem tangkapan kustom atau file video ke dalam SDK untuk transmisi.
- Menyiarkan frame yang dihasilkan AI, rekaman layar, atau konten kamera virtual melalui SDK.
AOQ Client SDK mendukung dua mode input video kustom:
- Raw frame mode: Tangkap frame video mentah dalam format seperti BGRA, I420, NV12, atau NV21, lalu dorong ke SDK melalui
pushExternalVideoCapturedFrame. SDK menangani encoding dan transmisi secara internal. - Encoded frame mode: Encode frame video sendiri (saat ini hanya JPEG), lalu dorong data yang telah diencode langsung ke SDK melalui
pushExternalVideoEncodedFrame, melewati encoder internal SDK.
Kode contoh
Segera hadir.
Prasyarat
- Instans engine telah dibuat dengan memanggil
createEngine. - Koneksi ke server telah terjalin (callback
onConnectionStatusChangetelah melaporkanAoqConnectionStatusConnected).
Implementasi
Pilih salah satu dari dua mode berdasarkan kasus penggunaan Anda. Kedua mode tidak dapat digunakan secara bersamaan: hanya satu antarmuka push yang dapat aktif dalam satu waktu.
Mode 1: Raw frame mode
Tangkap frame video mentah dalam format seperti BGRA, I420, NV12, atau NV21 dan dorong ke SDK untuk encoding dan transmisi. SDK menangani seluruh pipeline encoding dan pengiriman secara internal.
1. Konfigurasikan parameter encoding video
Encoder internal SDK mengencode frame mentah yang Anda dorong. Sesuaikan parameter encoding agar sesuai dengan kasus penggunaan Anda.
AoqClientEngine.AoqVideoCodecConfig config = new AoqClientEngine.AoqVideoCodecConfig();
config.width = 1280;
config.height = 720;
config.fps = 2;
config.bitrate = 500000; // Bitrate awal: 500 kbps
config.minBitrate = 128000; // Bitrate minimum: 128 kbps
config.keyframeInterval = 2;
// Biarkan isExternal bernilai false default — SDK menangani encoding secara internal
engine.setVideoEncoderConfig(config);
Parameter:
Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
trackType | AoqTrackType | AoqTrackTypeVideo | Jenis track video |
codecType | AoqEncoderType | AoqEncoderTypeVideoH264 | Jenis encoder |
width | int | 720 | Lebar encoding (piksel) |
height | int | 1280 | Tinggi encoding (piksel) |
fps | int | 5 | Laju frame |
bitrate | int | 500000 | Bitrate awal (bps) |
minBitrate | int | 128000 | Bitrate minimum (bps) |
keyframeInterval | int | 2 | Interval keyframe (detik) |
isExternal | boolean | false | Biar tetap false untuk raw frame mode |
mirrorMode | AoqMirrorMode | AoqMirrorModeDisabled | Mode cermin |
orientationMode | AoqOrientationMode | AoqOrientationModeAuto | Mode orientasi |
2. Mulai tangkapan video dalam mode tangkapan eksternal
Panggil startVideoCapture dengan isExternal=true untuk memberi tahu SDK agar tidak membuka kamera dan mengharapkan frame dari sumber eksternal. Ini wajib dilakukan untuk raw frame mode—jika Anda melewatkan pemanggilan ini, SDK tidak akan mengonsumsi frame yang Anda dorong.
AoqClientEngine.AoqVideoCaptureConfig config = new AoqClientEngine.AoqVideoCaptureConfig();
config.isExternal = true; // Jangan buka kamera; sumber eksternal akan mendorong frame
// Saat isExternal=true, width/height/fps tidak berpengaruh — resolusi aktual
// dan laju frame ditentukan oleh data yang didorong
int ret = engine.startVideoCapture(config);
Parameter:
Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
width | int | 1280 | Lebar tangkapan (diabaikan saat |
height | int | 720 | Tinggi tangkapan (diabaikan saat |
fps | int | 15 | Laju frame tangkapan (diabaikan saat |
isExternal | boolean | false | true: jangan buka kamera; sumber eksternal menyediakan frame |
cameraDirection | AoqCameraDirection | AoqCameraDirectionFront | Arah kamera (diabaikan saat |
3. Dorong frame video mentah
Panggil pushExternalVideoCapturedFrame untuk memasukkan frame mentah yang telah ditangkap ke dalam SDK. SDK menangani encoding dan transmisi.
Format yang didukung: BGRA, I420, NV12, NV21, RGBA. Pada platform Apple, zero-copy CVPixelBuffer juga didukung.
3.1 Format BGRA
BGRA adalah format packed dengan 4 byte per piksel (Blue, Green, Red, Alpha). Ukuran frame = lebar × tinggi × 4 byte.
// Buat frame video BGRA
AoqClientEngine.AoqVideoFrame frame = new AoqClientEngine.AoqVideoFrame();
frame.format = AoqClientEngine.AoqVideoPixelFormat.AoqVideoPixelFormatBGRA;
frame.width = 1280;
frame.height = 720;
frame.data = bgraBytes; // byte[], panjang = width * height * 4
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoCapturedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
3.2 Format I420
I420 adalah format planar dengan tiga bidang terpisah (Y, U, V). Ukuran bidang Y = lebar × tinggi; bidang U dan V masing-masing berukuran (lebar/2) × (tinggi/2).
// Buat frame video I420
AoqClientEngine.AoqVideoFrame frame = new AoqClientEngine.AoqVideoFrame();
frame.format = AoqClientEngine.AoqVideoPixelFormat.AoqVideoPixelFormatI420;
frame.width = 1280;
frame.height = 720;
frame.dataY = yPlane; // byte[], panjang = width * height
frame.dataU = uPlane; // byte[], panjang = (width/2) * (height/2)
frame.dataV = vPlane; // byte[], panjang = (width/2) * (height/2)
frame.strideY = 1280; // Stride baris bidang Y (byte)
frame.strideU = 640; // Stride baris bidang U (byte)
frame.strideV = 640; // Stride baris bidang V (byte)
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoCapturedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
3.3 Format NV12 / NV21
NV12 dan NV21 adalah format semi-planar yang terdiri dari bidang Y dan bidang UV interleaved. NV12 menginterleaving UV dalam urutan tersebut; NV21 menginterleaving VU. Ukuran frame = lebar × tinggi × 3 / 2 byte, dikemas ke dalam field data.
// Buat frame video NV12 (NV21 identik — cukup ubah field format)
AoqClientEngine.AoqVideoFrame frame = new AoqClientEngine.AoqVideoFrame();
frame.format = AoqClientEngine.AoqVideoPixelFormat.AoqVideoPixelFormatNV12;
frame.width = 1280;
frame.height = 720;
frame.data = nv12Bytes; // byte[], panjang = width * height * 3 / 2
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoCapturedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
3.4 Format CVPixelBuffer (platform Apple)
Pada iOS dan macOS, Anda dapat meneruskan CVPixelBufferRef secara langsung untuk transfer zero-copy, menghindari overhead performa akibat penyalinan memori.
// 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 menyimpan pixelBuffer secara asinkron — pertahankan dengan +1 ref count.
// SDK melepaskannya setelah selesai.
let _ = Unmanaged.passRetained(pixelBuffer)
engine.pushExternalVideoCapturedFrame(.video, frame: frame)
4. Hentikan tangkapan raw frame
Saat Anda tidak lagi perlu mendorong frame, hentikan timer push terlebih dahulu, lalu panggil stopVideoCapture untuk mematikan tangkapan video.
// 1. Hentikan timer push frame
stopExternalFramePush();
// 2. Hentikan tangkapan video
engine.stopVideoCapture();
Mode 2: Encoded frame mode
Encode frame video sendiri (saat ini hanya JPEG) dan dorong data yang telah diencode langsung ke SDK, melewati encoder internal. Mode ini tidak memerlukan pemanggilan startVideoCapture atau API terkait tangkapan lainnya.
1. Konfigurasikan parameter encoding video dan aktifkan encoding eksternal
Panggil setVideoEncoderConfig dengan isExternal=true untuk memberi tahu SDK agar melewati encoder internal dan mengharapkan data yang telah diencode dari luar.
AoqClientEngine.AoqVideoCodecConfig config = new AoqClientEngine.AoqVideoCodecConfig();
config.width = 1280;
config.height = 720;
config.fps = 2;
config.isExternal = true; // Lewati encoding internal; sumber eksternal menyediakan frame yang telah diencode
engine.setVideoEncoderConfig(config);
Setelah dikonfigurasi, Anda dapat segera mendorong frame yang telah diencode—tidak perlu memanggil startVideoCapture.
2. Dorong frame video yang telah diencode
Panggil pushExternalVideoEncodedFrame untuk meneruskan data video yang telah diencode langsung ke SDK. Saat ini hanya encoding JPEG yang didukung.
// Hasilkan data JPEG dari Bitmap
android.graphics.Bitmap bmp = android.graphics.Bitmap.createBitmap(
width, height, android.graphics.Bitmap.Config.ARGB_8888);
// ... isi konten Bitmap ...
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
bmp.compress(android.graphics.Bitmap.CompressFormat.JPEG, 85, baos);
bmp.recycle();
// Buat frame yang telah diencode dan dorong
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);
Parameter AoqVideoEncodedFrame:
Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
codec | AoqVideoCodecType | AoqVideoCodecTypeJPEG | Format encoding; saat ini hanya JPEG yang didukung |
data | byte[] | null | Data frame yang telah diencode |
width | int | 0 | Lebar frame (piksel) |
height | int | 0 | Tinggi frame (piksel) |
timeStamp | long | 0 | Timestamp (milidetik); saat 0, SDK menggunakan jam lokal |
3. Hentikan pendorongan frame yang telah diencode
Encoded frame mode tidak melibatkan perangkat tangkapan apa pun, sehingga penghentian cukup dengan menghentikan timer push Anda.
stopExternalFramePush();
Referensi
AoqVideoFrame (raw frame mode)
Bidang | Tipe | Deskripsi |
|---|---|---|
format | AoqVideoPixelFormat | Format piksel |
width | int | Lebar frame (piksel) |
height | int | Tinggi frame (piksel) |
data | byte[] | Data format packed (NV12/NV21/BGRA/RGBA) |
dataY | byte[] | Data bidang Y I420 |
dataU | byte[] | Data bidang U I420 |
dataV | byte[] | Data bidang V I420 |
strideY | int | Stride baris bidang Y I420 (byte) |
strideU | int | Stride baris bidang U I420 (byte) |
strideV | int | Stride baris bidang V I420 (byte) |
textureId | int | ID tekstur Android (TextureOES/Texture2D) |
transformMatrix | float[] | Matriks transformasi tekstur (4×4, row-major) |
eglContext | EGLContext | Konteks EGL bersama Android (untuk mode tekstur) |
pixelBuffer | CVPixelBufferRef | CVPixelBuffer zero-copy Apple (hanya iOS/macOS) |
timeStamp | long | Timestamp (milidetik); saat 0, SDK menggunakan jam lokal |
Nilai enum AoqVideoPixelFormat
Nilai enum | Nilai numerik | Deskripsi |
|---|---|---|
AoqVideoPixelFormatUnknown | 0 | Format tidak dikenal |
AoqVideoPixelFormatI420 | 1 | Format planar I420 |
AoqVideoPixelFormatNV12 | 2 | Format semi-planar NV12 (UV interleaved) |
AoqVideoPixelFormatNV21 | 3 | Format semi-planar NV21 (VU interleaved) |
AoqVideoPixelFormatBGRA | 4 | Format packed BGRA |
AoqVideoPixelFormatRGBA | 5 | Format packed RGBA |
AoqVideoPixelFormatCVPixelBuffer | 6 | CVPixelBuffer Apple (hanya iOS/macOS) |
AoqVideoPixelFormatTextureOES | 7 | Tekstur eksternal OES Android |
AoqVideoPixelFormatTexture2D | 8 | Tekstur 2D Android |
AoqVideoEncodedFrame (encoded frame mode)
Bidang | Tipe | Deskripsi |
|---|---|---|
codec | AoqVideoCodecType | Format encoding |
data | byte[] | Data frame yang telah diencode |
width | int | Lebar frame (piksel) |
height | int | Tinggi frame (piksel) |
timeStamp | long | Timestamp (milidetik); saat 0, SDK menggunakan jam lokal |
Nilai enum AoqVideoCodecType
Nilai enum | Nilai numerik | Deskripsi |
|---|---|---|
AoqVideoCodecTypeJPEG | 0 | Format encoding JPEG |
Catatan penting
- Raw frame mode: Anda harus memanggil
startVideoCapture(isExternal=true)sebelum mendorong frame. Jika Anda melewatkan pemanggilan ini, SDK akan mengembalikan error parameter. - Encoded frame mode: panggil
setVideoEncoderConfig(isExternal=true)dan dorong segera—pemanggilanstartVideoCapturetidak diperlukan. - Raw frame mode dan encoded frame mode tidak dapat digunakan secara bersamaan: hanya satu antarmuka push yang dapat aktif dalam satu waktu.
- Encoded frame mode saat ini hanya mendukung JPEG.
- Setelah Anda mendorong frame, SDK mengelola siklus hidupnya secara internal. Anda tidak perlu menyimpan data tersebut setelah pemanggilan push selesai.