2012-02-17 110 views
14

我正在寻找最快的方式来解码iPhone上的本地mpeg-4视频帧。我只关心每10帧中像素的亮度值。我不需要在任何地方渲染视频。解码iPhone GPU上的视频帧

我试过ffmpeg,AVAssetReader,ImageAssetGenerator,OpenCV和MPMoviePlayer,但它们都太慢了。我能得到的最快速度是〜2x(一分钟内扫描2分钟的视频)。我想要更接近10倍的东西。

假设我上面的尝试没有使用GPU,是否有任何方法可以通过GPU上运行的某些东西来实现我的目标? OpenGL似乎主要用于渲染输出,但我已经看到它用作传入视频的过滤器。也许这是一个选择?

在此先感谢!

回答

3

如果您愿意使用仅适用于iOS 5的解决方案,请查看AVCaputureSession上2011年WWDC会话中的示例应用程序ChromaKey。

该演示从内置摄像头捕获30帧FPS视频,并将每帧作为纹理传递给OpenGL。然后它使用OpenGL来处理该帧,并可选择将结果写入输出视频文件。

该代码使用一些严重的低级魔法将AVCaptureSession的Core Video Pixel缓冲区绑定到OpenGL,以便它们在图形硬件中共享内存。

将AVCaptureSession更改为使用电影文件作为输入而不是相机输入应该相当简单。

您可能可以设置会话以Y/UV形式传递帧,而不是RGB,其中Y分量是亮度。如果不这样做,编写一个将每个像素的RGB值转换为亮度值的着色器将非常简单。

你应该可以在所有帧上做所有这些,而不是每10帧。

+0

看起来好像我需要成为WWDC 2011的参与者才能获得该示例。我仍然担心这是实时转码。我想获得15倍的速度(1分钟内扫描15分钟的视频)。我认为瓶颈在帧解码中。 – 2012-03-02 17:35:34

+0

@simon。d - 我在我的答案中描述了ChromaKey示例中使用的技术:http://stackoverflow.com/a/9704392/19679,您可以抓住我的GPUImage代码来查看编码影片的动作。不过,我还没有更新我的电影阅读代码以使用快速纹理上传。由于iOS设备具有用于解码H.264的专用硬件,我感到有理由肯定的说,与使用iOS 5.0快速纹理上传的AVFoundation相比,您无法获得更快的电影解析。 – 2012-03-22 23:34:25

+0

Apple的RosyWriter示例代码还演示了此AVCaptureSession - > OpenGL链接。请参阅[这里](https://developer.apple.com/library/ios/samplecode/RosyWriter/Introduction/Intro.html)。 – bcattle 2014-05-27 18:57:16

0

看似vImage可能是合适的,假设你可以使用iOS 5.每个第10帧似乎都是使用像vImage这样的框架的理由。但是,任何类型的实时实时处理几乎肯定会需要OpenGL。

+0

Thanks @LucasTizma。我会看看vImage。不过,我的目标是比实时处理更快。这就是为什么我只想每10帧做一次。所以想象一下,视频已经记录在手机上,现在我想尝试扫描。这是否排除vImage? – 2012-02-21 06:55:36

+0

vImage只是快速执行图像处理操作的一种手段。我想你会没事的。看起来,除了OpenGL以外,这是您最快的解决方案。其他人,如果我错了,随时纠正我。 – LucasTizma 2012-02-22 02:00:09

+0

但是vImage只有在解码帧后才有用?如果是这样,我不知道我需要它。 90%的工作实际上是对帧进行解码,而不是处理像素。 – 2012-02-23 19:15:06

0

假设你的应用的瓶颈是在视频帧转换为可显示的格式(如RGB)的代码,你可能会感兴趣的代码共享我曾用于convert one .mp4 frame (encoded as YV12) to RGB using Qt and OpenGL。此应用程序将该帧上传到GPU并激活GLSL fragment shader以执行从YV12到RGB的转换,因此它可以显示在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);" 
    "}"