使用ffmpeg d3d11va的时候出现帧的时序上混乱。
通过ffmpeg 源码可知,ffmpeg 用d3d11va 时 出来的frame 中的data[0]存放的是decode texture数组(默认大小为20),data[1] 存放下标(可以发现,貌似下标总是一个随机的值,没调试进去,所以没有发现在哪里修改下标,不过通过下表访问的数据是没错的)。decode texture是在显存上的一个纹理,但是如果按demo中的方式去取图像,他需要先创建一个staging 类型的 texture ,再将decode texture拷贝到staging类型的 texture,再将staging 类型的texture中的内容map出来,这是极为消耗时间的 。我的操作是直接decode texture放到我的default类型的render texture中。开始的时候出现问题帧时序上的问题。但是如果调用ffmpeg demo中的原始的代码,却没有出现这个问题。
查了一通,发现这里。
大概意思就是: D3d中有一个内部的命令缓冲(command list)机制,这个机制能减少用户态和内核态的切换。很多函数执行完后,会暂时将操作放到command list中,后续command list会高效的去执行。有以下几个操作能让command list立马执行完。
猜测 因为ffmpeg d3d11va 中解码时在内部有开启子线程。多线程操作导致了在 copysubresource 时 ,产生了pipeline stall。
于是在copysubresourceregion后加入flush 命令,果然就没有这个问题了。下面的lock是必须加上的。
D3D11_BOX box; box.back = 1, box.front = 0, box.left = 0, box.right = descT.Width, box.top = 0, box.bottom = descT.Height;
ctx1->lock(ctx1->lock_ctx);
dctx->CopySubresourceRegion(frame->m_d3DTextureFfmpeg, 0, 0, 0, 0, (ID3D11Texture2D*)m_frame->data[0], currentFrameIndex,&box); //may be we can use the buffer in the frame directly
dctx->Flush(); //清空缓冲命令 //https://docs.microsoft.com/zh-cn/windows/desktop/api/d3d11/nf-d3d11-id3d11devicecontext-flush
ctx1->unlock(ctx1->lock_ctx);
值得注意的是copysubresouce 大概是有两帧的延时: