为了将算法执行流程与视频流交换流程分开,需要使用PRD出发软中断,再执行算法或视频流交换操作。

但是在实践中发现,当视频流交换函数触发的时钟周期为50ms时,会随机出现部分视频帧为旧数据的问题,造成视频播放时内容回跳,非常影响显示效果。经过试验,排除了缓冲区过小,硬件计算性能等问题,最后将问题锁定在vpfe和vpbe时数据交换失败上,并解决。

原理说明

在解决问题前首先需要理解sdk中视频帧交换的过程,在DSP/BIOS VPFE Device Driver
User's Guide中可以查到,vpfe和vpbe各有两个缓冲队列READY Queue和FREE Queue,它们会不断从READY队列中存入/取出数据,并放入FREE队列中。使用FVID_exchange可以将一个空的buffer加入READY队列并从FREE队列中取出一帧,这也是例子中所推荐的方法,在未使用PRD时也可以流程的执行。

但是,加入PRD触发的频率大于视频输入帧率的时候,vpfe无法及时提供视频帧,导致FVID_exchange失败。由于文档中并没有提失败时的算法内部处理流程,因此我们按照文档中说明的FVID_exchange是FVID_queue和FVID_dequeuer的集合,将这个方法结构,且不对异常进行处理。

//FVID_exchange(hGioVpfeCcdc, &frameBuffPtr);
FVID_queue(hGioVpfeCcdc, frameBuffPtr)
FVID_dequeue(hGioVpfeCcdc, &frameBuffPtr);

//FVID_exchange(hGioVpbeVid0, &frameBuffPtr);
FVID_queue(hGioVpbeVid0, frameBuffPtr);
FVID_dequeue(hGioVpbeVid0, &frameBuffPtr);

结构后执行发现和使用exchange时的效果类似,因此推测FVID_exchange对于出队失败并没有特殊处理。当这种情况出现时,frameBuffPtr早vpfe中并没有被更新,并直接放入vpbe的READ队列中,这时假如vpfe在vpbe播放这一帧之前更新了这个数据帧,就会造成某一帧显示的内容超前其它帧。假如没有更新这个数据帧,则会导致某一帧显示的内容落后其它帧。

修改方案

在理解原理后,就可以发现只要在出队失败时,framebuffer所指向的内容是过期的,不能再执行这一帧的入队操作,因此修改程序执行逻辑如下:

if ( FVID_dequeue(hGioVpfeCcdc, &frameBuffPtr) == IOM_COMPLETED )
    FVID_queue(hGioVpbeVid0, frameBuffPtr);
if ( FVID_dequeue(hGioVpbeVid0, &frameBuffPtr) == IOM_COMPLETED )
    FVID_queue(hGioVpfeCcdc, frameBuffPtr);

当vpfe出队失败时,frameBuffPtr就不会被加入vpbe的READ队列中,vpbe同理,这样就保证交换的数据帧不会出错,vpfe和vpbe的缓冲区能保持稳定,视频帧异常的问题修复。