【问题标题】:GPUImageMovieWriter frame presentationTimeGPUImageMovieWriter 帧演示时间
【发布时间】:2013-01-06 17:27:28
【问题描述】:

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

  1. GPUImageVideoCamera 正在从 iPhone 摄像机获取帧。
  2. GPUImageMovie 是一个 (MP4) 视频文件,我想将它放在实时摄像机源上。

GPUImageColorDodgeBlend 然后连接到两个输出:

  1. GPUImageImageView 提供实时混合效果预览。
  2. 按下录制按钮后,GPUImageMovieWriter 将电影写入存储空间。

现在,在视频开始录制之前,一切都 100% 正常。 GPUImageVideo 与实时摄像头视频完美融合,没有报告任何问题或警告。

但是,当GPUImageMovieWriter 开始录制时,事情开始随机出错。大约 80-90% 的时间,GPUImageMovieWriter 工作正常,没有错误或警告,并且输出视频正确写入。

但是,大约 10-20% 的时间(据我所知,这是相当随机的),在录制过程中似乎出现问题(尽管屏幕预览继续正常工作)。

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

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

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

据我所知,问题是由于作者有时会收到由摄像机编号的帧(其往往具有极高的时间值,例如 64616612394291,时间刻度为 1000000000 )。但是,有时编写者会得到编号为 GPUImageMovie 的帧,这些帧的编号要低得多(例如 200200,时间刻度为 30000)。

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

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

  • frameTime 值从何而来——为什么frameTime 是根据GPUImageVideoCamera 源还是GPUImageMovie 源编号看起来如此随意?为什么它会在每个帧之间交替——帧编号方案不应该在所有帧之间保持一致吗?

  • 我认为这个问题是由不增加的frameTimes 引起的是否正确?

  • ...如果是这样,为什么GPUImageView 接受并在屏幕上显示frameTimes 100% 的时间都很好,而GPUImageMovieWriter 要求它们被订购?

  • ...如果是这样,我如何确保进来的frameTimes 是有效的?我尝试添加if (frameTime.value < previousFrameTime.value) return; 以跳过任何有效的编号较小的帧 - 大多数情况下。不幸的是,当我在GPUImageMovie 上设置playsAtActualSpeed 时,这往往变得不那么有效,因为所有帧最终都会在某个点之后被跳过。

...也许这是一个错误,在这种情况下,我需要在 GitHub 上报告它——但我很想知道我在这里是否忽略了一些东西frameTimes 的工作原理。

【问题讨论】:

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


    【解决方案1】:

    我已经找到了这个问题的潜在解决方案,我现在已经将它作为一个 hack 来实现,但可以想象它可以扩展到一个适当的解决方案。

    我已将时间源追溯到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并完全忽略@987654329 @来自第二个输入。到目前为止,一切正常。 (考虑到GPUImageMovieWriter 似乎坚持增加frameTimes,仍然有兴趣让我知道为什么要这样写,但该方法原样不能保证。)

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

    【讨论】:

    • 是的,整个框架中的时序代码需要一些爱。多个视频源之间没有同步,而且我没有考虑两个视频源混合在一起的情况,所以这里出现问题也就不足为奇了。我没有花太多时间在电影输入和录制方面,所以如果你在这方面有更多改进,我很乐意接受拉取请求来解决这个问题。
    • 感谢您的意见 Brad,我只需要在 updatedMovieFrameOppositeStillImage 案例中加入一些注意事项,然后我将提交一个拉取请求以进行修复。希望仅从一个输入中获取frameTimes 不会产生不良的副作用......(到目前为止我没有遇到任何问题,但我再次在一个相当具体的用例中使用 GPUImage)
    • 我在这里有一个类似的设置,并且使用带有可可豆荚的版本构建它以某种方式工作正常。但是我需要一些新的东西和错误修复,所以我从 gpuimage master 编译,现在它不再工作了,因为它变得非常慢。所以基本上现在我不能将 GPUImageMovie 和 GPUImageVideoCamera 一起使用,有什么想法吗?
    猜你喜欢
    • 2015-04-24
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多