GPUImageMovieWriter帧presentationTime

时间:2013-01-06 17:27:29

标签: iphone objective-c ios opengl-es gpuimage

我有一个GPUImageColorDodgeBlend过滤器,连接了两个输入:

  1. 正在从iPhone摄像机获取帧的GPUImageVideoCamera
  2. 一个GPUImageMovie,这是一个(MP4)视频文件,我想放在实时相机Feed上。
  3. 然后GPUImageColorDodgeBlend连接到两个输出:

    1. 一个GPUImageImageView,用于提供正在进行的混合的实时预览。
    2. 按下录制按钮后,GPUImageMovieWriter将电影写入存储空间。
    3. 现在,在视频开始录制之前,所有内容都可以正常运行。 GPUImageVideo在实时摄像机视频中混合使用,并且不会报告任何问题或警告。

      然而,当GPUImageMovieWriter开始录制时,事情随机开始出错。大约80-90%的时间,GPUImageMovieWriter完美运行,没有错误或警告,输出视频写得正确。

      然而,大约10-20%的时间(从我可以看到,这是相当随机的),在录制过程中似乎出现了问题(虽然屏幕预览继续正常工作)。 / p>

      具体来说,我开始得到数百&数百Program appending pixel buffer at time:个错误。

      此错误源自- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex中的GPUImageWriter方法。

      此问题是由报告给此方法的frameTime值的问题触发的。

      从我所看到的,问题是由于作者有时接收由摄像机编号的帧(其中往往具有非常高的时间值,如 64616612394291 ,时间刻度 1000000000) )。但是,有时候作者会得到编号为GPUImageMovie的帧编号要低得多(例如 200200 ,时间刻度 30000 )。

      只要帧值增加,GPUImageWriter似乎很高兴,但一旦帧值减小,它就会停止写入并发出Program appending pixel buffer at time:个错误。

      我似乎在做一些相当普遍的事情,并且这在任何地方都没有被报告为错误,所以我的问题是(对任何或所有这些的答案都表示赞赏 - 他们并非都需要必须按顺序回答单独的问题):

      • frameTime值来自哪里 - 为什么frameTime根据GPUImageVideoCamera来源或GPUImageMovie进行编号似乎是如此随意资源?为什么它在每个帧之间是替代的 - 帧编号方案不应该在所有帧中是统一的吗?

      • 我是否认为此问题是由非增加的frameTime引起的?

      • ......如果是这样,为什么GPUImageView在100%的时间内接受并在屏幕上显示frameTime就好了,但GPUImageMovieWriter要求它们是有序?

      • ......如果是这样,我怎样才能确保进来的frameTime有效?我尝试添加if (frameTime.value < previousFrameTime.value) return;以跳过任何较少编号的帧 - 大部分时间都可以。不幸的是,当我在playsAtActualSpeed上设置GPUImageMovie时,这种情况的效果远远低于所有,这些帧最终会在某个点之后被跳过。

      ... 也许这是一个错误,在这种情况下我需要在GitHub上报告 - 但我有兴趣知道这里是否有我忽略的东西在frameTime的工作方式。

1 个答案:

答案 0 :(得分:3)

我找到了这个问题的潜在解决方案,我现在已经将其作为黑客实施,但可以想象可以扩展到正确的解决方案。

我已经将时序源追溯到GPUImageTwoInputFilter,它基本上将两个输入源复用为单个帧输出。

在方法- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex中,过滤器会一直等待,直到它从第一个源(textureInput == 0)和第二个源收集了一个帧,然后将这些帧转发到其目标。

问题(我看到它的方式)是该方法只使用frameTime中的第二个帧(不包括我不考虑CMTIME_IS_INDEFINTE(frameTime) == YES的静止图像的情况因为我不使用静止图像),这可能并不总是相同的帧(无论出于何种原因)。

检查两个帧并将其发送以进行处理的相关代码如下:

  if ((hasReceivedFirstFrame && hasReceivedSecondFrame) || updatedMovieFrameOppositeStillImage)
    {
        [super newFrameReadyAtTime:frameTime atIndex:0]; // this line has the problem
        hasReceivedFirstFrame = NO;
        hasReceivedSecondFrame = NO;
    }

我所做的是将上述代码调整为[super newFrameReadyAtTime:firstFrameTime atIndex:0],以便始终使用第一个输入中的frameTime忽略第二个输入中的frameTime。到目前为止,这一切都很好。 (仍然有兴趣让某些人知道为什么这是用这种方式编写的,因为GPUImageMovieWriter似乎坚持要增加frameTime s,而方法原样并不能保证。)< / p>

警告:如果您只使用静止图像,这几乎肯定会完全破坏,在这种情况下,您的第一个输入CMTIME_IS_INDEFINITE(frameTime) == YES会有frameTime