Qt使用FFmpeg播放视频

2023-05-16

一、使用场景

  因为项目中需要加载MP4播放开机视频,而我们的设备所使用的架构为arm架构,其中缺乏一些多媒体库。安装这些插件库比较麻烦,所以最终决定使用FFmpeg播放视频。

二、下载编译ffmpeg库

2.1 下载源码

  源码下载路径:https://www.ffmpeg.org/download.html#build-windows

2.2 编译源码

  1) 解压:将源码放到指定目录,并运行"tar -jxvf ffmpeg-snapshot.tar.bz2"。若是xxx.tar.gz源文件,则用"tar -zxvf ffmpeg-xxx.tar.gz"。

  2) 创建构建目录,"cd ffmpeg", "mkdir build";

  3)编译:

  a) ubuntu编译: "./configure --enable-static --prefix=./build"

  b)arm交叉编译: "./configure --cc=xxx/aarch64-linux-gnu-gcc(QT指定的gcc路径) --cxx=xxx/aarch64-linux-gnu-g++ --enable-staticc(QT指定的g++路径) --prefix=./build --enable-cross-compile --arch=arm64 --target-os=linux"。

  4) make安装: "make && make install"。

  5) 运行:若需要运行ffmpeg则需要增加--enable-shared参数,并且添加环境变量"export LD_LIBRARY_PATH=xxx/build/lib/"。

  6)使用帮助: 在xxx/build/bin路径下运行"./ffmpeg --help"。

2.3 常见报错

  1) 交叉编译需要指定对应的gcc和g++编译器和其它的如平台参数,Linux的QTCreator可以通过如下选项查看对应的编译器路径,工程-》管理构建-》编译器-》指南(Manual)-》双击gcc或g++。注意在操作之前需要先选择工程当前的运行和构建平台为arrch64。

  2) make install 报错:"strip: Unable to recognise the format of the input file":将config.mak中的"Trip=strip"改为"Trip=arm -linux-strip"。

三、使用源码

  1.在工程中导入头文件和库,注意库顺序。eg:

INCLUDEPATH += xxx/build/include
LIBS += -Lxxx/xxx -lavformat\
    -lavdevice \
    -lavcodec \
    -lswresample \
    -lavfilter \    
    -lavutil \
    -lswscale

  2.头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include <QTimer>
#include <QTime>
#include <QAudioOutput>
extern "C"
{
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
    #include <libavdevice/avdevice.h>
    #include <libavformat/version.h>
    #include <libavutil/time.h>
    #include <libavutil/mathematics.h>
    #include <libavfilter/buffersink.h>
    #include <libavfilter/buffersrc.h>
    #include <libavutil/avutil.h>
    #include <libavutil/imgutils.h>
    #include <libavutil/pixfmt.h>
    #include <libswresample/swresample.h>
}

#define MAX_AUDIO_FRAME_SIZE 192000

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public slots:
   void timeCallback(void);
   void on_play_clicked();
   void resizeEvent(QResizeEvent* );

private:
    Ui::MainWindow *ui;
    int playVedio(void);
    QTimer *timer;      // 定时播放,根据帧率来
    int vedioW,vedioH;  // 图像宽高
    QList<QPixmap> vedioBuff;   // 图像缓存区

    QString myUrl = QString("E:/workspace/Qt_workspace/ffmpeg/三国之战神无双.mp4");  // 视频地址
    AVFormatContext    *pFormatCtx;
    AVCodecContext  *pCodecCtx;
    AVCodec         *pCodec;
    AVFrame         *pFrame, *pFrameRGB;
    int ret, got_picture,got_audio;  // 视频解码标志
    int videoindex;        // 视频序号
    // 音频
    int audioindex;        // 音频序号
    AVCodecParameters   *aCodecParameters;
    AVCodec             *aCodec;
    AVCodecContext      *aCodecCtx;
    QByteArray          byteBuf;//音频缓冲
    QAudioOutput        *audioOutput;
    QIODevice           *streamOut;
};

#endif // MAINWINDOW_H

  3.源文件:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//    qDebug(avcodec_configuration());
//    unsigned version = avcodec_version();
//    QString ch = QString::number(version,10);
//    qDebug()<<"version:"<<version;


    timer = new QTimer(this);
    timer->setTimerType(Qt::PreciseTimer);   // 精准定时设置
    connect(timer,SIGNAL(timeout()),this,SLOT(timeCallback()));
}

