Ejemplo de código iOS para compartir pantalla
Visión general
Esta guía muestra cómo utilizar el SDK de iOS para publicar un vídeo de pantalla compartida, utilizando la pantalla del dispositivo como fuente para el vídeo de la secuencia.
Configuración del proyecto
El código de esta sección se encuentra en compartir pantalla rama de la repo learning-opentok-iospor lo que, si aún no lo ha hecho, deberá clonar el repositorio en un directorio local. esto se puede hacer utilizando la línea de comandos:
A continuación, echa un vistazo a la sucursal:
Esta rama muestra cómo capturar la pantalla (un UIView) usando un capturador de vídeo personalizado. Abre el proyecto en XCode para seguir el proceso.
Importante: Tenga en cuenta que su ID de la aplicación es tu Clave API.
Explorar el código
Esta muestra utiliza el initCapture, releaseCapture, startCapture, stopCapturey isCaptureStarted de la clase OTVideoKit para gestionar las funciones de captura de la aplicación.
La clase ViewController crea una sesión, instancia los suscriptores y configura el editor.
La clase OTKBasicVideoCapturer crea un fotograma, captura una captura de pantalla, etiqueta el fotograma con una marca de tiempo y lo guarda en una instancia de consumer.
El editor accede al consumidor para obtener la trama.
En initCapture se utiliza para inicializar la captura y establece el valor para el formato de píxel de un objeto OTVideoFrame. En este ejemplo, se establece en ARGB.
- (void)initCapture
{
self.format = [[OTVideoFormat alloc] init];
self.format.pixelFormat = OTPixelFormatARGB;
}
En releaseCapture borra el búfer de memoria:
- (void)releaseCapture
{
self.format = nil;
}
En startCapture crea un subproceso independiente y llama al método produceFrame para iniciar las capturas de pantalla:
- (int32_t)startCapture
{
self.captureStarted = YES;
dispatch_after(kTimerInterval,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),
^{
@autoreleasepool {
[self produceFrame];
}
});
return 0;
}
En produceFrame método:
- Define el marco para las imágenes capturadas
- Crea una marca de tiempo para etiquetar una imagen capturada
- Realiza una captura de pantalla
- Convierte la captura de pantalla a un formato legible
- Etiqueta la captura de pantalla con una marca de tiempo
- Calcula el tamaño de la imagen
- Establece el consumeFrame con la imagen
- Se llama a sí mismo 15 veces por segundo una vez iniciada la captura
El marco para las imágenes capturadas se establece como un objeto de OTVideoFrame. Las propiedades de OTVideoFrame definen los planos, la marca de tiempo, la orientación y el formato de un fotograma.
OTVideoFrame *frame = [[OTVideoFrame alloc] initWithFormat:self.format];
Se crea una marca de tiempo para etiquetar la imagen. Cada imagen se etiqueta con una marca de tiempo para que tanto el editor como el suscriptor puedan crear la misma línea de tiempo y referenciar los fotogramas en el mismo orden.
static mach_timebase_info_data_t time_info;
uint64_t time_stamp = 0;
time_stamp = mach_absolute_time();
time_stamp *= time_info.numer;
time_stamp /= time_info.denom;
Se llama al método de captura de pantalla para obtener una imagen de la pantalla.
CGImageRef screenshot = [[self screenshot] CGImage];
El método fillPixelBufferFromCGImage convierte los datos de imagen de una CGImage en un CVPixelBuffer.
[self fillPixelBufferFromCGImage:screenshot];
El fotograma se etiqueta con una marca de tiempo y se establecen la velocidad de captura en fotogramas por segundo y el retardo entre capturas.
CMTime time = CMTimeMake(time_stamp, 1000);
frame.timestamp = time;
frame.format.estimatedFramesPerSecond = kFramesPerSecond;
frame.format.estimatedCaptureDelay = 100;
El número de bytes de una fila se multiplica por la altura de la imagen para obtener su tamaño. Tenga en cuenta que la matriz de un solo elemento y los bytes por fila se basan en una especificación de un solo plano de 4 bytes de una imagen RGB.
frame.format.imageWidth = CVPixelBufferGetWidth(pixelBuffer);
frame.format.imageHeight = CVPixelBufferGetHeight(pixelBuffer);
frame.format.bytesPerRow = [@[@(frame.format.imageWidth * 4)] mutableCopy];
frame.orientation = OTVideoOrientationUp;
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
uint8_t *planes[1];
planes[0] = CVPixelBufferGetBaseAddress(pixelBuffer);
[frame setPlanesWithPointers:planes numPlanes:1];
La imagen se guarda en una instancia del consumidor. El editor accede a las imágenes capturadas a través de la instancia del consumidor.
[self.consumer consumeFrame:frame];
El búfer de píxeles se vacía y se utiliza una cola con prioridad de fondo (independiente de la cola utilizada por la interfaz de usuario) para capturar imágenes. Si la captura de imágenes está en curso, el produceFrame se llama a sí mismo 15 veces por segundo.
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
if (self.captureStarted) {
dispatch_after(kTimerInterval,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),
^{
@autoreleasepool {
[self produceFrame];
}
});
}
En screenshot toma una captura de pantalla y devuelve una imagen. Este método es llamado por el produceFrame método.
- (UIImage *)screenshot
{
CGSize imageSize = CGSizeZero;
imageSize = [UIScreen mainScreen].bounds.size;
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
UIWindow *window = [UIApplication sharedApplication].keyWindow;
if ([window respondsToSelector:
@selector(drawViewHierarchyInRect:afterScreenUpdates:)])
{
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:NO];
}
else {
[window.layer renderInContext:UIGraphicsGetCurrentContext()];
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}