Cette rubrique décrit les deux modes d'entrée vidéo personnalisée pris en charge par le SDK Client AOQ : le mode trame brute et le mode trame encodée. Elle détaille également la configuration et fournit des exemples de code pour chaque mode.
Présentation
Le module vidéo intégré du SDK Client AOQ répond aux besoins vidéo de base. Toutefois, dans certains scénarios, ce module de capture natif peut s'avérer insuffisant. La capture vidéo personnalisée est utile lorsque vous devez :
- Contourner des conflits de périphériques de caméra ou des problèmes de compatibilité.
- Alimenter le SDK avec des données vidéo provenant d'un système de capture personnalisé ou d'un fichier vidéo afin de les transmettre.
- Publier via le SDK des trames générées par IA, des enregistrements d'écran ou du contenu issu d'une caméra virtuelle.
Le SDK Client AOQ prend en charge deux modes d'entrée vidéo personnalisée :
- Mode trame brute : capturez des trames vidéo brutes dans des formats tels que BGRA, I420, NV12 ou NV21, puis injectez-les dans le SDK via
pushExternalVideoCapturedFrame. Le SDK gère l'encodage et la transmission en interne. - Mode trame encodée : encodez vous-même les trames vidéo (actuellement JPEG uniquement), puis injectez les données encodées directement dans le SDK via
pushExternalVideoEncodedFrame, en contournant ainsi l'encodeur interne du SDK.
Exemple de code
Bientôt disponible.
Prérequis
- Une instance de moteur a été créée en appelant
createEngine. - Une connexion au serveur est établie (le callback
onConnectionStatusChangea signaléAoqConnectionStatusConnected).
Mise en œuvre
Choisissez l'un des deux modes selon votre cas d'utilisation. Ces deux modes ne peuvent pas être utilisés simultanément : une seule interface d'injection peut être active à la fois.
Mode 1 : Mode trame brute
Capturez des trames vidéo brutes dans des formats tels que BGRA, I420, NV12 ou NV21, puis injectez-les dans le SDK pour qu'il procède à l'encodage et à la transmission. Le SDK gère l'intégralité du pipeline d'encodage et d'envoi en interne.
1. Configurer les paramètres d'encodage vidéo
L'encodeur interne du SDK encode les trames brutes que vous injectez. Ajustez les paramètres d'encodage pour les adapter à votre cas d'utilisation.
AoqClientEngine.AoqVideoCodecConfig config = new AoqClientEngine.AoqVideoCodecConfig();
config.width = 1280;
config.height = 720;
config.fps = 2;
config.bitrate = 500000; // Starting bitrate: 500 kbps
config.minBitrate = 128000; // Minimum bitrate: 128 kbps
config.keyframeInterval = 2;
// Leave isExternal at the default false — the SDK handles encoding internally
engine.setVideoEncoderConfig(config);
Paramètres :
Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
trackType | AoqTrackType | AoqTrackTypeVideo | Type de piste vidéo |
codecType | AoqEncoderType | AoqEncoderTypeVideoH264 | Type d'encodeur |
width | int | 720 | Largeur d'encodage (pixels) |
height | int | 1280 | Hauteur d'encodage (pixels) |
fps | int | 5 | Fréquence d'images |
bitrate | int | 500000 | Débit binaire initial (bps) |
minBitrate | int | 128000 | Débit binaire minimal (bps) |
keyframeInterval | int | 2 | Intervalle entre les images clés (secondes) |
isExternal | boolean | false | Laisser à false pour le mode trame brute |
mirrorMode | AoqMirrorMode | AoqMirrorModeDisabled | Mode miroir |
orientationMode | AoqOrientationMode | AoqOrientationModeAuto | Mode d'orientation |
2. Démarrer la capture vidéo en mode capture externe
Appelez startVideoCapture avec isExternal=true pour indiquer au SDK de ne pas ouvrir la caméra et d'attendre des trames provenant d'une source externe. Cette étape est obligatoire pour le mode trame brute : si vous omettez cet appel, le SDK ne traitera aucune des trames injectées.
AoqClientEngine.AoqVideoCaptureConfig config = new AoqClientEngine.AoqVideoCaptureConfig();
config.isExternal = true; // Do not open the camera; external source will push frames
// When isExternal=true, width/height/fps have no effect — the actual resolution
// and frame rate are determined by the pushed data
int ret = engine.startVideoCapture(config);
Paramètres :
Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
width | int | 1280 | Largeur de capture (ignorée lorsque |
height | int | 720 | Hauteur de capture (ignorée lorsque |
fps | int | 15 | Fréquence d'images de capture (ignorée lorsque |
isExternal | boolean | false | true : ne pas ouvrir la caméra ; une source externe fournit les trames |
cameraDirection | AoqCameraDirection | AoqCameraDirectionFront | Direction de la caméra (ignorée lorsque |
3. Injecter des trames vidéo brutes
Appelez pushExternalVideoCapturedFrame pour alimenter le SDK avec les trames brutes capturées. Le SDK se charge de l'encodage et de la transmission.
Formats pris en charge : BGRA, I420, NV12, NV21, RGBA. Sur les plateformes Apple, le zéro copie via CVPixelBuffer est également pris en charge.
3,1 Format BGRA
BGRA est un format compact utilisant 4 octets par pixel (Blue, Green, Red, Alpha). Taille de la trame = largeur × hauteur × 4 octets.
// Build a BGRA video frame
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 Format I420
I420 est un format planaire composé de trois plans distincts (Y, U, V). La taille du plan Y correspond à largeur × hauteur ; les plans U et V mesurent chacun (largeur/2) × (hauteur/2).
// Build an I420 video frame
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 plane row stride (bytes)
frame.strideU = 640; // U plane row stride (bytes)
frame.strideV = 640; // V plane row stride (bytes)
frame.timeStamp = System.currentTimeMillis();
int ret = engine.pushExternalVideoCapturedFrame(
AoqClientEngine.AoqTrackType.AoqTrackTypeVideo, frame);
3,3 Formats NV12 / NV21
NV12 et NV21 sont des formats semi-planaires constitués d'un plan Y et d'un plan UV entrelacé. NV12 entrelace les composantes dans l'ordre UV, tandis que NV21 utilise l'ordre VU. La taille de la trame équivaut à largeur × hauteur × 3 / 2 octets, stockés dans le champ data.
// Build an NV12 video frame (NV21 is identical — just change the format field)
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 Format CVPixelBuffer (plateformes Apple)
Sur iOS et macOS, vous pouvez transmettre directement un CVPixelBufferRef pour bénéficier d'un transfert zéro copie, évitant ainsi la surcharge de performance liée aux copies mémoire.
// iOS / macOS
let frame = AoqVideoFrame()
frame.format = .cvPixelBuffer
frame.width = 1280
frame.height = 720
frame.pixelBuffer = pixelBuffer // CVPixelBufferRef
frame.timeStamp = Int64(Date().timeIntervalSince1970 * 1000)
// The SDK holds pixelBuffer asynchronously — retain it with +1 ref count.
// The SDK releases it when done.
let _ = Unmanaged.passRetained(pixelBuffer)
engine.pushExternalVideoCapturedFrame(.video, frame: frame)
4. Arrêter la capture de trames brutes
Lorsque vous n'avez plus besoin d'injecter des trames, arrêtez d'abord le minuteur d'injection, puis appelez stopVideoCapture pour fermer la capture vidéo.
// 1. Stop the frame push timer
stopExternalFramePush();
// 2. Stop video capture
engine.stopVideoCapture();
Mode 2 : Mode trame encodée
Encodez vous-même les trames vidéo (actuellement JPEG uniquement) et injectez les données encodées directement dans le SDK, en contournant l'encodeur interne. Ce mode ne nécessite pas l'appel à startVideoCapture ni à aucune autre API liée à la capture.
1. Configurer les paramètres d'encodage vidéo et activer l'encodage externe
Appelez setVideoEncoderConfig avec isExternal=true pour indiquer au SDK d'ignorer l'encodeur interne et d'attendre des données pré-encodées provenant d'une source externe.
AoqClientEngine.AoqVideoCodecConfig config = new AoqClientEngine.AoqVideoCodecConfig();
config.width = 1280;
config.height = 720;
config.fps = 2;
config.isExternal = true; // Skip internal encoding; external source provides encoded frames
engine.setVideoEncoderConfig(config);
Une fois la configuration terminée, vous pouvez injecter immédiatement des trames encodées sans avoir à appeler startVideoCapture.
2. Injecter des trames vidéo encodées
Appelez pushExternalVideoEncodedFrame pour transmettre des données vidéo pré-encodées directement au SDK. Seul l'encodage JPEG est actuellement pris en charge.
// Generate JPEG data from a Bitmap
android.graphics.Bitmap bmp = android.graphics.Bitmap.createBitmap(
width, height, android.graphics.Bitmap.Config.ARGB_8888);
// ... fill in Bitmap content ...
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
bmp.compress(android.graphics.Bitmap.CompressFormat.JPEG, 85, baos);
bmp.recycle();
// Build the encoded frame and push it
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);
Paramètres de AoqVideoEncodedFrame :
Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
codec | AoqVideoCodecType | AoqVideoCodecTypeJPEG | Format d'encodage ; seul JPEG est actuellement pris en charge |
data | byte[] | null | Données de la trame encodée |
width | int | 0 | Largeur de la trame (pixels) |
height | int | 0 | Hauteur de la trame (pixels) |
timeStamp | long | 0 | Horodatage (millisecondes) ; si la valeur est 0, le SDK utilise l'horloge locale |
3. Arrêter l'injection de trames encodées
Le mode trame encodée n'utilisant aucun périphérique de capture, l'arrêt consiste simplement à suspendre votre minuteur d'injection.
stopExternalFramePush();
Référence
AoqVideoFrame (mode trame brute)
Champ | Type | Description |
|---|---|---|
format | AoqVideoPixelFormat | Format de pixel |
width | int | Largeur de la trame (pixels) |
height | int | Hauteur de la trame (pixels) |
data | byte[] | Données au format compact (NV12/NV21/BGRA/RGBA) |
dataY | byte[] | Données du plan Y pour I420 |
dataU | byte[] | Données du plan U pour I420 |
dataV | byte[] | Données du plan V pour I420 |
strideY | int | Pas de ligne du plan Y pour I420 (octets) |
strideU | int | Pas de ligne du plan U pour I420 (octets) |
strideV | int | Pas de ligne du plan V pour I420 (octets) |
textureId | int | ID de texture Android (TextureOES/Texture2D) |
transformMatrix | float[] | Matrice de transformation de texture (4×4, ordre ligne) |
eglContext | EGLContext | Contexte EGL partagé Android (pour le mode texture) |
pixelBuffer | CVPixelBufferRef | CVPixelBuffer Apple zéro copie (iOS/macOS uniquement) |
timeStamp | long | Horodatage (millisecondes) ; si la valeur est 0, le SDK utilise l'horloge locale |
Valeurs de l'énumération AoqVideoPixelFormat
Valeur d'énumération | Valeur numérique | Description |
|---|---|---|
AoqVideoPixelFormatUnknown | 0 | Format inconnu |
AoqVideoPixelFormatI420 | 1 | Format planaire I420 |
AoqVideoPixelFormatNV12 | 2 | Format semi-planaire NV12 (UV entrelacé) |
AoqVideoPixelFormatNV21 | 3 | Format semi-planaire NV21 (VU entrelacé) |
AoqVideoPixelFormatBGRA | 4 | Format compact BGRA |
AoqVideoPixelFormatRGBA | 5 | Format compact RGBA |
AoqVideoPixelFormatCVPixelBuffer | 6 | CVPixelBuffer Apple (iOS/macOS uniquement) |
AoqVideoPixelFormatTextureOES | 7 | Texture externe OES Android |
AoqVideoPixelFormatTexture2D | 8 | Texture 2D Android |
AoqVideoEncodedFrame (mode trame encodée)
Champ | Type | Description |
|---|---|---|
codec | AoqVideoCodecType | Format d'encodage |
data | byte[] | Données de la trame encodée |
width | int | Largeur de la trame (pixels) |
height | int | Hauteur de la trame (pixels) |
timeStamp | long | Horodatage (millisecondes) ; si la valeur est 0, le SDK utilise l'horloge locale |
Valeurs de l'énumération AoqVideoCodecType
Valeur d'énumération | Valeur numérique | Description |
|---|---|---|
AoqVideoCodecTypeJPEG | 0 | Format d'encodage JPEG |
Remarques importantes
- Mode trame brute : vous devez appeler
startVideoCapture(isExternal=true)avant d'injecter des trames. En l'absence de cet appel, le SDK renvoie une erreur de paramètre. - Mode trame encodée : appelez
setVideoEncoderConfig(isExternal=true)et injectez les données immédiatement. L'appel àstartVideoCapturen'est pas requis. - Les modes trame brute et trame encodée sont mutuellement exclusifs : une seule interface d'injection peut être active à la fois.
- Le mode trame encodée ne prend actuellement en charge que le format JPEG.
- Après l'injection d'une trame, le SDK gère son cycle de vie en interne. Il est inutile de conserver les données une fois l'appel d'injection terminé.