1、简述:
此文章使用的是雄迈官网下载的sdk在Linux布置环境,并且配合qt进行可视化界面显示,由于雄迈摄像头获取的图像数据是YUN420P格式的,而qt的QImage只支持RGB32图像显示,所以需要使用ffmpeg对图像数据格式进行转化。
2、具体操作:
首先在雄迈官网下载相关的sdk:
https://developer.jftech.com/docs/?menusId=57e91028bdc14909b269ddb19180d30a&lang=zh
将sdk中的Linux-x64-libXNetSDK.so和include文件夹放在指定文件夹,并在.pro文件中指明添加路径。
注意:libXNetSDK.so文件需要看清使用的系统,sdk中有Windows和Linux两种使用场景
并配置ffmpeg指明文件路径。如下图所示:
核心执行代码:
//初始化结构体
SXSDKInitParam initParam;
memset(&initParam,0,sizeof(SXSDKInitParam));
// SDK初始化
XSDK_Init(&initParam);
XSDK_SetSDKIntAttr(1024, 0);
//登录结构体初始化
SXSDKLoginParam LoginParam;
memset(&LoginParam,0,sizeof(SXSDKLoginParam));
QString Id = "192.168.1.199";
char* ptr =Id.toLatin1().data();
strcpy(LoginParam.sDevId,ptr);
QString name = "admin";
char* ptr1 =name.toLatin1().data();
strcpy(LoginParam.sUserName,ptr1);
QString pw = "";
char* ptr2 =pw.toLatin1().data();
strcpy(LoginParam.sPassword,ptr2);
LoginParam.nDevPort = 34567;
LoginParam.nCnnType = EDEV_CNN_TYPE_AUTO;
g_hDevice = XSDK_DevLoginSyn(&LoginParam,4000);
//查看登录是否成功,大于0表示成功,此处可以省略
if (g_hDevice > 0 && LoginParam.nCnnType != EDEV_CNN_TYPE_DAS)
{
//获取系统配置,主要是获取通道数
int nResult = GetDevSystemInfo();
if (nResult < 0)
{
qDebug() <<"Get device systeminfo error";
}
}
qDebug() << "g_hDevice:" <<g_hDevice;
SXMediaRealPlayReq param;
memset(¶m,0,sizeof(SXMediaRealPlayReq));
param.nChannel = 0; // 通道号(必填)
param.nStreamType = 0; // 0:主码流 1:辅码流
param.nDecodeType = DECODE_RESULT_YUV420;
param.nRequestType = EUIMSG_YUV_DATA; //帧数据
param.result = RealPlayMediaCallBack; // 结果回调(必填)
che = XSDK_MediaRealPlay(g_hDevice, ¶m);
connect(&testDecoder,&H265Decoder::sig_GetOneFrame,this,&MainWindow::addimage);
if(che > 0){
qDebug() << "读取成功" << che;
}
int MainWindow::GetDevSystemInfo()
{
if (g_hDevice > 0)
{
char szOutBuffer[40960] = { 0 };
int nInOutSize = sizeof(szOutBuffer);
int nResult = XSDK_DevGetSysConfigSyn(g_hDevice, "SystemInfo", szOutBuffer, &nInOutSize, 4000, 1020);
if (nResult >= 0)
{
XSDK_CFG::SystemInfo cfg;
cfg.Parse(szOutBuffer);
int g_nChannelNum = cfg.DigChannel.Value() + cfg.VideoOutChannel.Value();
qDebug() <<"通道数:" <<g_nChannelNum;
}
return nResult;
}
return -1;
}
//槽响应函数,用于刷新可视化界面显示
void MainWindow::addimage(QImage image){
ui->label->clear();
//这里对图像进行了缩放,将图像大小适应于QLabel的大小
ui->label->setPixmap(QPixmap::fromImage(image).scaled(ui->label->width(),ui->label->height(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
}
ffmpeg解码的实现:
//初始化
void H265Decoder::InitPlay(int width,int height)
{
//width和heigt为传入的分辨率的大小
int yuvSize = width * height * 3 /2;
yuvBuffer = (uint8_t *)malloc(yuvSize);
//为每帧图像分配内存
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
int numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, width,height);
rgbBuffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB, rgbBuffer, AV_PIX_FMT_RGB32,width, height);
//特别注意 img_convert_ctx 该在做H264流媒体解码时候,发现sws_getContext /sws_scale内存泄露问题,
//注意sws_getContext只能调用一次,在初始化时候调用即可,另外调用完后,在析构函数中使用sws_free_Context,将它的内存释放。
//设置图像转换上下文
img_convert_ctx = sws_getContext(width, height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
}
//实时接收yuv数据转换成rgb32 str是yuv数据,len为长度
void H265Decoder::wb_yuv(void* str,int width,int height)
{
avpicture_fill((AVPicture *)pFrame, (uint8_t *)str, AV_PIX_FMT_YUV420P, width, height);//这里的长度和高度跟之前保持一致
//转换图像格式,将解压出来的YUV420P的图像转换为RGB的图像
sws_scale(img_convert_ctx,
(uint8_t const * const *) pFrame->data,
pFrame->linesize, 0, height, pFrameRGB->data,
pFrameRGB->linesize);
//把这个RGB数据 用QImage加载
QImage tmpImg((uchar *)rgbBuffer,width,height,QImage::Format_RGB32);
QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示
emit sig_GetOneFrame(image); //发送信号,将次imamge发送到要显示的控件,用paintEvent绘制出来
}
将创建的文件继承于QObject,并在头文件中加入Q_OBJECT,即可使用信号与槽
程序最初想使用ffmpeg对图像一帧一帧的解析显示,但是获取的图像通过ffmpeg解析,一直显示
这个问题我一直没解决,希望有大佬可以指点一下。
通过申请工单的方式联系到开发者,在其指导下使用了YUN420P数据进行展示。
解码参考:https://blog.csdn.net/ASKLW/article/details/73332233