Qt 环境实现视频和音频播放
在这个示例中,我们将使用 FFmpeg 进行视频和音频的解码,并使用 Qt 的界面进行显示和控制。为了实现音频和视频的解码以及同步显示,我们需要使用 FFmpeg 的解码库进行视频和音频解码,使用 Qt 的 QLabel 显示解码后的视频帧,使用 QAudioOutput 来播放解码后的音频。
环境依赖
FFmpeg:用于解码音视频数据。
Qt:用于图形界面和音频输出。
示例代码
这是一个使用 Qt 和 FFmpeg 结合实现的视频播放器,包括播放、暂停、进度条等功能。
#include <QMainWindow>
#include <QTimer>
#include <QSlider>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QWidget>
#include <QImage>
#include <QPixmap>
#include <QFileDialog>
#include <QAudioOutput>
#include <QAudioFormat>// FFmpeg 头文件
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/imgutils.h>
}class VideoPlayer : public QMainWindow {Q_OBJECTpublic:VideoPlayer(QWidget *parent = nullptr);~VideoPlayer();private slots:void play();void pause();void openFile();void updateFrame();private:void initializeFFmpeg();void decodeVideo();void decodeAudio();void displayFrame(AVFrame *frame);void initializeAudio();void audioOutput();AVFormatContext *formatContext;AVCodecContext *videoCodecContext;AVCodecContext *audioCodecContext;SwsContext *swsContext;SwrContext *swrContext;int videoStreamIndex;int audioStreamIndex;QLabel *videoLabel;QPushButton *playButton;QPushButton *pauseButton;QSlider *progressSlider;QTimer *timer;QAudioOutput *audioOutputDevice;QByteArray audioBuffer;bool isPlaying;
};VideoPlayer::VideoPlayer(QWidget *parent) : QMainWindow(parent), isPlaying(false) {// GUI 部件初始化videoLabel = new QLabel(this);playButton = new QPushButton("Play", this);pauseButton = new QPushButton("Pause", this);progressSlider = new QSlider(Qt::Horizontal, this);timer = new QTimer(this);// 布局QHBoxLayout *controlLayout = new QHBoxLayout;controlLayout->addWidget(playButton);controlLayout->addWidget(pauseButton);controlLayout->addWidget(progressSlider);QVBoxLayout *mainLayout = new QVBoxLayout;mainLayout->addWidget(videoLabel);mainLayout->addLayout(controlLayout);QWidget *centralWidget = new QWidget(this);centralWidget->setLayout(mainLayout);setCentralWidget(centralWidget);// 连接信号和槽connect(playButton, &QPushButton::clicked, this, &VideoPlayer::play);connect(pauseButton, &QPushButton::clicked, this, &VideoPlayer::pause);connect(timer, &QTimer::timeout, this, &VideoPlayer::updateFrame);// 初始化 FFmpeginitializeFFmpeg();initializeAudio();
}VideoPlayer::~VideoPlayer() {avcodec_free_context(&videoCodecContext);avcodec_free_context(&audioCodecContext);avformat_close_input(&formatContext);sws_freeContext(swsContext);swr_free(&swrContext);
}void VideoPlayer::initializeFFmpeg() {av_register_all();formatContext = avformat_alloc_context();QString fileName = QFileDialog::getOpenFileName(this, "Open Video File");if (fileName.isEmpty()) {return;}// 打开文件并找到流avformat_open_input(&formatContext, fileName.toStdString().c_str(), nullptr, nullptr);avformat_find_stream_info(formatContext, nullptr);// 查找视频流和音频流for (unsigned int i = 0; i < formatContext->nb_streams; i++) {AVCodecParameters *codecParams = formatContext->streams[i]->codecpar;AVCodec *codec = avcodec_find_decoder(codecParams->codec_id);if (codecParams->codec_type == AVMEDIA_TYPE_VIDEO) {videoCodecContext = avcodec_alloc_context3(codec);avcodec_parameters_to_context(videoCodecContext, codecParams);avcodec_open2(videoCodecContext, codec, nullptr);videoStreamIndex = i;} else if (codecParams->codec_type == AVMEDIA_TYPE_AUDIO) {audioCodecContext = avcodec_alloc_context3(codec);avcodec_parameters_to_context(audioCodecContext, codecParams);avcodec_open2(audioCodecContext, codec, nullptr);audioStreamIndex = i;// 音频重采样设置swrContext = swr_alloc();swr_alloc_set_opts(swrContext, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16,audioCodecContext->sample_rate, audioCodecContext->channel_layout,audioCodecContext->sample_fmt, audioCodecContext->sample_rate, 0, nullptr);swr_init(swrContext);}}// 视频缩放上下文swsContext = sws_getContext(videoCodecContext->width, videoCodecContext->height,videoCodecContext->pix_fmt, videoCodecContext->width,videoCodecContext->height, AV_PIX_FMT_RGB24, SWS_BILINEAR,nullptr, nullptr, nullptr);
}void VideoPlayer::initializeAudio() {QAudioFormat format;format.setSampleRate(audioCodecContext->sample_rate);format.setChannelCount(2);format.setSampleSize(16);format.setCodec("audio/pcm");format.setByteOrder(QAudioFormat::LittleEndian);format.setSampleType(QAudioFormat::SignedInt);audioOutputDevice = new QAudioOutput(format, this);
}void VideoPlayer::play() {isPlaying = true;audioOutputDevice->start();timer->start(30); // 30ms刷新一次
}void VideoPlayer::pause() {isPlaying = false;audioOutputDevice->suspend();timer->stop();
}void VideoPlayer::updateFrame() {decodeVideo();decodeAudio();
}void VideoPlayer::decodeVideo() {AVPacket packet;while (av_read_frame(formatContext, &packet) >= 0) {if (packet.stream_index == videoStreamIndex) {avcodec_send_packet(videoCodecContext, &packet);AVFrame *frame = av_frame_alloc();if (avcodec_receive_frame(videoCodecContext, frame) == 0) {displayFrame(frame);}av_frame_free(&frame);}av_packet_unref(&packet);}
}void VideoPlayer::decodeAudio() {AVPacket packet;while (av_read_frame(formatContext, &packet) >= 0) {if (packet.stream_index == audioStreamIndex) {avcodec_send_packet(audioCodecContext, &packet);AVFrame *frame = av_frame_alloc();if (avcodec_receive_frame(audioCodecContext, frame) == 0) {// 音频重采样int outSamples = swr_convert(swrContext, nullptr, 0,(const uint8_t **)frame->data, frame->nb_samples);audioBuffer.resize(outSamples * 2 * sizeof(int16_t));audioOutputDevice->write(audioBuffer.data(), audioBuffer.size());}av_frame_free(&frame);}av_packet_unref(&packet);}
}void VideoPlayer::displayFrame(AVFrame *frame) {AVFrame *rgbFrame = av_frame_alloc();int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, videoCodecContext->width,videoCodecContext->height, 1);uint8_t *buffer = (uint8_t *)av_malloc(numBytes);av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, buffer, AV_PIX_FMT_RGB24,videoCodecContext->width, videoCodecContext->height, 1);sws_scale(swsContext, frame->data, frame->linesize, 0, videoCodecContext->height,rgbFrame->data, rgbFrame->linesize);QImage img(rgbFrame->data[0], videoCodecContext->width, videoCodecContext->height,QImage::Format_RGB888);videoLabel->setPixmap(QPixmap::fromImage(img));av_free(buffer);av_frame_free(&rgbFrame);
}#include "main.moc"
代码说明
FFmpeg 初始化和解码:通过 initializeFFmpeg 初始化视频和音频流,设置解码器以及音视频重采样(用于音频)。
音频输出:通过 QAudioOutput 将解码后的音频数据写入到音频输出设备中。
视频显示:解码后的视频帧通过 sws_scale 转换为 RGB24 格式并在 QLabel 中显示。
播放控制:实现了播放和暂停控制,同时可以通过定时器 (`
相关文章:
Qt 环境实现视频和音频播放
在这个示例中,我们将使用 FFmpeg 进行视频和音频的解码,并使用 Qt 的界面进行显示和控制。为了实现音频和视频的解码以及同步显示,我们需要使用 FFmpeg 的解码库进行视频和音频解码,使用 Qt 的 QLabel 显示解码后的视频帧…...
【人工智能训练师】7 大数据处理与应用
大数据处理与应用(Hive技术)(0/100分) 1.本地开发工具连接Hadoop集群 1.本次环境版本为Hadoop2.7.7,对应eclips插件存放于云主机master:/usr/package277/中。 2.本机映射名为hadoop000,云主机Hadoop/Hive的hosts文件中IP需要修改…...
nginx配置文件介绍及示例
一、nginx配置文件一共有main,http,server,location,upstream,stream,events7个块。 step 1: main 块 作用:main 块是 Nginx 配置文件的顶级块,用于设置一些全局的参数和配置&…...
如何在算家云搭建YOLOv5(物体检测)
一、YOLOv5简介 YOLOv5 模型是一种以实时物体检测闻名的计算机视觉模型,由 Ultralytics 开发,并于 2020 年年中发布。它是 YOLO 系列的升级版,继承了 YOLO 系列以实时物体检测能力而著称的特点。 二、模型搭建流程 1.选择模型实例 在应用…...
现场工程师日记-MSYS2迅速部署PostgreSQL主从备份数据库
文章目录 一、概要二、整体架构流程1. 安装 MSYS2 环境2. 安装postgresql 三、技术名词解释1.MSYS22.postgresql 四、技术细节1. 创建主数据库2.添加从数据库复制权限3. 按需修改参数(1)WAL保留空间(2)监听地址 4. 启动主服务器5.…...
使用Element UI实现一个拖拽图片上传,并可以Ctrl + V获取图片实现文件上传
要在 Element UI 的拖拽上传组件中实现 Ctrl V 图片上传功能,可以通过监听键盘事件来捕获粘贴操作,并将粘贴的图片数据上传到服务器。 版本V1,实现获取粘贴板中的文件 注意,本案例需要再你已经安装了Element UI并在项目中正确配…...
私域流量圈层在新消费时代的机遇与挑战:兼论开源 AI 智能名片、2 + 1 链动模式、S2B2C 商城小程序的应用
摘要:本文剖析了私域流量圈层在新消费时代呈现出的独特温度与信任优势,阐述了从传统销售到新消费转型中用户心理的变化。同时,强调了内容对于私域流量的关键作用,并分析开源 AI 智能名片、2 1 链动模式、S2B2C 商城小程序在私域流…...
vxe-vxe-colgroup后端返回数据 对数据进行处理 动态合并分组表头(v-if控制表格渲染(数据请求完成后渲染))
1.html vxe-colgroup循环合并数据;v-if控制表格渲染(数据请求完成后渲染) <template><vxe-table v-if"isTableReady" :data"tableData"><vxe-colgroup title"基本信息"><template v-for…...
ESLint 使用教程(五):从输入 eslint 命令到最终代码被处理,ESLint 中间究竟做了什么工作
前言 ESLint 是现代 JavaScript 开发中不可或缺的代码质量工具。它能够帮助开发者找到并修复代码中的问题,提升代码的可维护性。但是,你可能会好奇:从我们在终端里输入 eslint 命令到最终代码被处理,ESLint 中间究竟做了什么工作…...
【安全测试】sqlmap工具(sql注入)学习
前言:sqimap是一个开源的渗透测试工具,它可以自动化检测和利用SQL注入缺陷以及接管数据库服务器的过程。它有一个强大的检测引擎,许多适合于终极渗透测试的小众特性和广泛的开关,从数据库指纹、从数据库获 取数据到访问底层文件系…...
YOLOv11融合CVPR[2023]空间和通道重建卷积ScConv模块及相关改进思路|YOLO改进最简教程
YOLOv11v10v8使用教程: YOLOv11入门到入土使用教程 YOLOv11改进汇总贴:YOLOv11及自研模型更新汇总 《SCConv: Spatial and Channel Reconstruction Convolution for Feature Redundancy》 一、 模块介绍 论文链接:SCConv: Spatial and Cha…...
C++研发笔记13——C语言程序设计初阶学习笔记11
从今天开始我们开始第三模块《分支语句和循环语句》的学习,在本模块中我们将会涉及到以下9个内容:什么是语句、分支语句——if语言、分支语句——switch语句、循环语句——while循环、循环语句——for循环、循环语句——do while循环、折半查找算法、猜数…...
html5拖放
1、什么是拖放(Drag 和 Drop) 拖放,字面意思就是拖动,放置 在编程里面也是如此,拖放是一种常见的特性,即抓取对象以后拖到另一个位置。 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放。…...
卫导调零天线功率倒置算法原理及MATLAB仿真
卫导调零天线功率倒置算法原理及MATLAB仿真 文章目录 前言一、调零天线简介二、功率倒置自适应算法三、MATLAB仿真四、MATLAB代码总结 前言 \;\;\;\;\; 自适应调零抗干扰技术可以很大程度改善导航抗干扰性能,也是目前导航抗干扰技术中不可或缺的,其研究意…...
【划分型 DP】力扣139. 单词拆分
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例 1: 输入: s “leetcode”, wordDic…...
Python学习从0到1 day26 第三阶段 Spark ④ 数据输出
半山腰太挤了,你该去山顶看看 —— 24.11.10 一、输出为python对象 1.collect算子 功能: 将RDD各个分区内的数据,统一收集到Driver中,形成一个List对象 语法: rdd.collect() 返回值是一个list列表 示例: from …...
AWTK fscript 中的 JSON 扩展函数
fscript 是 AWTK 内置的脚本引擎,开发者可以在 UI XML 文件中直接嵌入 fscript 脚本,提高开发效率。本文介绍一下 fscript 中的 ** JSON 扩展函数 ** 1.json_load 加载 json 数据。 原型 json_load(str) > object json_load(binary) > object js…...
动态规划 —— dp 问题-买卖股票的最佳时机III
1. 买卖股票的最佳时机III 题目链接: 123. 买卖股票的最佳时机 III - 力扣(LeetCode)https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/description/ 2. 题目解析 3. 算法原理 状态表示:以某一个位置为结尾或者…...
“绽放艺术风采、激发强国力量” 海南省第十一届中小学生艺术展演活动圆满开展
2024年11月1日,由省教育厅主办、琼台师范学院承办的海南省第十一届中小学生艺术展演省级展演活动在海口正式拉开帷幕。来自全省各市县、省属学校等共计4000余名师生参加本届中小学生艺术展演现场展演活动。 本届展演活动以“绽放艺术风采、激发强国力量”为主题&…...
Linux之文件和目录类命令详解(2)
Linux之文件和目录类命令详解(2) 1、mv-移动文件或重命名2、find-查找文件和目录3、locate-快速查找文件4、du-显示目录或文件的磁盘使用情况5、df-显示文件系统的磁盘空间使用情况6、chmod-更改文件或目录的权限7、chown-更改文件或目录的拥有者8、tree…...
AI智能证件照制作工坊高可用部署:生产环境配置建议
AI智能证件照制作工坊高可用部署:生产环境配置建议 1. 项目概述与核心价值 AI智能证件照制作工坊是一个商业级证件照生产工具,基于Rembg高精度抠图引擎构建。这个工具能够将普通的生活照或自拍照,通过全自动流程转换为符合标准的证件照&…...
CLIP-GmP-ViT-L-14开发者案例:基于CLIP-GmP-ViT-L-14构建私有图文检索原型系统
CLIP-GmP-ViT-L-14开发者案例:基于CLIP-GmP-ViT-L-14构建私有图文检索原型系统 1. 引言:从想法到原型,一个下午就够了 你有没有遇到过这样的场景?手头有一堆产品图片,需要快速找到哪张图对应“一个穿着红色衣服的人在…...
Gradio实战:用gr.Button和gr.Markdown打造高颜值交互界面(附CSS美化技巧)
Gradio界面美学革命:从基础组件到高级定制的全链路设计指南 在AI应用爆炸式增长的今天,一个美观直观的交互界面已经成为产品成功的关键因素。Gradio作为最受欢迎的AI应用快速构建工具,其默认样式往往难以满足专业级产品的视觉需求。本文将带您…...
欧拉Euler~21.10系统下OpenSSH 9.0升级与安全加固实战指南
1. 环境准备:从零搭建OpenSSH 9.0升级基础 在欧拉Euler~21.10系统上升级OpenSSH,就像给老房子换新门窗——既要保证新功能正常使用,又不能破坏原有结构。我最近刚在测试环境完成这套操作,整个过程踩过几个坑,这里把完整…...
SAP IDoc入站出站处理全流程拆解:从WE19测试到IDOC_INPUT_函数调试
SAP IDoc接口开发实战:从零构建到生产环境调试全指南 在SAP系统集成领域,IDoc(Intermediate Document)作为企业级数据交换的标准载体,其重要性不言而喻明。不同于简单的文件传输,一个健壮的IDoc接口需要开发…...
极简安装方案:树莓派部署OpenClaw轻量版对接云端Qwen3-32B
极简安装方案:树莓派部署OpenClaw轻量版对接云端Qwen3-32B 1. 为什么选择树莓派OpenClaw轻量版? 去年夏天,我突发奇想:能不能用树莓派做个24小时在线的AI管家?既能控制智能家居,又能处理简单办公任务。但…...
阿联酋人工智能大学:AI能在战争迷雾中做出理性判断吗?
这项由阿联酋穆罕默德本扎耶德人工智能大学和美国马里兰大学共同完成的研究发表于2026年3月,论文编号为arXiv:2603.16642v1。有兴趣深入了解的读者可以通过该编号查询完整论文。在人类历史上,预测战争走向一直是个极其困难的任务。就像我们很难在暴风雨中…...
AI 模型推理框架性能分析与对比
AI模型推理框架性能分析与对比 随着人工智能技术的快速发展,AI模型推理框架成为支撑各类应用落地的核心工具。无论是计算机视觉、自然语言处理还是推荐系统,高效的推理框架直接影响模型的响应速度、资源占用和部署成本。本文将从多个维度对比主流AI推理…...
【收藏干货】IndexRAG:离线生成桥接事实,实现单次检索的多跳推理
plaintext IndexRAG: Bridging Facts for Cross-Document Reasoning at Index Timehttps://arxiv.org/pdf/2603.16415 ### 一、多跳QA的困境多跳问答(Multi-hop QA)要求模型跨越多篇文档进行推理,比如回答"电影Aylwin的导演出生在哪里&q…...
各向异性方解石晶体的双折射效应
1. 摘要 双折射效应是各向异性材料最重要的光学特性,并广泛应用于多种光学器件。当入射光波撞击各向异性材料,会以不同的偏振态分束到不同路径,即众所周知的寻常光束和异常光束。在本示例中,描述了如何利用VirtualLab Fusion对双折…...
