基于QT实现对网络摄像头数据的显示

其实一直有一个想法,就是设计一个远程视频监控软件,目前自己手中有的硬件包括:mini2440开发板,韦东山老师的摄像头模块ov7740,当然这款摄像头提供了基于mini2440下的读取及显示功能,但是没有提供网络显示功能,为此,我想增加这项功能,有这个想法,也是来自于mjpg-streamer项目的设计思路。
设计思路如下:
mini2440读取摄像头数据,然后通过udp广播是否传输给上位机,上位机通过QT实现数据的显示。
mini2440上源代码:
此代码基于韦东山老师的video2lcd修改,改动如下:

/* video2lcd  */
int main(int argc, char **argv)
{	
//	unsigned char test = 0;
	int ret;
	int sockfd = 0x00;
	int iError;

    T_VideoDevice tVideoDevice;
    PT_VideoConvert ptVideoConvert;
    int iPixelFormatOfVideo;
    int iPixelFormatOfDisp;

    PT_VideoBuf ptVideoBufCur;
    T_VideoBuf tVideoBuf;
    T_VideoBuf tConvertBuf;
    T_VideoBuf tZoomBuf;
    T_VideoBuf tFrameBuf;
    
    int iLcdWidth;
    int iLcdHeight;
    int iLcdBpp;

    int iTopLeftX;
    int iTopLeftY;

    float k;
    
    uint16_t timeout = 0xFFFF;

    u8 ipaddr[4] = {192,168,1,100};

    if (argc != 2)
    {
        printf("Usage:\n");
        printf("%s \n", argv[0]);
        return -1;
    }
    /*network init*/

    ret = net_udp_init(SIMU_PORT, timeout);
	if(ret < 0){
		DBG_PRINTF("net_udp_init error!\n");
		return -1;
	}else{
		sockfd = ret;
	}

    /* 一系列的初始化 */
	/* 注册显示设备 */
	DisplayInit();
	/* 可能可支持多个显示设备: 选择和初始化指定的显示设备 */
	SelectAndInitDefaultDispDev("fb");
    GetDispResolution(&iLcdWidth, &iLcdHeight, &iLcdBpp);
    GetVideoBufForDisplay(&tFrameBuf);
    iPixelFormatOfDisp = tFrameBuf.iPixelFormat;

    VideoInit();

    iError = VideoDeviceInit(argv[1], &tVideoDevice);
    if (iError)
    {
        DBG_PRINTF("VideoDeviceInit for %s error!\n", argv[1]);
        return -1;
    }
    iPixelFormatOfVideo = tVideoDevice.ptOPr->GetFormat(&tVideoDevice);

    VideoConvertInit();
    ptVideoConvert = GetVideoConvertForFormats(iPixelFormatOfVideo, iPixelFormatOfDisp);
    if (NULL == ptVideoConvert)
    {
        DBG_PRINTF("can not support this format convert\n");
        return -1;
    }


    /* 启动摄像头设备 */
    iError = tVideoDevice.ptOPr->StartDevice(&tVideoDevice);
    if (iError)
    {
        DBG_PRINTF("StartDevice for %s error!\n", argv[1]);
        return -1;
    }

    memset(&tVideoBuf, 0, sizeof(tVideoBuf));
    memset(&tConvertBuf, 0, sizeof(tConvertBuf));
    tConvertBuf.iPixelFormat     = iPixelFormatOfDisp;
    tConvertBuf.tPixelDatas.iBpp = iLcdBpp;


    memset(&tZoomBuf, 0, sizeof(tZoomBuf));
    //PutTest();

    while (1)
    {
//    	char buf[255];
//    	FILE *fp;

//    	time_t ts;
//    	struct tm *t;

//    	time(&ts);

//    	t = gmtime(&ts);

//    	sprintf(buf, "video-%d-%d-%d--%02d-%02d-%02d.jpg",t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);

//    	fp = fopen(buf,"w");
//    	if(fp == NULL)
//    	{
//    		DBG_PRINTF("fopen file error!\n");
//    		return -1;
//    	}

        /* 读入摄像头数据 */
        iError = tVideoDevice.ptOPr->GetFrame(&tVideoDevice, &tVideoBuf);
        if (iError)
        {
            DBG_PRINTF("GetFrame for %s error!\n", argv[1]);
            return -1;
        }
        ptVideoBufCur = &tVideoBuf;
//        DBG_PRINTF("ptVideoBufCur->tPixelDatas.iWidth:%d ptVideoBufCur->tPixelDatas.iHeight:%d total:%d\n",ptVideoBufCur->tPixelDatas.iWidth,ptVideoBufCur->tPixelDatas.iHeight,ptVideoBufCur->tPixelDatas.iTotalBytes);
//        fwrite(tVideoBuf.tPixelDatas.aucPixelDatas,tVideoBuf.tPixelDatas.iTotalBytes,1,fp);

//        fclose(fp);

        ret = net_udp_send(sockfd, tVideoBuf.tPixelDatas.aucPixelDatas, tVideoBuf.tPixelDatas.iTotalBytes, ipaddr, 9000);
        if(ret < 0)
        {
        	DBG_PRINTF("net_udp_send error!\n");
        }

        if (iPixelFormatOfVideo != iPixelFormatOfDisp)
        {
            /* 转换为RGB */
            iError = ptVideoConvert->Convert(&tVideoBuf, &tConvertBuf);
            DBG_PRINTF("Convert %s, ret = %d\n", ptVideoConvert->name, iError);
            if (iError)
            {
                DBG_PRINTF("Convert for %s error!\n", argv[1]);
                return -1;
            }
            ptVideoBufCur = &tConvertBuf;
        }
        //DBG_PRINTF("ptVideoBufCur->tPixelDatas.iWidth:%d ptVideoBufCur->tPixelDatas.iHeight:%d\n",ptVideoBufCur->tPixelDatas.iWidth,ptVideoBufCur->tPixelDatas.iHeight);

        /* 如果图像分辨率大于LCD, 缩放 */
        if (ptVideoBufCur->tPixelDatas.iWidth > iLcdWidth || ptVideoBufCur->tPixelDatas.iHeight > iLcdHeight)
        {
            /* 确定缩放后的分辨率 */
            /* 把图片按比例缩放到VideoMem上, 居中显示
             * 1. 先算出缩放后的大小
             */
            k = (float)ptVideoBufCur->tPixelDatas.iHeight / ptVideoBufCur->tPixelDatas.iWidth;
            tZoomBuf.tPixelDatas.iWidth  = iLcdWidth;
            tZoomBuf.tPixelDatas.iHeight = iLcdWidth * k;
            if ( tZoomBuf.tPixelDatas.iHeight > iLcdHeight)
            {
                tZoomBuf.tPixelDatas.iWidth  = iLcdHeight / k;
                tZoomBuf.tPixelDatas.iHeight = iLcdHeight;
            }
            tZoomBuf.tPixelDatas.iBpp        = iLcdBpp;
            tZoomBuf.tPixelDatas.iLineBytes  = tZoomBuf.tPixelDatas.iWidth * tZoomBuf.tPixelDatas.iBpp / 8;
            tZoomBuf.tPixelDatas.iTotalBytes = tZoomBuf.tPixelDatas.iLineBytes * tZoomBuf.tPixelDatas.iHeight;

            if (!tZoomBuf.tPixelDatas.aucPixelDatas)
            {
                tZoomBuf.tPixelDatas.aucPixelDatas = malloc(tZoomBuf.tPixelDatas.iTotalBytes);
            }

            PicZoom(&ptVideoBufCur->tPixelDatas, &tZoomBuf.tPixelDatas);
            ptVideoBufCur = &tZoomBuf;
        }

        /* 合并进framebuffer */
        /* 接着算出居中显示时左上角坐标 */
        iTopLeftX = (iLcdWidth - ptVideoBufCur->tPixelDatas.iWidth) / 2;
        iTopLeftY = (iLcdHeight - ptVideoBufCur->tPixelDatas.iHeight) / 2;

        PicMerge(iTopLeftX, iTopLeftY, &ptVideoBufCur->tPixelDatas, &tFrameBuf.tPixelDatas);

        FlushPixelDatasToDev(&tFrameBuf.tPixelDatas);
        //FlushPixelDatasToDev(&ptVideoBufCur->tPixelDatas);

        iError = tVideoDevice.ptOPr->PutFrame(&tVideoDevice, &tVideoBuf);
        if (iError)
        {
            DBG_PRINTF("PutFrame for %s error!\n", argv[1]);
            return -1;
        }

        //fclose(fp);
        /* 把framebuffer的数据刷到LCD上, 显示 */
    }
		
	return 0;
}
	

git代码库:https://git.oschina.net/pengrui2009/video2lcd.git
QT显示源代码:
udp广播接收数据并转化为QImage显示:

void ImageViewer::proc_udp_data()
{
    QImage image;//(databuf, 240, 320, QImage::Format_RGB16);
    uint32_t len;

    //接收队列入队
    while (udpsocket->hasPendingDatagrams())
    {
        len = udpsocket->readDatagram((char *)buf, 65535);
        if(len)
        {
            image.loadFromData(buf, len);

            imageLabel->setPixmap(QPixmap::fromImage(image));

            scaleFactor = 1.0;

            printAct->setEnabled(true);
            fitToWindowAct->setEnabled(true);
            updateActions();

            if (!fitToWindowAct->isChecked())
                imageLabel->adjustSize();

            //fitToWindow();
            scrollArea->setWidgetResizable(true);
        }
    }
}

git代码库:https://git.oschina.net/pengrui2009/video2lcd-qt.git

你可能感兴趣的:(QT应用程序开发,linux内核及驱动开发)