Swift

Inicialización de la captura

En este ejemplo, la aplicación utiliza un capturador de vídeo personalizado para publicar píxeles aleatorios (ruido blanco). Esto se hace simplemente para ilustrar los principios básicos de la configuración de un capturador de vídeo personalizado.

En el principal VonageVideoManagerdespués de llamar a session.publish(publisher, error: &error) para iniciar la publicación de un flujo de audio-vídeo, el videoCapture propiedad del OTPublisher se establece en una instancia de BasicVideoCapturer:

publisher.videoCapture = BasicVideoCapturer()

BasicVideoCapturer es una clase personalizada que implementa la función OTVideoCapture (definido en el SDK de Vonage para iOS). Este protocolo te permite definir una capturadora de vídeo personalizada para que la utilice un editor de OpenTok.

El initCapture inicializa la configuración de captura que utilizará el capturador de vídeo personalizado. En la implementación personalizada de OTVideoCapture (OTKBasicVideoCapturer), el initCapture establece las propiedades del método videoFormat propiedad:

func initCapture() {
    let format = OTVideoFormat()
    format.pixelFormat = .ARGB
    format.bytesPerRow = [NSNumber(value: imageWidth * 4)]
    format.imageHeight = imageHeight
    format.imageWidth = imageWidth
    
    self.videoFormat = format
}

El OTVideoFormat La clase está definida por el SDK de Vonage para iOS. En este código de ejemplo, el formato del capturador de vídeo se configura para utilizar ARGB como formato de píxeles, con un número específico de bytes por fila, altura y anchura.

El videoCaptureConsumer establece una propiedad OTVideoCaptureConsumer objeto que el consumidor de vídeo utiliza para transmitir fotogramas de vídeo a la transmisión del editor. En BasicVideoCaptureresta propiedad se sintetiza a partir del protocolo:

var videoCaptureConsumer: OTVideoCaptureConsumer?

Captura inicial

El start El método se invoca cuando un emisor comienza a grabar vídeo para enviarlo como transmisión a la sesión de Vonage. Esto ocurrirá después de que el Session.publish(_:error:) . En el BasicVideoCapturer, este método activa produceFrame en una cola de fondo:

//
//  returns:
//  - a negative value for error
//  - 0 value when all is OK
//
func start() -> Int32 {
    self.captureStarted = true
    
    // Start the frame loop on a background queue
    DispatchQueue.global(qos: .background).asyncAfter(deadline: timerInterval) { [weak self] in
        self?.produceFrame()
    }
    
    return 0
}

Personalización del marco

El produceFrame El método genera un OTVideoFrame objeto que representa un fotograma de vídeo. En este caso, el fotograma contiene píxeles aleatorios que ocupan la altura y la anchura definidas:

private func produceFrame() {
    guard let format = self.videoFormat else { return }
    
    let frame = OTVideoFrame(format: format)
    
    // Allocate buffer for image data
    let bufferSize = Int(imageWidth * imageHeight * 4)
    let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
    
    // Generate random pixels
    for i in stride(from: 0, to: bufferSize, by: 4) {
        buffer[i]     = UInt8.random(in: 0...255) // A
        buffer[i + 1] = UInt8.random(in: 0...255) // R
        buffer[i + 2] = UInt8.random(in: 0...255) // G
        buffer[i + 3] = UInt8.random(in: 0...255) // B
    }
    
    // Pass pointer to Vonage
    var planePointer: UnsafeMutablePointer<UInt8> = buffer
    withUnsafeMutablePointer(to: &planePointer) { pointerToPlanePointer in
        frame.setPlanesWithPointers(UnsafeMutableRawPointer(pointerToPlanePointer).assumingMemoryBound(to: UnsafeMutablePointer<UInt8>.self), numPlanes: 1)
    }
    
    // Send frame to consumer
    self.videoCaptureConsumer?.consumeFrame(frame)
    
    buffer.deallocate()
    
    if self.captureStarted {
        DispatchQueue.global(qos: .background).asyncAfter(deadline: timerInterval) { [weak self] in
            self?.produceFrame()
        }
    }
}

El método pasa el marco al consumeFrame método del OTVideoCaptureConsumer. Esto hace que el editor envíe el fotograma de datos al flujo de vídeo de la sesión.