Entrada de vídeo personalizada
Use uma fonte de vídeo externa em vez da câmera do dispositivo
Descreve os dois modos de entrada de vídeo personalizados compatíveis com o SDK do cliente AOQ (modo de quadro bruto e modo de quadro codificado), incluindo configuração e exemplos de código para cada um.
Visão geral
O módulo de vídeo integrado do SDK do cliente AOQ cobre necessidades básicas de vídeo, mas em alguns cenários o módulo de captura integrado pode não ser suficiente. A captura de vídeo personalizada é útil quando você precisa:
- Contornar conflitos de dispositivos de câmera ou problemas de compatibilidade.
- Alimente dados de vídeo de um sistema de captura personalizado ou arquivo de vídeo no SDK para transmissão.
- Publique quadros gerados por IA, gravações de tela ou conteúdo de câmera virtual por meio do SDK.
O SDK do cliente AOQ oferece suporte a dois modos de entrada de vídeo personalizados:
- Modo de quadro bruto: capture quadros de vídeo brutos em formatos como BGRA, I420, NV12 ou NV21 e, em seguida, envie-os para o SDK via
pushExternalVideoCapturedFrame. O SDK lida com codificação e transmissão internamente. - Modo de quadro codificado: codifique você mesmo os quadros de vídeo (atualmente apenas JPEG) e, em seguida, envie os dados codificados diretamente para o SDK via
pushExternalVideoEncodedFrame, ignorando o codificador interno do SDK.
Código de exemplo
Em breve.
Pré-requisitos
- Uma instância do mecanismo foi criada chamando
createEngine. - Uma conexão com o servidor foi estabelecida (o
onConnectionStatusChangeretorno de chamada foi relatadoAoqConnectionStatusConnected).
Implementação
Escolha um dos dois modos com base no seu caso de uso. Os dois modos não podem ser usados simultaneamente: apenas uma interface push pode estar ativa por vez.
Modo 1: modo de quadro bruto
Capture quadros de vídeo brutos em formatos como BGRA, I420, NV12 ou NV21 e envie-os para o SDK para codificação e transmissão. O SDK lida internamente com a codificação completa e o pipeline de envio.
1. Configure os parâmetros de codificação de vídeo
O codificador interno do SDK codifica os quadros brutos que você envia. Ajuste os parâmetros de codificação de acordo com seu caso de uso.
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);
Parâmetros:
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
| trackType | AoqTrackType | AoqTrackTypeVídeo | Tipo de trilha de vídeo |
| tipo de codec | AoqEncoderType | AoqEncoderTypeVideoH264 | Tipo de codificador |
| largura | interno | 720 | Largura de codificação (pixels) |
| altura | interno | 1280 | Altura de codificação (pixels) |
| FPS | interno | 5 | Taxa de quadros |
| taxa de bits | interno | 500000 | Taxa de bits inicial (bps) |
| minTaxa de bits | interno | 128.000 | Taxa de bits mínima (bps) |
| keyframeInterval | interno | 2 | Intervalo de quadro-chave (segundos) |
| éExterno | booleano | falso | Mantenha falso para o modo de quadro bruto |
| modo espelho | AoqMirrorMode | AoqMirrorModeDesativado | Modo espelho |
| modo de orientação | AoqOrientationMode | AoqOrientationModeAuto | Modo de orientação |
2. Inicie a captura de vídeo no modo de captura externa
Ligar startVideoCapture com isExternal=true para informar ao SDK para não abrir a câmera e esperar quadros de uma fonte externa. Isso é necessário para o modo de quadro bruto. Se você ignorar esta chamada, o SDK não consumirá nenhum quadro enviado por push.
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);
Parâmetros:
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
| largura | interno | 1280 | Largura de captura (ignorada quando isExternal=true) |
| altura | interno | 720 | Altura de captura (ignorada quando isExternal=true) |
| FPS | interno | 15 | Taxa de quadros de captura (ignorada quando isExternal=true) |
| éExterno | booleano | falso | verdadeiro: não abra a câmera; fonte externa fornece frames |
| direção da câmera | AoqCameraDireção | AoqCameraDirectionFrente | Direção da câmera (ignorada quando isExternal=true) |
3. Envie quadros de vídeo brutos
Ligar pushExternalVideoCapturedFrame para alimentar quadros brutos capturados no SDK. O SDK lida com codificação e transmissão.
Formatos suportados: BGRA, I420, NV12, NV21, RGBA. Nas plataformas Apple, a cópia zero do CVPixelBuffer também é suportada.
Formato 3.1 BGRA
BGRA é um formato compactado com 4 bytes por pixel (azul, verde, vermelho, alfa). Tamanho do quadro = largura x altura x 4 bytes.
// 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 Formato I420
I420 é um formato planar com três planos separados (Y, U, V). Tamanho do plano Y = largura x altura; Os planos U e V são cada um (largura/2) x (altura/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 Formato NV12 / NV21
NV12 e NV21 são formatos semiplanares que consistem em um plano Y e um plano UV intercalado. O NV12 intercala o UV nessa ordem; NV21 intercala VU. Tamanho do quadro = largura x altura x 3/2 bytes, compactado no data campo.
// 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);
Formato 3.4 CVPixelBuffer (plataformas Apple)
No iOS e no macOS, você pode passar um CVPixelBufferRef diretamente para transferência de cópia zero, evitando a sobrecarga de desempenho das cópias de memória.
// 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. Pare a captura de quadros brutos
Quando você não precisar mais enviar frames, pare primeiro o temporizador de envio e depois ligue stopVideoCapture para encerrar a captura de vídeo.
// 1. Stop the frame push timer
stopExternalFramePush();
// 2. Stop video capture
engine.stopVideoCapture();
Modo 2: modo de quadro codificado
Codifique você mesmo os quadros de vídeo (atualmente apenas JPEG) e envie os dados codificados diretamente para o SDK, ignorando o codificador interno. Este modo não requer chamada startVideoCapture ou quaisquer outras APIs relacionadas à captura.
1. Configure os parâmetros de codificação de vídeo e habilite a codificação externa
Ligar setVideoEncoderConfig com isExternal=true para informar ao SDK para ignorar o codificador interno e esperar dados pré-codificados de fora.
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);
Uma vez configurado, você pode enviar quadros codificados imediatamente - não há necessidade de chamar startVideoCapture.
2. Quadros de vídeo codificados por push
Ligar pushExternalVideoEncodedFrame para passar dados de vídeo pré-codificados diretamente para o SDK. Atualmente, apenas a codificação JPEG é suportada.
// 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);
Parâmetros AoqVideoEncodedFrame:
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
| codec | AoqVideoCodecType | AoqVideoCodecTypeJPEG | Formato de codificação; atualmente apenas JPEG é suportado |
| dados | byte[] | nulo | Dados de quadro codificados |
| largura | interno | 0 | Largura do quadro (pixels) |
| altura | interno | 0 | Altura do quadro (pixels) |
| carimbo de data / hora | longo | 0 | Carimbo de data/hora (milissegundos); quando 0, o SDK usa o relógio local |
3. Pare de enviar quadros codificados
O modo de quadro codificado não envolve nenhum dispositivo de captura, portanto, parar é simplesmente uma questão de interromper o cronômetro de envio.
stopExternalFramePush();
Referência
AoqVideoFrame (modo de quadro bruto)
| Campo | Tipo | Descrição |
|---|---|---|
| formato | AoqVideoPixelFormat | Formato de pixel |
| largura | interno | Largura do quadro (pixels) |
| altura | interno | Altura do quadro (pixels) |
| dados | byte[] | Dados em formato compactado (NV12/NV21/BGRA/RGBA) |
| dadosY | byte[] | Dados do avião I420 Y |
| dadosU | byte[] | Dados do avião I420 U |
| dadosV | byte[] | Dados do plano I420 V |
| passoY | interno | Passo da linha do plano Y I420 (bytes) |
| passoU | interno | Passo da linha do plano I420 U (bytes) |
| passoV | interno | Passo da linha plana I420 V (bytes) |
| ID da textura | interno | ID de textura do Android (TextureOES/Texture2D) |
| transformarMatriz | flutuar[] | Matriz de transformação de textura (4x4, linha principal) |
| eglContexto | Contexto EGL | Contexto EGL compartilhado do Android (para modo de textura) |
| pixelBuffer | CVPixelBufferRef | CVPixelBuffer de cópia zero da Apple (somente iOS/macOS) |
| carimbo de data / hora | longo | Carimbo de data/hora (milissegundos); quando 0, o SDK usa o relógio local |
Valores de enumeração AoqVideoPixelFormat
| Valor enum | Valor numérico | Descrição |
|---|---|---|
| AoqVideoPixelFormatUnknown | 0 | Formato desconhecido |
| AoqVideoPixelFormatI420 | 1 | Formato plano I420 |
| AoqVideoPixelFormatNV12 | 2 | Formato semiplanar NV12 (intercalado UV) |
| AoqVideoPixelFormatNV21 | 3 | Formato semiplanar NV21 (intercalado VU) |
| AoqVideoPixelFormatBGRA | 4 | Formato compactado BGRA |
| AoqVideoPixelFormatRGBA | 5 | Formato compactado RGBA |
| AoqVideoPixelFormatCVPixelBuffer | 6 | Apple CVPixelBuffer (somente iOS/macOS) |
| AoqVideoPixelFormatTextureOES | 7 | Textura externa Android OES |
| AoqVideoPixelFormatTexture2D | 8 | Textura 2D Android |
AoqVideoEncodedFrame (modo de quadro codificado)
| Campo | Tipo | Descrição |
|---|---|---|
| codec | AoqVideoCodecType | Formato de codificação |
| dados | byte[] | Dados de quadro codificados |
| largura | interno | Largura do quadro (pixels) |
| altura | interno | Altura do quadro (pixels) |
| carimbo de data / hora | longo | Carimbo de data/hora (milissegundos); quando 0, o SDK usa o relógio local |
Valores de enumeração AoqVideoCodecType
| Valor enum | Valor numérico | Descrição |
|---|---|---|
| AoqVideoCodecTypeJPEG | 0 | Formato de codificação JPEG |
Notas importantes
- Modo de quadro bruto: você deve ligar
startVideoCapture(isExternal=true)antes de empurrar quadros. Se você ignorar esta chamada, o SDK retornará um erro de parâmetro. - Modo de quadro codificado: chamada
setVideoEncoderConfig(isExternal=true)e pressione imediatamente - chamandostartVideoCapturenão é obrigatório. - O modo de quadro bruto e o modo de quadro codificado não podem ser usados simultaneamente: apenas uma interface push pode estar ativa por vez.
- O modo de quadro codificado atualmente suporta apenas JPEG.
- Depois de enviar um quadro, o SDK gerencia seu ciclo de vida internamente. Você não precisa reter os dados após o retorno da chamada push.