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…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
渗透实战PortSwigger靶场:lab13存储型DOM XSS详解
进来是需要留言的,先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码,输入的<>当成字符串处理回显到页面中,看来只是把用户输…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
