2012-02-17 13 views
14

Estoy buscando la manera más rápida de decodificar los marcos de un video de MPEG local 4 en el iPhone. Simplemente me interesan los valores de luminancia de los píxeles en cada 10º fotograma. No necesito renderizar el video en ningún lado.Decodificar marcos de video en la GPU de iPhone

He probado ffmpeg, AVAssetReader, ImageAssetGenerator, OpenCV y MPMoviePlayer, pero son demasiado lentos. La velocidad más rápida que puedo obtener es ~ 2x (2 minutos de video escaneados en un minuto). Me gustaría algo más cerca de 10x.

Suponiendo que mis intentos anteriores no utilizaron la GPU, ¿hay alguna manera de lograr mi objetivo con algo que se ejecute en la GPU? Parece que OpenGL es principalmente para renderizar resultados, pero lo he visto como filtros para video entrante. Tal vez esa es una opción?

¡Gracias de antemano!

Respuesta

3

Si está dispuesto a utilizar una solución solo iOS 5, eche un vistazo a la aplicación de muestra ChromaKey de la sesión WWDC 2011 en AVCaputureSession.

Esa demostración captura 30 FPS de video de la cámara incorporada y pasa cada cuadro a OpenGL como una textura. A continuación, utiliza OpenGL para manipular el marco y, opcionalmente, escribe el resultado en un archivo de video de salida.

El código utiliza una magia grave de bajo nivel para vincular un almacenamiento intermedio de Core Video Pixel de una sesión AVCaptureSession a OpenGL para que compartan memoria en el hardware de gráficos.

Debería ser bastante sencillo cambiar la sesión de AVCaptureSession para usar un archivo de película como entrada en lugar de entrada de cámara.

Probablemente podría configurar la sesión para entregar marcos en formato Y/UV en lugar de RGB, donde el componente Y es la luminancia. De lo contrario, sería una cuestión bastante simple escribir un sombreador que convertiría los valores RGB para cada píxel en valores de luminancia.

Debería poder hacer todo esto en TODOS los cuadros, no solo en cada décimo marco.

+0

bummer Parece que necesito ser un asistente WWDC 2011 para obtener esa muestra. Todavía me preocupa que esto sea una transcodificación en tiempo real. Quiero obtener 15x velocidades (15 minutos de video escaneados en 1 minuto). Creo que el cuello de la botella está en la decodificación del marco. –

+0

@simon.d - Describo la técnica utilizada en el ejemplo ChromaKey en mi respuesta aquí: http://stackoverflow.com/a/9704392/19679, y puede tomar mi código GPUImage para ver esto en acción para codificar películas. Sin embargo, aún no actualicé el código de lectura de mi película para usar cargas rápidas de textura. Debido al hecho de que los dispositivos iOS tienen hardware dedicado para decodificar H.264, me siento razonablemente seguro de que no obtendrá un análisis más rápido de las películas que el uso de AVFoundation con las cargas de textura rápida de iOS 5.0. –

+0

El código de ejemplo RosyWriter de Apple también demuestra este AVCaptureSession -> enlace OpenGL. Ver [aquí] (https://developer.apple.com/library/ios/samplecode/RosyWriter/Introduction/Intro.html). – bcattle

0

Al parecer, vImage podría ser apropiado, suponiendo que puede usar iOS 5. Cada 10º fotograma parece estar dentro de lo razonable para usar un marco como vImage. Sin embargo, cualquier tipo de procesamiento real en tiempo real va a requerir OpenGL.

+0

Gracias @LucasTizma. Echaré un vistazo a vImage. Sin embargo, mi objetivo es tener un procesamiento más rápido que en tiempo real. Es por eso que solo quería hacer cada décimo marco. Imagine que el video ya está grabado en el teléfono y ahora quiero intentar escanearlo. ¿Eso descarta vImage? –

+0

vImage es solo un medio para realizar rápidamente operaciones de procesamiento de imágenes. Creo que estarás bien. Aparentemente, aparte de OpenGL, esta es la solución más rápida posible. Otros, siéntanse libres de corregirme si me equivoco. – LucasTizma

+0

, pero ¿vImage solo es útil una vez que he descodificado el marco? Si es así, no estoy seguro de que lo necesite. El 90% del trabajo en realidad está decodificando el cuadro, no procesando los píxeles. –

0

Suponiendo que el cuello de botella de su aplicación está en el código que convierte los marcos de video a un formato visualizable (como RGB), podría interesarle un código compartido que se usó para convert one .mp4 frame (encoded as YV12) to RGB using Qt and OpenGL. Esta aplicación carga el marco a la GPU y activa un GLSL fragment shader para hacer la conversión de YV12 a RGB, por lo que podría mostrarse en un QImage.

static const char *p_s_fragment_shader = 
    "#extension GL_ARB_texture_rectangle : enable\n" 
    "uniform sampler2DRect tex;" 
    "uniform float ImgHeight, chromaHeight_Half, chromaWidth;" 
    "void main()" 
    "{" 
    " vec2 t = gl_TexCoord[0].xy;" // get texcoord from fixed-function pipeline 
    " float CbY = ImgHeight + floor(t.y/4.0);" 
    " float CrY = ImgHeight + chromaHeight_Half + floor(t.y/4.0);" 
    " float CbCrX = floor(t.x/2.0) + chromaWidth * floor(mod(t.y, 2.0));" 
    " float Cb = texture2DRect(tex, vec2(CbCrX, CbY)).x - .5;" 
    " float Cr = texture2DRect(tex, vec2(CbCrX, CrY)).x - .5;" 
    " float y = texture2DRect(tex, t).x;" // redundant texture read optimized away by texture cache 
    " float r = y + 1.28033 * Cr;" 
    " float g = y - .21482 * Cb - .38059 * Cr;" 
    " float b = y + 2.12798 * Cb;" 
    " gl_FragColor = vec4(r, g, b, 1.0);" 
    "}"