【转】Qt简单视频显示--

【转】Qt简单视频显示--上篇 v4l2 库

#ifndef VIDEODEVICE_H

#define VIDEODEVICE_H

 

#include <string.h>

#include <stdlib.h>

#include <errno.h>

#include <fcntl.h>

 

 

#include <sys/ioctl.h>

#include <sys/mman.h>

 

#include <asm/types.h>

#include <linux/videodev2.h>

 

#include <QString>

#include <QObject>

 

#define WIDTH 320

#define HEIGHT 240

#define CLEAR(x) memset(&(x), 0, sizeof(x))

 

class VideoDevice : public QObject

{

    Q_OBJECT

public:

    VideoDevice(QString dev_name);

    //VideoDevice();

    int open_device();

    int close_device();

    int init_device();

    int start_capturing();

    int stop_capturing();

    int uninit_device();

    int get_frame(void **, size_t*);

    int unget_frame();

 

private:

    int init_mmap();

 

    struct buffer

    {

        void * start;

        size_t length;

    };

    QString dev_name;

    int fd;

    buffer* buffers;

    unsigned int n_buffers;

    int index;

 

signals:

    void display_error(QString);

 

};

 

#endif // VIDEODEVICE_H

-------------------------------------------------------------------------------------------------------------------------------------------

 

#include "videodevice.h"

 

VideoDevice::VideoDevice(QString dev_name)

{

    this->dev_name = dev_name;

    this->fd = -1;

    this->buffers = NULL;

    this->n_buffers = 0;

    this->index = -1;

 

}

 

int VideoDevice::open_device()

{

    fd = open(dev_name.toStdString().c_str(), O_RDWR/*|O_NONBLOCK*/, 0);

   // fd = open(dev_name.toStdString().c_str(), O_RDWR|O_NONBLOCK, 0);

 

    if(-1 == fd)

    {

        emit display_error(tr("open: %1").arg(QString(strerror(errno))));

        return -1;

    }

    return 0;

}

 

int VideoDevice::close_device()

{

    if(-1 == close(fd))

    {

        emit display_error(tr("close: %1").arg(QString(strerror(errno))));

        return -1;

    }

    return 0;

}

 

int VideoDevice::init_device()

{

    v4l2_capability cap;

    v4l2_cropcap cropcap;

    v4l2_crop crop;

    v4l2_format fmt;

    qDebug("init star");

    if(-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap))

    {

        if(EINVAL == errno)

        {

            emit display_error(tr("%1 is no V4l2 device").arg(dev_name));

        }

        else

        {

            emit display_error(tr("VIDIOC_QUERYCAP: %1").arg(QString(strerror(errno))));

        }

        return -1;

    }

 

    if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))

    {

        emit display_error(tr("%1 is no video capture device").arg(dev_name));

        return -1;

    }

 

    if(!(cap.capabilities & V4L2_CAP_STREAMING))

    {

        emit display_error(tr("%1 does not support streaming i/o").arg(dev_name));

        return -1;

    }

 

    CLEAR(cropcap);

 

    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

 

//    if(0 == ioctl(fd, VIDIOC_CROPCAP, &cropcap))

//    {

//        CLEAR(crop);

//        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

//        crop.c = cropcap.defrect;

//

//        if(-1 == ioctl(fd, VIDIOC_S_CROP, &crop))

//        {

//            if(EINVAL == errno)

//            {

               emit display_error(tr("VIDIOC_S_CROP not supported"));

//            }

//            else

//            {

//                emit display_error(tr("VIDIOC_S_CROP: %1").arg(QString(strerror(errno))));

//                return -1;

//            }

//        }

//    }

//    else

//    {

//        emit display_error(tr("VIDIOC_CROPCAP: %1").arg(QString(strerror(errno))));

//        return -1;

//    }

 

    CLEAR(fmt);

 

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    fmt.fmt.pix.width = WIDTH;

    fmt.fmt.pix.height = HEIGHT;

    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

 

    if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt))

    {

        emit display_error(tr("VIDIOC_S_FMT").arg(QString(strerror(errno))));

        return -1;

    }

 

    if(-1 == init_mmap())

    {

        return -1;

    }

 

    return 0;

}

 

int VideoDevice::init_mmap()

{

    v4l2_requestbuffers req;

    CLEAR(req);

 

    req.count = 4;

    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    req.memory = V4L2_MEMORY_MMAP;

 

    if(-1 == ioctl(fd, VIDIOC_REQBUFS, &req))

    {

        if(EINVAL == errno)

        {

            emit display_error(tr("%1 does not support memory mapping").arg(dev_name));

            return -1;

        }

        else

        {

            emit display_error(tr("VIDIOC_REQBUFS %1").arg(QString(strerror(errno))));

            return -1;

        }

    }

 

    if(req.count < 2)

    {

        emit display_error(tr("Insufficient buffer memory on %1").arg(dev_name));

        return -1;

    }

 

    buffers = (buffer*)calloc(req.count, sizeof(*buffers));

 

    if(!buffers)

    {

        emit display_error(tr("out of memory"));

        return -1;

    }

 

    for(n_buffers = 0; n_buffers < req.count; ++n_buffers)

    {

        v4l2_buffer buf;

        CLEAR(buf);

 

        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        buf.memory = V4L2_MEMORY_MMAP;

        buf.index = n_buffers;

 

        if(-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))

        {

            emit display_error(tr("VIDIOC_QUERYBUF: %1").arg(QString(strerror(errno))));

            return -1;

        }

 

        buffers[n_buffers].length = buf.length;

        buffers[n_buffers].start =

                mmap(NULL, // start anywhere

                     buf.length,

                     PROT_READ | PROT_WRITE,

                     MAP_SHARED,

                     fd, buf.m.offset);

 

        if(MAP_FAILED == buffers[n_buffers].start)

        {

            emit display_error(tr("mmap %1").arg(QString(strerror(errno))));

            return -1;

        }

    }

    return 0;

 

}

 