void MainWindow::timeCallback(void)
{
    // 视频缓存播放
    if(!vedioBuff.isEmpty())
    {
        ui->label->setPixmap(vedioBuff.at(0));
        vedioBuff.removeAt(0);
    }
    else {
        timer->stop();
    }

    // 音频缓存播放
    if(audioOutput && audioOutput->state() != QAudio::StoppedState && audioOutput->state() != QAudio::SuspendedState)
    {
        int writeBytes = qMin(byteBuf.length(), audioOutput->bytesFree());
        streamOut->write(byteBuf.data(), writeBytes);
        byteBuf = byteBuf.right(byteBuf.length() - writeBytes);
    }
}

void Delay_MSec(unsigned int msec)
{
    QTime _Timer = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < _Timer )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

int MainWindow::playVedio(void)
{
    QAudioFormat fmt;
    fmt.setSampleRate(44100);
    fmt.setSampleSize(16);
    fmt.setChannelCount(2);
    fmt.setCodec("audio/pcm");
    fmt.setByteOrder(QAudioFormat::LittleEndian);
    fmt.setSampleType(QAudioFormat::SignedInt);
    audioOutput = new QAudioOutput(fmt);
    streamOut = audioOutput->start();

    char *filepath = myUrl.toUtf8().data();
    av_register_all();
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();

    // 打开视频文件,初始化pFormatCtx结构
    if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){
        qDebug("视频文件打开失败.\n");
        return -1;
    }
    // 获取音视频流
    if(avformat_find_stream_info(pFormatCtx,NULL)<0){
        qDebug("媒体流获取失败.\n");
        return -1;
    }
    videoindex = -1;
    audioindex = -1;
    //nb_streams视音频流的个数,这里当查找到视频流时就中断了。
    for(int 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 -1;
    }

    //nb_streams视音频流的个数,这里当查找到音频流时就中断了。
    for(int i=0; i<pFormatCtx->nb_streams; i++)
        if(pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_AUDIO){
            audioindex=i;
            break;
    }
    if(audioindex==-1){
        qDebug("找不到音频流.\n");
        return -1;
    }

    //获取视频流编码结构
    pCodecCtx=pFormatCtx->streams[videoindex]->codec;

    float frameNum = pCodecCtx->framerate.num;  // 每秒帧数
    if(frameNum>100)  frameNum = frameNum/1001;
    int frameRate = 1000/frameNum;   //
    qDebug("帧/秒 = %f  播放间隔是时间=%d\n",frameNum,frameRate);

    //查找解码器
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL)
    {
        qDebug("找不到解码器.\n");
        return -1;
    }
    //使用解码器读取pCodecCtx结构
    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
    {
        qDebug("打开视频码流失败.\n");
        return -1;
    }

    //获取音频流编码结构-------------------------------------------------------------
    aCodecParameters = pFormatCtx->streams[audioindex]->codecpar;
    aCodec = avcodec_find_decoder(aCodecParameters->codec_id);
    if (aCodec == 0) {
        qDebug("找不到解码器.\n");
        return -1;
    }
    aCodecCtx = avcodec_alloc_context3(aCodec);
    avcodec_parameters_to_context(aCodecCtx, aCodecParameters);
    //使用解码器读取aCodecCtx结构
    if (avcodec_open2(aCodecCtx, aCodec, 0) < 0) {
        qDebug("打开视频码流失败.\n");
        return 0;
    }

    // 清空缓存区
    byteBuf.clear();
    vedioBuff.clear();

    //创建帧结构,此函数仅分配基本结构空间,图像数据空间需通过av_malloc分配
    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();

    // 获取音频参数
    uint64_t out_channel_layout = aCodecCtx->channel_layout;
    AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    int out_sample_rate = aCodecCtx->sample_rate;
    int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);

    uint8_t *audio_out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE*2);
    SwrContext *swr_ctx = swr_alloc_set_opts(NULL, out_channel_layout, out_sample_fmt,out_sample_rate, aCodecCtx->channel_layout, aCodecCtx->sample_fmt, aCodecCtx->sample_rate, 0, 0);
    swr_init(swr_ctx);

    //创建动态内存,创建存储图像数据的空间
    unsigned char *out_buffer = (unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height, 1));
    av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, out_buffer, AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height, 1);
    AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
    //初始化img_convert_ctx结构
    struct SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);

    timer->start(frameRate);  //定时间隔播放

    while (av_read_frame(pFormatCtx, packet) >= 0){
        if (packet->stream_index == audioindex){
            int ret = avcodec_decode_audio4(aCodecCtx, pFrame, &got_audio, packet);
            if ( ret < 0)
            {
                qDebug("解码失败.\n");
                return 0;
            }

            if (got_audio)
            {
                int len = swr_convert(swr_ctx, &audio_out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pFrame->data, pFrame->nb_samples);
                if (len <= 0)
                {
                    continue;
                }
                int dst_bufsize = av_samples_get_buffer_size(0, out_channels, len, out_sample_fmt, 1);
                QByteArray atemp =  QByteArray((const char *)audio_out_buffer, dst_bufsize);
                byteBuf.append(atemp);
            }
        }
        //如果是视频数据
        else if (packet->stream_index == videoindex){
            //解码一帧视频数据
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);

            if (ret < 0){
                qDebug("解码失败.\n");
                return 0;
            }
            if (got_picture){
                sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
                    pFrameRGB->data, pFrameRGB->linesize);
                QImage img((uchar*)pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
                img = img.scaled(vedioW, vedioH);
                QPixmap temp = QPixmap::fromImage(img);
                vedioBuff.append(temp);
                Delay_MSec(frameRate-5);  // 这里需要流出时间来显示,如果不要这个延时界面回卡死到整个视频解码完成才能播放显示
                //ui->label->setPixmap(temp);
            }
        }
        av_free_packet(packet);
    }

    sws_freeContext(img_convert_ctx);
    av_frame_free(&pFrameRGB);
    av_frame_free(&pFrame);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);
}

void MainWindow::resizeEvent(QResizeEvent* )
{
    vedioW = ui->label->width();
    vedioH = ui->label->height();
}
MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_play_clicked()
{
    vedioW = ui->label->width();
    vedioH = ui->label->height();
    if(timer->isActive())   timer->stop();
    playVedio();
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt使用FFmpeg播放视频 的相关文章

  • FFMPEG 在视频末尾添加图像

    我需要使用 FFMPEG 在 mp4 视频文件末尾添加一秒钟的图像 我的视频尺寸是 WxH 图像尺寸是 MxM 因此视频和图像尺寸不同 我尝试了不同的选项 以便在视频末尾添加图像 ffmpeg i concat videoIn mp4 im
  • 使用 libavformat API 读取 H264 SPS 和 PPS NAL 字节

    如何使用 libavformat API 读取 H264 SPS 和 PPS NAL 字节 我尝试使用 av read frame input avFormatContext avPkt API 从 mp4 视频 编解码器为 h264 文件
  • 安全地使用 PHP exec 函数

    我正在编写一个 PHP 脚本 旨在通过 exec 函数运行可执行文件 ffmpeg exe 问题是我已经读到使用 exec 函数可能存在安全风险 应该尽可能避免 我一直在研究如何安全地运行 exec 函数 唯一遇到的问题是使用 escape
  • 如何从 Golang 访问 C 指针数组

    我正在使用 FFmpeg 为 Windows 平台编写一个应用程序 它是 golang 包装器 goav 但我无法理解如何使用 C 指针来访问数组 我试图获取存储在 AVFormatContext 类中的流以在 go 中使用 并最终将帧添加
  • 如何使用 FFmpeg 从图像创建视频? [关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的
  • FFmpeg:如何估计音频流中的样本数量?

    我目前正在编写一个小型应用程序 它利用 FFmpeg 库来解码 C 中的音频文件 尤其是 avformat 和 swresample 现在我需要音频流中的样本总数 我知道确切的数字只能通过实际解码所有帧才能找到 我只需要一个估计 这里的首选
  • 在 Visual Studio 中使用 FFmpeg

    我正在尝试在 Visual Studio 2010 的 C 项目中使用 FFmpeg 我想将这些库作为静态链接文件包含在内 简单的程序如libavcodec api example c http cekirdek pardus org tr
  • FFMPEG - 以特定时间间隔在视频上叠加多个视频

    我想以指定的时间间隔将多个视频叠加在单个视频上 尝试过不同的解决方案 但它不会像我一样工作 我使用下面的命令将视频叠加在视频上 String cmdWorking3 new String i yourRealPath i gifVideoF
  • 使用 FFmpeg 在特定时间将一个视频叠加在另一个视频上

    我正在尝试将一个视频与另一个视频叠加 我按照OP发布的原始命令进行操作here https stackoverflow com questions 35269387 ffmpeg overlay one video onto another
  • 使用 Popen 替换 Python 中的 Bash 进程

    我试图通过从 python 子进程库调用 ffmpeg 来创建循环视频文件 这是给我带来问题的部分 import subprocess as sp sp Popen ffmpeg f concat i lt for f in Desktop
  • RTSP 帧抓取会产生拖尾、像素化和损坏的图像

    我正在尝试使用以下命令从 RTSP 流中每秒捕获一帧 ffmpeg i rtsp XXX q v 1 vf fps fps 1 strftime 1 ZZZZ H M S jpg But some of the frames are sme
  • 如何将 ffplay 作为无窗口进程运行?

    我正在运行 ffplay 作为后台进程 它向我的主 UI 进程提供图像数据 我已经设定 SDL VIDEODRIVER dummy 抑制 SDL 窗口中显示的 ffplay 视频 问题是 即使不显示视频输出窗口 ffplay 进程仍然显示为
  • 在 Android 4.1/4.2 设备中使用 MediaCodec.getOutputFormat() 作为编码器的问题

    我正在尝试使用 MediaCodec 将帧 通过相机或解码器 编码为视频 当通过 dequeueOutputBuffer 处理编码器输出时 我期望收到返回索引 MediaCodec INFO OUTPUT FORMAT CHANGED 因此
  • OpenCV 3.0.0 使用 FFMPEG 时出错

    我使用 OpenCV 一段时间了 但是 我最近将系统更改为没有任何管理员权限的集群 问题是这样的 在我的主文件夹中 我安装了 FFMPEG ffmpeg 网站上提供的最新稳定版本 我将它安装在 HOME 中 因此在 HOME lib 中安装
  • 使用 ffmpeg 进行视频标准化

    无论如何 有没有使用 ffmpeg 脚本将视频亮度标准化为其完整的动态范围 我一直在尝试用 lutyuv 这样做 ffmpeg i input mp4 vf lutyuv y val minval 255 maxval minval 输出
  • pictureBox 图片处理异常

    我最近想尝试一下锻造网 http www aforgenet com framework 因为我发现它非常简单 所以我决定使用 Video FFMPEG 命名空间进行一些简单的视频播放 这样我就可以将每个帧直接放在 pictureBox 上
  • 为视频添加水印的命令

    我尝试在一个视频上添加水印 但 FFmpeg 命令不会执行 错误代码为 3037 我运行相同的代码来修剪视频 视频已成功修剪 因此没有问题inputpath or outputpath我也有ic watermark png在资产文件夹中 我
  • 在 R 中导入 png 文件并转换为动画(.mp4)

    我正在尝试用 R 中的几个 png 文件创建一个简短的动画 我尝试了 packagemagick但只有当我将它们保存为 gif 时它才有效 当我尝试另存为 mp4 时 它将生成一个 mp4 文件 但一旦打开它 只会显示第一张图像 我的代码是
  • ffmpeg创建RTP流

    我正在尝试使用 ffmpeg 进行编码和流式传输 libavcodec libavformat MSVC x64 with Zeranoe builds 这是我的代码 很大程度上改编自编码示例 删除了错误处理 include stdafx
  • FFmpeg - H264 编码器找不到有效设备并且无法配置编码器

    我尝试使用 H264 编码器进行编码 但是当我这样做时 出现以下错误 h264 v4l2m2m 0x55682d2416c0 Could not find a valid device h264 v4l2m2m 0x55682d2416c0

随机推荐

  • ROS学习笔记10:TF坐标变换(ROS常用组件)

    前言 xff1a 机器人本体和机器人的工作环境中往往存在大量的组件元素 xff0c 在机器人设计和应用中会涉及不同组件的位置和姿态 xff0c 这就需要引入坐标系和坐标变换的概念 一 机器人中空间描述和变换 xff1a 1 位置描述 xff
  • ROS学习笔记11:launch启动文件(ROS常用组件)

    一 launch启动文件介绍 xff1a 上节的海龟跟随实验 xff0c 输入的指令比较繁杂 xff0c 很容易输错命令 对于这种多节点任务 xff0c 可以使用启动文件 启动文件是ROS中一种可以通过xml文件 xff0c 同时启动多个节
  • 学习ARM架构,系统移植和驱动开发总结

    本次结束了对ARM架构 xff0c 系统移植和驱动开发的学习 xff0c 它们都是属于底层 xff0c 难度想对都比较的难一点 xff0c 但先学习arm架构之后去学习系统移植和驱动开发 xff0c 会使自己对系统移植和驱动开发容易理解点
  • Robocup2D环境搭配以及安装(Ubuntu18.04)

    个人是看过很多安装教程并且在一次次实验成 xfeff 功后得出的成果 xff1a 首先 xff0c 在gitee网站下载安装所需的文件夹 xfeff gitee网站下载zip压缩包 其次 xff0c 进行依赖库的安装 终端输入 sudo a
  • 树莓派配置网络实现ssh登录

    上面一篇文章我实现了串口方式访问树莓派 xff0c 可以实现树莓派开发 xff0c 但每次都需要接线 xff0c 比较麻烦所以我们可以对树莓派进行配置让他可以用IP地址登录 1 配置树莓派接入网络 sudo nano etc wpa sup
  • 字符串查找函数strstr

    前言 xff1a 本章我们将学习如何用strstr函数在字符串中查找是否存在指定的字符串 strstr 功能 xff1a 在一个字符串中查找是否存在指定的字符串 xff08 定位子字符串 xff09 cplusplus介绍如下 xff1a
  • Module not found: Error: Can‘t resolve ‘querystring‘ in ‘xxxxxxxxx‘

    解决办法 request js里面 import qs from 34 querystring 34 改为import qs from 34 qs 34
  • 【C语言】初学者写基础代码的基本步骤

    一 写代码 xff08 底阿妈 xff09 步骤 xff1a 1 创建一个项目 2 创建一个源文件 什么是源文件 xff1a xxxx c c开头的叫源文件 xxxx h h开头的叫头文件 3 写代码 xff08 底阿妈 xff09 one
  • ROS新手学习路线

    希望这些信息能够帮助你学习ROS 如果你有任何其他问题 xff0c 请随时告诉我 安装ROS 首先 xff0c 你需要在你的计算机上安装ROS 请参阅官方文档中的 安装 章节 xff0c 了解如何在你的系统上安装ROS xff1a http
  • JAVA学习心得体会

    这周是考试结束第一周 xff0c 刚开始继续学习JAVA时 xff0c 短时间不学习就感觉遗忘了许多有关JAVA的知识 xff0c 所以及时的复习所学内容是真的很重要 通过学长学姐的介绍 xff0c 我发现Typora记笔记是真的很方便 x
  • Ubuntu18.04在ROS下利用realsenseD435i相机实时运行ORB-SLAM2

    1 安装realsenseD435i的SDK Librealsense 可以参照这位博主 6条消息 Ubuntu18 04 43 ROS melodic 安装使用 InterRealSenseD435i SDK2和RealSense ROS
  • opencv-python识别魔方特定颜色方块,并输出各方块中心坐标

    先叠个甲 xff08 作者寒假才开始自学opencv xff0c 做题练手 xff0c 还不是很熟练 xff0c 如果有不正确或者有更好的方法 xff0c 欢迎在评论区指出 xff09 题目 xff1a 从网上寻找任一魔方图片 xff0c
  • Git教程学习笔记及VScode中Git使用

    文章目录 前言1 配置git2 创建版本库3 版本回退4 工作区和暂存区5 添加远程仓库6 分支管理处理bug分支多人协作 7 标签管理8 自定义git9 VScode中的Git使用 前言 欢迎通过我的个人博客看本篇文章https sunm
  • Qt的基本数据类型

    1 1 基本数据类型 qint8 signed charqint16 signed shortqint32 signed intqint64 long long int int64 on Windows qreal doublequint8
  • Qt——Javascript/Qt交互、脚本化

    Qt提供了对Javascript的良好支持 如果查阅过文档你就知道Qt有两个不同的Js封装引擎 xff1a QScriptEngine QJSEngine QScriptEngine出现的比较早 xff08 自Qt4 3始 xff09 xf
  • QT自绘标题和边框

    在QT中如果想要自绘标题和边框 xff0c 一般步骤是 xff1a 1 xff09 在创建窗口前设置Qt FramelessWindowHint标志 xff0c 设置该标志后会创建一个无标题 无边框的窗口 2 xff09 在客户区域的顶部创
  • Qt:QSqlQuery

    0 说明 QSqlQuery提供了执行SQL代码的方法 QSqlQuery封装了在QSqlDatabase中查询 检索数据的相关函数 它可以用来执行如SELECT INSERT UPDATE DELETE等方法 xff0c 也可以执行如CR
  • Qt - 读取GPS数据

    1 GPS型号为ublox xff08 EVK M8L xff09 xff0c 配有USB接口 xff0c Qt版本5 7 2 实现步骤 xff1a 1 实现串口通信 采用Qt5 7 内置的串口操作类QSerialPort和QSerialP
  • QT打包的两种方式

    QT打包的两种方式 xff1a 一个是QT5自带的windeployqt xff08 不需要下载安装 xff09 xff0c 它可以找到程序 xff08 exe xff09 用到的所有库文件 xff0c 并且都拷贝到exe程序的当前文件 此
  • Qt使用FFmpeg播放视频

    一 使用场景 因为项目中需要加载MP4播放开机视频 xff0c 而我们的设备所使用的架构为arm架构 xff0c 其中缺乏一些多媒体库 安装这些插件库比较麻烦 xff0c 所以最终决定使用FFmpeg播放视频 二 下载编译ffmpeg库 2