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

  • 从iPhone摄像机获取帧的GPUImageVideoCamera
  • 一个GPUImageMovie,它是一个我想放置在实时摄像机源上的(MP4)视频文件。

  • 然后将GPUImageColorDodgeBlend连接到两个输出:
  • 一个GPUImageImageView,可提供实时混合效果预览。
  • 一个GPUImageMovieWriter,可在按下录制按钮后将影片写入存储。

  • 现在,在开始录制视频之前,一切都可以在100%的时间内正常进行。 GPUImageVideo混合在实时摄像机视频上,并且未报告任何问题或警告。

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

    但是,大约有10%到20%的时间(从我的观察中,这是相当随机的),在录制过程中似乎出现了问题(尽管屏幕上的预览仍然可以正常工作)。

    具体来说,我开始收到成百上千的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的工作方式在这里是否被我忽略了。

    最佳答案

    我已经找到了解决此问题的潜在解决方案,目前已经将其实现为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,而完全忽略第二个输入的frameTime。到目前为止,一切都像这样正常工作。 (鉴于GPUImageMovieWriter似乎坚持要增加frameTime,这仍然会引起别人的兴趣,因为CMTIME_IS_INDEFINITE(frameTime) == YES似乎坚持要增加frameTime,这是按原样不能保证的。)

    警告:如果仅处理静态图像,几乎可以肯定会完全中断,在这种情况下,您的第一个输入的ojit_code将具有ojit_code。

    10-08 08:06