我有一个GPUImageColorDodgeBlend
过滤器,其中连接了两个输入:
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。