写在前面:
投影融合软件 几乎大部分时间都是运行在公开场合,主机一般都携带的多显示设备,所以对软件的稳定性提出较高的要求。如果融合软件是运行在window系统,一定要选择d3d11做绘制地层api,不要使用OpenGL,,因为 OpenGL的兼容性问题 而用户的主机主机不是你决定的,比如会遇到集成显卡下显示色差严重,hdr显示不正常,显示器缩放等等问题。
如何理解并定制自己的播放器视频播放器:
现在网上播放器播放器的技术介绍很多,推荐硬啃ffplay。
可以先从简化版开始ffmpeg/ffplay vc6 源码剖析 - mcodec - 博客园 (cnblogs.com)
多动手 多读 直到能写一个简单的播放器为止。
对融合播放器的定制一般注意:
1:集群播放功能:
对于超大型投影项目,播放器必须具备主机集群播放的功能,这必须要求开发者对播放器有个通透的理解。特别是音视频轨道同步的问题,PTS和DTS和时间戳以及控制流程有个通透的理解。 这部分极强容易出错。
其实同步也特别简单:采用视频轨同步到音频轨的方法,在视频轨上进行多主机同步:
伪代码:
int RenderingProcess(int *delay){
......
......
//多主机同步处理
if(!ifEof){
if(currFrameId==preFrameId){
currFrameId++;
TellServerIReady();
}
}
if ( CanTakeAction()==true){
preFrameId=currFrameId;
}else{
return 正在等待标识 并且不更新纹理
}
//音视频同步处理:间隔处理 或 帧丢弃
(*delay) =time_synchronize_fix()
......
......
}
2:纯硬件(不经内存)功能:
纯硬件解码(显卡到显卡,如果还经内存8k 的视频不用做了)是融合软件必不可以少的,而这部分比较难 网上很少能找到线 但从av_hwframe_transfer_data()的源码能找到答案:libavutil/hwcontext_d3d11va.c 仔细分析后 我重写这个函数:最重要的伪代码如下:
ID3D11Texture2D *createTmpTexture(int w, int h, DXGI_FORMAT form,ID3D11Device* dev){
ID3D11Texture2D *tmp_tex = NULL;
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = w;
desc.Height = h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = form;//DXGI_FORMAT_NV12;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.MiscFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
dev->CreateTexture2D(&desc, NULL, &tmp_tex);
}
handleInDecThread(){
int ret = avcodec_send_packet(video_ctx, packet);
if (ret < 0) {
if (ret == AVERROR(EAGAIN)) {
}
}else {
while (1) {
AVFrame* frame1 = av_frame_alloc();
frame1->opaque = NULL;
ret = avcodec_receive_frame(video_ctx, frame1);
if (ret<0){
}else{
if (ret == AVERROR(EAGAIN) ) {
}else if(ret == AVERROR_EOF){}
}else{
AVHWFramesContext* ctx = (AVHWFramesContext*)(frame1->hw_frames_ctx->data);
AVD3D11VADeviceContext* device_hwctx = (AVD3D11VADeviceContext*)ctx->device_ctx->hwctx;
D3D11VAFramesContext* s = (D3D11VAFramesContext*)ctx->internal->priv;
//这里就是需要
if (tmp_tex==NULL){
tmp_tex=createTmpTexture(frame1->width, frame1->height, s->format, device_hwctx->device)
}
device_hwctx->lock(device_hwctx->lock_ctx);
ID3D11Resource* texture = (ID3D11Resource*)(ID3D11Texture2D*)frame1->data[0];
int ind = (intptr_t)frame1->data[1];
D3D11_BOX sourceRegion;
sourceRegion.left = 0;
sourceRegion.right = frame1->width;
sourceRegion.top = 0;
sourceRegion.bottom = frame1->height;
sourceRegion.front = 0;
sourceRegion.back = 1;
device_hwctx->device_context->CopySubresourceRegion(tmp_tex, 0, 0, 0, 0, texture, ind, &sourceRegion);
device_hwctx->device_context->Flush();
device_hwctx->unlock(device_hwctx->lock_ctx);
}
}
}
av_packet_unref(packet);
av_packet_free(&packet);
}
3 hap格式 极致高清
hap格式,很多时候如果真要求极致高清的话 往往需要这种格式的视频支持。官网地址如下:HAP Codecs
这个格式其实非常简单,产出是rgba格式 由于几乎没有压缩,导致这种格式的视频非常非常大(7680*2160,3分钟视频,大小320G ),在渲染这种格式的 ,io性能成为了瓶颈,解决办法也很简单,用多线程读取就轻易解决了。
总结:
播放器开发工作其实不难,重要的是能对ffplay有通透的理解。多尝试 ,拆分 ,整合 是理解的不错方法,我就是这样做的。
下面是运行8k 60帧频视频 效果图: