linux下使用QT调用FFMPEG读取摄像头一帧数据显示到标签控件上

简介: linux下使用QT调用FFMPEG读取摄像头一帧数据显示到标签控件上

下面代码调用FFMPEG库,读取摄像头的一帧数据,转换为RGB888,加载到QImage,再显示到标签控件上。

开发环境:

操作系统: ubuntu18.04 64位

QT版本: QT5.12

代码包已经上传到CSDN,需要的可以去下载。

https://download.csdn.net/download/xiaolong1126626497/12233526

mainwindow.cpp文件代码:

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    FFMPEG_Init_Config();
}
MainWindow::~MainWindow()
{
    delete ui;
}
int MainWindow::FFMPEG_Init_Config()
{
    AVInputFormat   *ifmt;
    AVFormatContext *pFormatCtx;
    AVCodecContext  *pCodecCtx;
    AVCodec         *pCodec;
    AVDictionary    *options=nullptr;
    AVPacket        *packet;
    AVFrame         *pFrame,*pFrameYUV;
    int videoindex;
    int i,ret,got_picture;
    /*1. FFMPEG初始化*/
    av_register_all();
    avcodec_register_all();
    avdevice_register_all(); //注册多媒体设备交互的类库
    /*2. 查找用于输入的设备*/
    ifmt=av_find_input_format("video4linux2");
    pFormatCtx=avformat_alloc_context();
    av_dict_set(&options,"video_size","640x480",0); //设置摄像头输出的分辨率
    //av_dict_set(&options,"framerate","30",0);     //设置摄像头帧率. 每秒为单位,这里设置每秒30帧.
    //一般帧率不用设置,默认为最高,帧率和输出的图像尺寸有关系
    if(avformat_open_input(&pFormatCtx,"/dev/video0",ifmt,&options)!=0)
    {
        qDebug("输入设备打开失败: /dev/video0\n");
        return -1;
    }
    if(avformat_find_stream_info(pFormatCtx,nullptr)<0)
    {
        qDebug("查找输入流失败.\n");
        return -2;
    }
    videoindex=-1;
    for(i=0;i<pFormatCtx->nb_streams;i++)
    {
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
        {
            videoindex=i;
            break;
        }
    }
    if(videoindex==-1)
    {
        qDebug("视频流查找失败.\n");
        return -3;
    }
    pCodecCtx=pFormatCtx->streams[videoindex]->codec;
    qDebug("摄像头尺寸(WxH): %d x %d \n",pCodecCtx->width, pCodecCtx->height);
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==nullptr)
    {
        qDebug("找不到编解码器。\n");
        return -4;
    }
    if(avcodec_open2(pCodecCtx, pCodec,nullptr)<0)
    {
        qDebug("无法打开编解码器。\n");
        return -5;
    }
    packet=(AVPacket *)av_malloc(sizeof(AVPacket));
    pFrame=av_frame_alloc();
    pFrameYUV=av_frame_alloc();
    unsigned char *out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,16));   // avpicture_get_size
    av_image_fill_arrays(pFrameYUV->data,pFrameYUV->linesize,out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,16);
    struct SwsContext *img_convert_ctx;
    img_convert_ctx=sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
    //读取一帧数据
    if(av_read_frame(pFormatCtx, packet)>=0)
    {
        //输出图像的大小
        qDebug("数据大小=%d\n",packet->size);
        //判断是否是视频流
        if(packet->stream_index==videoindex)
        {
            //解码从摄像头获取的数据,pframe结构
            ret=avcodec_decode_video2(pCodecCtx, pFrame,&got_picture,packet);
            if(ret<0)
            {
                qDebug("解码Error.\n");
                return -6;
            }
            if(got_picture)
            {
                 size_t y_size=pCodecCtx->width*pCodecCtx->height;
                 sws_scale(img_convert_ctx,(const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);  //根据前面配置的缩放参数,进行图像格式转换以及缩放等操作
                 unsigned char *p=new unsigned char[y_size]; //申请空间
                 unsigned char *rgb24_p=new unsigned char[pCodecCtx->width*pCodecCtx->height*3];
                 //将YUV数据拷贝到缓冲区
                 memcpy(p,pFrameYUV->data[0],y_size);
                 memcpy(p+y_size,pFrameYUV->data[1],y_size/4);
                 memcpy(p+y_size+y_size/4,pFrameYUV->data[2],y_size/4);
                 //将YUV数据转为RGB格式
                 YUV420P_to_RGB24(p,rgb24_p,pCodecCtx->width,pCodecCtx->height);
                 //加载到QIMAGE显示到QT控件
                 QImage image(rgb24_p,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB888);
                 QPixmap my_pixmap;
                 my_pixmap.convertFromImage(image);
                 ui->label_DisplayImage->setPixmap(my_pixmap);
                 delete[] p; //释放空间
                 delete[] rgb24_p; //释放空间
            }
        }
    }
    sws_freeContext(img_convert_ctx);
    av_free(out_buffer);
    av_free(pFrameYUV);
    avcodec_close(pCodecCtx); //关闭编码器
    avformat_close_input(&pFormatCtx); //关闭输入设备
}
/**
 * YUV420P转RGB24
 * @param data
 * @param rgb
 * @param width
 * @param height
 */
void MainWindow::YUV420P_to_RGB24(unsigned char *data, unsigned char *rgb, int width, int height)
{
    int index = 0;
    unsigned char *ybase = data;
    unsigned char *ubase = &data[width * height];
    unsigned char *vbase = &data[width * height * 5 / 4];
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            //YYYYYYYYUUVV
            u_char Y = ybase[x + y * width];
            u_char U = ubase[y / 2 * width / 2 + (x / 2)];
            u_char V = vbase[y / 2 * width / 2 + (x / 2)];
            rgb[index++] = Y + 1.402 * (V - 128); //R
            rgb[index++] = Y - 0.34413 * (U - 128) - 0.71414 * (V - 128); //G
            rgb[index++] = Y + 1.772 * (U - 128); //B
        }
    }
}
//FFMPEG推流线程执行起始点
void Thread_ffmpgVideo::run()
{
    int ret,got_picture;
    while(1)
    {
        sleep(1);
    }
}

mainwindos.h代码:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QImage>
#include <QThread>
extern "C"{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include "libavdevice/avdevice.h"
#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
/*
FFmpeg多媒体设备交互的类库:Libavdevice。
使用这个库可以读取电脑(或者其他设备上)的多媒体设备的数据或者输出数据到指定的多媒体设备上。
*/
}
class MainWindow;
//线程类的子类化
class Thread_ffmpgVideo : public QThread
{
public:
    MainWindow *mianwindow;  //指向widget的指针
protected:
    void run();  //线程执行的函数
};
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    int FFMPEG_Init_Config();
    void YUV420P_to_RGB24(unsigned char *data, unsigned char *rgb, int width, int height);
private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

main.cpp:

#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

pro 工程文件

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
    main.cpp \
    mainwindow.cpp
HEADERS += \
    mainwindow.h
FORMS += \
    mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#指定库的路径
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lavcodec
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lavfilter
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lavutil
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lavdevice
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lavformat
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lpostproc
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lswscale
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lswresample
unix:LIBS += -L$$PWD/ffmpeg_x264_lib/lib -lx264
#制定头文件的路径
INCLUDEPATH+=$$PWD/ffmpeg_x264_lib/include

image.png

目录
相关文章
|
3月前
|
缓存 监控 计算机视觉
视频监控笔记(三):opencv结合ffmpeg获取rtsp摄像头相关信息
本文介绍了如何使用OpenCV结合FFmpeg获取RTSP摄像头信息,包括网络架构、视频监控系统组成、以及如何读取和显示网络摄像头视频流。
121 1
|
6月前
|
数据采集 大数据 Python
FFmpeg 在爬虫中的应用案例:流数据解码详解
在大数据背景下,网络爬虫与FFmpeg结合,高效采集小红书短视频。需准备FFmpeg、Python及库如Requests和BeautifulSoup。通过设置User-Agent、Cookie及代理IP增强隐蔽性,解析HTML提取视频链接,利用FFmpeg下载并解码视频流。示例代码展示完整流程,强调代理IP对避免封禁的关键作用,助你掌握视频数据采集技巧。
FFmpeg 在爬虫中的应用案例:流数据解码详解
|
5月前
|
Linux
关于linux的qt发布(linuxdeployqt)中opengl版本过高的解决
关于linux的qt发布(linuxdeployqt)中opengl版本过高的解决
|
6月前
|
Oracle 关系型数据库 Linux
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
通过这一连串的步骤,可以专业且有效地在Linux下为Qt编译Oracle驱动库 `libqsqloci.so`,使得Qt应用能够通过OCI与Oracle数据库进行交互。这些步骤适用于具备一定Linux和Qt经验的开发者,并且能够为需要使用Qt开发数据库应用的专业人士提供指导。
207 1
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
|
6月前
|
Web App开发 缓存 Linux
FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
《FFmpeg开发实战》书中第10章提及轻量级流媒体服务器MediaMTX,适合测试RTSP/RTMP协议,但不适合生产环境。推荐使用SRS或ZLMediaKit,其中SRS是国产开源实时视频服务器,支持多种流媒体协议。本文简述在华为欧拉系统上编译安装SRS和FFmpeg的步骤,包括安装依赖、下载源码、配置、编译以及启动SRS服务。此外,还展示了如何通过FFmpeg进行RTMP推流,并使用VLC播放器测试拉流。更多FFmpeg开发内容可参考相关书籍。
157 2
FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
|
6月前
|
Linux
FFmpeg开发笔记(三十四)Linux环境给FFmpeg集成libsrt和librist
《FFmpeg开发实战》书中介绍了直播的RTSP和RTMP协议,以及新协议SRT和RIST。SRT是安全可靠传输协议,RIST是可靠的互联网流传输协议,两者于2017年发布。腾讯视频云采用SRT改善推流卡顿。以下是Linux环境下为FFmpeg集成libsrt和librist的步骤:下载安装源码,配置、编译和安装。要启用这些库,需重新配置FFmpeg,添加相关选项,然后编译和安装。成功后,通过`ffmpeg -version`检查版本信息以确认启用SRT和RIST支持。详细过程可参考书中相应章节。
131 1
FFmpeg开发笔记(三十四)Linux环境给FFmpeg集成libsrt和librist
|
6月前
|
存储 安全 Linux
|
7月前
|
编解码 Linux
FFmpeg开发笔记(二十八)Linux环境给FFmpeg集成libxvid
XviD是开源的MPEG-4视频编解码器,曾与DivX一起用于早期MP4视频编码,但现在已被H.264取代。要集成XviD到Linux上的FFmpeg,首先下载源码,解压后配置并编译安装libxvid。接着,在FFmpeg源码目录中,重新配置FFmpeg以启用libxvid,然后编译并安装。成功后,通过`ffmpeg -version`检查是否启用libxvid。详细步骤包括下载、解压libxvid,使用`configure`和`make`命令安装,以及更新FFmpeg配置并安装。
108 2
FFmpeg开发笔记(二十八)Linux环境给FFmpeg集成libxvid
|
5月前
|
编解码 Linux 开发工具
Linux平台x86_64(麒麟|统信UOS)|aarch64(飞腾)如何实现摄像头|屏幕和麦克风|扬声器采集推送RTMP服务或轻量级RTSP服务
国产化操作系统的发展,减少了外部依赖,更符合国家安全标准,并可提升自主研发能力,促进产业链发展,满足定制开发能力,减少了外部技术封锁的风险,提高了国际竞争力,推动了产业升级。目前大牛直播SDK针对Linux平台x86_64架构和aarch64架构的RTMP推送模块和轻量级RTSP服务模块
109 0
|
7月前
|
Web App开发 安全 Linux
FFmpeg开发笔记(二十六)Linux环境安装ZLMediaKit实现视频推流
《FFmpeg开发实战》书中介绍轻量级流媒体服务器MediaMTX,但其功能有限,不适合生产环境。推荐使用国产开源的ZLMediaKit,它支持多种流媒体协议和音视频编码标准。以下是华为欧拉系统下编译安装ZLMediaKit和FFmpeg的步骤,包括更新依赖、下载源码、配置、编译、安装以及启动MediaServer服务。此外,还提供了通过FFmpeg进行RTSP和RTMP推流,并使用VLC播放器拉流的示例。
369 3
FFmpeg开发笔记(二十六)Linux环境安装ZLMediaKit实现视频推流

热门文章

最新文章