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…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