int VideoDevice::start_capturing()

{

    unsigned int i;

    for(i = 0; i < n_buffers; ++i)

    {

        v4l2_buffer buf;

        CLEAR(buf);

 

        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        buf.memory =V4L2_MEMORY_MMAP;

        buf.index = i;

//        fprintf(stderr, "n_buffers: %d\n", i);

 

        if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))

        {

            emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));

            return -1;

        }

    }

 

    v4l2_buf_type type;

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

 

    if(-1 == ioctl(fd, VIDIOC_STREAMON, &type))

    {

        emit display_error(tr("VIDIOC_STREAMON: %1").arg(QString(strerror(errno))));

        return -1;

    }

    return 0;

}

 

int VideoDevice::stop_capturing()

{

    v4l2_buf_type type;

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

 

    if(-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))

    {

        emit display_error(tr("VIDIOC_STREAMOFF: %1").arg(QString(strerror(errno))));

        return -1;

    }

    return 0;

}

 

int VideoDevice::uninit_device()

{

    unsigned int i;

    for(i = 0; i < n_buffers; ++i)

    {

        if(-1 == munmap(buffers[i].start, buffers[i].length))

        {

            emit display_error(tr("munmap: %1").arg(QString(strerror(errno))));

            return -1;

        }

 

    }

    free(buffers);

    return 0;

}

 

int VideoDevice::get_frame(void **frame_buf, size_t* len)

{

    v4l2_buffer queue_buf;

    CLEAR(queue_buf);

 

    queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    queue_buf.memory = V4L2_MEMORY_MMAP;

 

    if(-1 == ioctl(fd, VIDIOC_DQBUF, &queue_buf))

    {

        switch(errno)

        {

        case EAGAIN:

//            perror("dqbuf");

            return -1;

        case EIO:

            return -1 ;

        default:

            emit display_error(tr("VIDIOC_DQBUF: %1").arg(QString(strerror(errno))));

            return -1;

        }

    }

 

    *frame_buf = buffers[queue_buf.index].start;

    *len = buffers[queue_buf.index].length;

    index = queue_buf.index;

 

    return 0;

 

}

 

int VideoDevice::unget_frame()

{

    if(index != -1)

    {

        v4l2_buffer queue_buf;

        CLEAR(queue_buf);

 

        queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        queue_buf.memory = V4L2_MEMORY_MMAP;

        queue_buf.index = index;

 

        if(-1 == ioctl(fd, VIDIOC_QBUF, &queue_buf))

        {

            emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));

            return -1;

        }

        return 0;

    }

    return -1;

}

Qt客户端接收MJPEG流(一种常见的视频传输格式)通常需要通过网络通信库,比如QTCPServer或者QTcpSocket,以及处理图像数据的库,如QImage或QWebEngineView。以下是简单的步骤: 1. **设置服务器连接**: - 首先,你需要创建一个QTcpSocket实例,并设置其主机名和端口号,用于连接到MJPEG服务器。 ```cpp QTcpSocket *socket = new QTcpSocket(this); connect(socket, &QTcpSocket::connected, this, &YourClass::onConnected); socket->connectToHost("your_server_ip", 8080); // Mjpeg默认端口 ``` 2. **读取并解码数据**: - 当连接成功后,可以开始接收数据。每次接收到数据,将它添加到`QByteArray`中,然后解析为MJPEG帧并显示在一个QImage或QPainter对象上。 ```cpp void YourClass::handleData(const QByteArray &data) { if (socket->state() == QAbstractSocket::ConnectedState) { QImage image(QSize(width, height), QImage::Format_RGB888); QBuffer buffer(&image.bits()); buffer.open(QIODevice::WriteOnly); buffer.write(data.data(), data.size()); buffer.close(); // 解码并显示图像 QPainter painter(&image); painter.drawImage(0, 0, image); painter.end(); update(); // 更新UI以显示新帧 } } ``` 3. **错误处理**: - 添加适当的错误处理,例如断开连接、超时或其他网络问题。 4. **线程支持**: - 如果数据流量很大,可能会导致主线程阻塞。你可以考虑使用QThread或Qt Concurrency框架来异步处理数据接收。 5. **关闭连接**: - 接收完数据后,记得关闭TCP连接。 ```cpp void YourClass::closeConnection() { socket->disconnectFromHost(); delete socket; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值