IOSurfaces: artefactos en video e incapaces de tomar superficies de video

Esta es una pregunta de 2 partes. Tengo el siguiente código funcionando que toma la superficie de la pantalla actual y crea un video fuera de las superficies (todo sucede en segundo plano).

for(int i=0;i<100;i++){ IOMobileFramebufferConnection connect; kern_return_t result; IOSurfaceRef screenSurface = NULL; io_service_t framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleH1CLCD")); if(!framebufferService) framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleM2CLCD")); if(!framebufferService) framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleCLCD")); result = IOMobileFramebufferOpen(framebufferService, mach_task_self(), 0, &connect); result = IOMobileFramebufferGetLayerDefaultSurface(connect, 0, &screenSurface); uint32_t aseed; IOSurfaceLock(screenSurface, kIOSurfaceLockReadOnly, &aseed); uint32_t width = IOSurfaceGetWidth(screenSurface); uint32_t height = IOSurfaceGetHeight(screenSurface); m_width = width; m_height = height; CFMutableDictionaryRef dict; int pitch = width*4, size = width*height*4; int bPE=4; char pixelFormat[4] = {'A','R','G','B'}; dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(dict, kIOSurfaceIsGlobal, kCFBooleanTrue); CFDictionarySetValue(dict, kIOSurfaceBytesPerRow, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pitch)); CFDictionarySetValue(dict, kIOSurfaceBytesPerElement, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &bPE)); CFDictionarySetValue(dict, kIOSurfaceWidth, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width)); CFDictionarySetValue(dict, kIOSurfaceHeight, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height)); CFDictionarySetValue(dict, kIOSurfacePixelFormat, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, pixelFormat)); CFDictionarySetValue(dict, kIOSurfaceAllocSize, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &size)); IOSurfaceRef destSurf = IOSurfaceCreate(dict); IOSurfaceAcceleratorRef outAcc; IOSurfaceAcceleratorCreate(NULL, 0, &outAcc); IOSurfaceAcceleratorTransferSurface(outAcc, screenSurface, destSurf, dict, NULL); IOSurfaceUnlock(screenSurface, kIOSurfaceLockReadOnly, &aseed); CFRelease(outAcc); // MOST RELEVANT PART OF CODE CVPixelBufferCreateWithBytes(NULL, width, height, kCVPixelFormatType_32BGRA, IOSurfaceGetBaseAddress(destSurf), IOSurfaceGetBytesPerRow(destSurf), NULL, NULL, NULL, &sampleBuffer); CMTime frameTime = CMTimeMake(frameCount, (int32_t)5); [adaptor appendPixelBuffer:sampleBuffer withPresentationTime:frameTime]; CFRelease(sampleBuffer); CFRelease(destSurf); frameCount++; } 

PS: Las últimas 4-5 líneas de código son las más relevantes (si necesita filtrar).

1) El video que se produce tiene artefactos. He trabajado anteriormente en videos y también me he encontrado con un problema similar. Supongo que puede haber 2 razones para esto:
yo. El PixelBuffer que se pasa al adaptador se modifica o se libera antes de que finalice el process (encoding + escritura). Esto puede deberse a llamadas asincrónicas. Pero no estoy seguro si este es el problema y cómo resolverlo.
ii. Las marcas de time que se pasan son imprecisas (por ejemplo, 2 cuadros que tienen la misma timestamp o un cuadro que tiene una timestamp menor que el cuadro anterior). Desconecté los valores de date y hora y esto no parece ser el problema.

2) El código anterior no puede agarrar superficies cuando se reproduce un video o cuando jugamos juegos. Todo lo que obtengo es una pantalla en blanco en la salida. Esto podría deberse a la desencoding acelerada por hardware que ocurre en tales casos.

Cualquier input en cualquiera de las 2 partes de las preguntas será realmente útil. Además, si tiene algún buen enlace para leer en IOSurfaces en general, publíquelo aquí.

Hice un poco de experimentación y llegué a la conclusión de que la superficie de la pantalla desde la que se copy el contenido está cambiando incluso antes de que se complete la transferencia del contenido (llamada a IOSurfaceAcceleratorTransferSurface ()). Estoy usando un locking (probado tanto asíncrono como de solo lectura), pero el iOS lo reemplaza. Cambié el código entre la parte de locking / deslocking al siguiente mínimo:

 IOSurfaceLock(screenSurface, kIOSurfaceLockReadOnly, &aseed); aseed1 = IOSurfaceGetSeed(screenSurface); IOSurfaceAcceleratorTransferSurface(outAcc, screenSurface, destSurf, dict, NULL); aseed2 = IOSurfaceGetSeed(screenSurface); IOSurfaceUnlock(screenSurface, kIOSurfaceLockReadOnly, &aseed); 

La function GetSeed indica si los contenidos de la superficie han cambiado. Y registré un recuento que indica la cantidad de ttwigs para las cuales cambia la semilla. El recuento no fue cero. Entonces, el siguiente código resolvió el problema:

 if(aseed1 != aseed2){ //Release the created surface continue; //Do not use this surface/frame since it has artefacts } 

Sin embargo, esto afecta el performance ya que muchos frameworks / superficies son rechazados debido a artefactos. Cualquier adiciones / correcciones a esto será útil.