Cómo actualizar píxeles directamente – con CGImage y CGDataProvider directo

Pregunta real

Varias respuestas resolverán mi problema:

  1. ¿Puedo forzar una CGImage para recargar sus datos de un proveedor de datos directo (creado con CGDataProviderCreateDirect ) como CGContextDrawImage ? ¿O hay alguna otra forma en la que puedo establecer el self.layer.contents para hacerlo?
  2. ¿Existe una configuration CGContext , o truco que puedo utilizar para representar 1024×768 imágenes al less 30 fps de forma coherente con CGContextDrawImage .
  3. ¿Alguien ha podido usar con éxito CVOpenGLESTextureCacheCreateTextureFromImage para actualizaciones de búfer en time real con sus propios datos de textura? Creo que mi mayor problema es crear un CVImageBuffer mientras copyba las otras properties de la documentation de Apples para texturas. Si alguien tiene más información sobre esto, sería increíble.
  4. Cualquier otra guía sobre cómo puedo get una image de la memory en la pantalla a 30 fps.

Antecedentes (lotes):

Estoy trabajando en un proyecto donde necesito modificar los píxeles de los datos de imágenes NPOT en time real (mínimo de 30 fps) y dibujarlos en la pantalla en iOS.

Mi primer pensamiento fue utilizar OpenGL con glTexSubimage2D para actualizar, desafortunadamente eso terminó siendo muy lento (6 fps en iPad) ya que el controller swizzels y convierte mis datos RGB en cada ttwig a BGR. Entonces, envíenlo en BGR que diga, y yo también, pero por alguna razón no puede llamar a glTexSubImage2D con GL_BGR ir a la figura. Sé que la lentitud se debe a que no es el poder de 2 imágenes, pero mis requisitos lo dictan.

Más lecturas me llevaron a CVOpenGLESTextureCacheCreateTextureFromImage pero todos los ejemplos son de ello usando la input directa de camera para get un CVImageBufferRef . Intenté usar la documentation (sin comentarios de encabezado oficiales) para hacer que mi propio CVImageBuffer forme mis datos de image, pero no funcionaría con esto (no hay errores sino una textura vacía en el depurador), lo que me hace pensar que Apple creó esto específicamente para procesar datos de cameras en time real y que no se ha probado mucho fuera de esta área, sino IDK.

De todos modos, después de renunciar a mi dignidad al download OpenGL y cambiar mis pensamientos a CoreGraphics, llegué a esta pregunta, la forma más rápida de dibujar un búfer de pantalla en el iPhone, que recomienda utilizar una CGImage respaldada por CGDataProviderCreateDirect , que le permite devolver un puntero a los datos de image cuando el CGImage lo necesita, ¿verdad? Bueno, no parece funcionar como lo anuncian. Si uso CGContextDrawImage entonces todo funciona. Puedo modificar el búfer de píxeles, y cada sorteo, solicita los datos de image de mi proveedor de datos como debería, llamando a los methods en CGDataProviderDirectCallbacks ( Note: parecen tener una optimization incorporada, ignora el puntero actualizado si tiene el mismo dirección como el permeable). CGContextDrawImage no es súper rápido (alnetworkingedor de 18 fps) incluso con la interpolación de deshabilitación que aumentó eso a como 6 fps. Los documentos de Apple me dicen que usar self.layer.contents será mucho más rápido que CGContextDrawImage . El uso de self.layer.contents funciona para la primera asignación pero CGImage nunca solicita una recarga del proveedor de datos como lo hace CGContextDrawImage , incluso cuando [layer setNeedsDisplay] . En la pregunta SO a la que hice reference, el usuario muestra su solución al problema creando y destruyendo una nueva image CG de la fuente de datos en cada cuadro, un process irremediablemente lento (sí lo intenté), por lo tanto, el time para la pregunta real.

Nota : He descrito todas estas operaciones y sé que el problema realmente es glTexSubImage para OpenGL y CGContextDrawImage es realmente el problema de CoreGraphics, así que no hay respuestas de "ir perfil".

EDITAR El código fuente que demuestra esta técnica ahora se puede encontrar en http://github.com/narpas/image-sequence-streaming

Gracias a Brad Larson y David H por ayudarnos con este (ver nuestra discusión completa en los comentarios). Resulta que usar OpenGL y CoreVideo con CVOpenGLESTextureCache terminó siendo la forma más rápida de enviar imágenes en bruto a la pantalla (¡sabía que CoreGraphics no podía ser el más rápido!), Dándome 60 fps con imágenes a pantalla completa de 1024×768 en un iPad 1. Hay poco documentation sobre esto ahora, así que intentaré y explicaré todo lo posible para ayudar a las personas:

CVOpenGLESTextureCacheCreateTextureFromImage permite crear una textura OpenGL que tenga memory directamente asignada al CVImageBuffer que usa para crearlo. Esto le permite crear un CVPixelBuffer con sus datos brutos y modificar el puntero de datos recostackdo de CVPixelBufferGetBaseAddress . Esto le brinda resultados instantáneos en OpenGL sin necesidad de modificar o volver a cargar la textura real. Solo asegúrate de bloquear con CVPixelBufferLockBaseAddress antes de modificar los píxeles y desbloquear cuando CVPixelBufferLockBaseAddress terminado. Tenga en count que, en este momento, esto no funciona en el simulador de iOS, solo en el dispositivo que especulo que pertenece a la split VRAM / RAM, donde la CPU no tiene acceso directo a VRAM. Brad recomendó usar una compilation condicional para cambiar entre las actualizaciones de glTexImage2D sin glTexImage2D y usar cachings de textura.

Varias cosas a tener en count (una combinación de estas hizo que no funcione para mí):

  1. Prueba en el dispositivo
  2. Asegúrese de que CVPixelBuffer esté respaldado con kCVPixelBufferIOSurfacePropertiesKey vea enlace, por ejemplo (gracias de nuevo, Brad).
  3. Debe usar GL_CLAMP_TO_EDGE para datos de textura NPOT con OpenGL ES 2.0
  4. glBindTexture(CVOpenGLESTextureGetTarget(_cvTexture), CVOpenGLESTextureGetName(_cvTexture)); cachings de textura con glBindTexture(CVOpenGLESTextureGetTarget(_cvTexture), CVOpenGLESTextureGetName(_cvTexture)); no seas estúpido como yo y usa CVOpenGLESTextureGetTarget para ambos parameters.
  5. No recrear la textura de cada cuadro simplemente copie los datos de image en el puntero obtenido de CVPixelBufferGetBaseAddress para actualizar la textura.