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 中显示。
播放控制:实现了播放和暂停控制,同时可以通过定时器 (`

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/60126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java导出word文件(手绘)

文章目录 代码细节效果图参考资料 代码细节 使用的hutool的WordUtil&#xff0c;WordUtil对poi进行封装&#xff0c;但是这一块的官方封装的很少&#xff0c;很多细节都没有。代码中是常见的绘制段落&#xff0c;标题、表格等常用api Word07Writer writer WordUtil.getWriter(…

UML的另一个主角——用例图

顺序图和类图已经出过单集&#xff0c;本贴要分享的是用例图。 类图https://blog.csdn.net/jsl123x/article/details/143526286?spm1001.2014.3001.5501顺序图https://jslhyh32.blog.csdn.net/article/details/134350587 目录 一.系统 二.参与者 1.主要参与者 2.次要参与…

《TCP/IP网络编程》学习笔记 | Chapter 4:基于TCP的服务器端/客户端(1)

《TCP/IP网络编程》学习笔记 | Chapter 4&#xff1a;基于TCP的服务器端/客户端&#xff08;1&#xff09; 《TCP/IP网络编程》学习笔记 | Chapter 4&#xff1a;基于TCP的服务器端/客户端&#xff08;1&#xff09;理解TCP和UDPTCP/IP协议栈TCP/IP协议的诞生背景链路层网络层T…

【基于PSINS工具箱】以速度为观测量的SINS/GNSS组合导航,UKF滤波

基于【PSINS工具箱】&#xff0c;提供一个MATLAB例程&#xff0c;仅以速度为观测量的SINS/GNSS组合导航&#xff08;滤波方式为UKF&#xff09; 文章目录 工具箱程序简述运行结果 代码程序讲解MATLAB 代码教程&#xff1a;使用UKF进行速度观测1. 引言与基本设置2. 初始设置3. U…

【Vue】Vue3.0(十七)Vue 3.0中Pinia的深度使用指南(基于setup语法糖)

上篇文章&#xff1a; 【Vue】Vue3.0&#xff08;十一&#xff09;Vue 3.0 中 computed 计算属性概念、使用及示例 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月10日15点23分 文章…

跨境云专线:构建高速、安全的全球业务网络

在企业出海加速的背景下&#xff0c;越来越多的企业需要在全球范围内部署业务&#xff0c;特别是在多个国家和地区之间进行数据传输。然而&#xff0c;跨境网络连接常常面临带宽不足、延迟高、数据安全性差等问题&#xff0c;这给企业的业务运营带来了巨大挑战。为了解决这些问…

分布式——BASE理论

简单来说&#xff1a; BASE&#xff08;Basically Available、Soft state、Eventual consistency&#xff09;是基于CAP理论逐步演化而来的&#xff0c;核心思想是即便不能达到强一致性&#xff08;Strong consistency&#xff09;&#xff0c;也可以根据应用特点采用适当的方…

UE5.4 PCG 获取地形Layer

使用AttributeFilter&#xff1a;属性过滤器 节点 设置地形Layer名称和权重 效果&#xff1a;

使用wordpress搭建简易的信息查询系统

背景 当前有这样的一个需求&#xff0c;要实现让客户能够自助登录系统查询一些个人的信息&#xff0c;市面上没有特别符合我的需求的产品&#xff0c;经过一段时间的研究&#xff0c;想出了一个用wordpress实现简易信息查询系统&#xff0c;有两种方式。 方式一&#xff1a;使…

EasyUI弹出框行编辑,通过下拉框实现内容联动

EasyUI弹出框行编辑&#xff0c;通过下拉框实现内容联动 需求 实现用户支付方式配置&#xff0c;当弹出框加载出来的时候&#xff0c;显示用户现有的支付方式&#xff0c;datagrid的第一列为conbobox,下来选择之后实现后面的数据直接填充&#xff1b; 点击新增&#xff1a;新…

ssm079基于SSM框架云趣科技客户管理系统+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;客户管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本客户管理系统就是在这…

PICO+Unity 用手柄点击UI界面

如果UI要跟随头显&#xff0c;可将Canvas放置到XR Origin->Camera Offset->Main Camera下 1.Canvas添加TrackedDeviceGraphicRaycaster组件 2.EventSystem移动默认的Standard Input Module&#xff0c;添加XRUIInputModule组件 3.&#xff08;可选&#xff09;设置射线可…

apt镜像源制作-ubuntu22.04

# 安装必要的软件 sudo apt-get install -y apt-mirror # 编辑/etc/apt/mirror.list,添加以下内容 set base_path /var/spool/apt-mirror # 指定要镜像的Ubuntu发布和组件-null dir jammy-updates main restricted universe multiverse # 镜像的Ubuntu发布和组件的URL-n…

springboot初体验

目录 环境 controller 修改端口号 更改banner图标 运行结果 最核心的:自动装配 环境 jdk17springboot3.3.5maven3.8.2 controller controller层和启动类同级 package com.example.demo.controller; ​ import org.springframework.web.bind.annotation.RequestMapping;…

Q:警告无法解释导入PIL Pylance(reportMisssingIMports)

问题显示&#xff1a; 解决方法&#xff1a; 1.确认安装 Pillow&#xff1a;在 VS Code 的终端中运行以下命令&#xff0c;以确保环境中安装了 Pillow pip install pillow2.选择正确的解释器&#xff1a;在 VS Code 中&#xff0c;按下 CtrlShiftP&#xff0c;输入并选择 “P…

python中常见的8种数据结构之一数组的应用

在Python中&#xff0c;数组是一种常见的数据结构&#xff0c;用于存储一系列相同类型的元素。在实际应用中&#xff0c;数组可以用于解决各种问题。 以下是数组在Python中的一些常见应用&#xff1a; 1. 存储和访问数据&#xff1a;数组可以用于存储和访问一组数据。可以通过…

网络安全——下载并在kali虚拟机上启动Cobalt Strike

目录 一、下载 二、上传文件到kali虚拟机 三、启动服务端 四、启动客户端 一、下载 CobaltStrike4.8汉化版带插件-CSDN博客 下载并解压后 二、上传文件到kali虚拟机 1、打开并运行kali虚拟机&#xff0c;查看kali的ip地址 2、打开xshell&#xff0c;新建连接&#xff0c;连…

用 Python 从零开始创建神经网络(四):激活函数(Activation Functions)

激活函数&#xff08;Activation Functions&#xff09; 引言1. 激活函数的种类a. 阶跃激活功能b. 线性激活函数c. Sigmoid激活函数d. ReLU 激活函数e. more 2. 为什么使用激活函数3. 隐藏层的线性激活4. 一对神经元的 ReLU 激活5. 在隐蔽层中激活 ReLU6. ReLU 激活函数代码7. …

22.oop-strust与class

OOP是什么&#xff1a;oop 是面向对象编程,面向对象编程是一种计算机编程架构, OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或 对象组、合而成。 OOP有什么特性&#xff1a; 1、封装性&#xff1a;也称为信息隐藏&#xff0c;就是将一个类的使用和实现分开…

【Linux】ubuntu安装图形化界面步骤

一、ubuntu 安装桌面环境 1、更新软件包列表&#xff08;命令↓&#xff09; sudo apt update 2、安装桌面环境GNOME&#xff08;命令↓&#xff09; sudo apt install ubuntu-desktop 3、安装完成后需要重启服务器&#xff08;服务器重启命令↓&#xff09; sudo reboot 二、…