一、概述
本项目使用 QMediaPlayer 和 QAudioOutput 分离的音频架构采用 QVideoWidget 作为视频输出组件,为Qt6风格语法。项目结构简单,适合初学者或想熟悉Qt6新风格的程序员。
仓库:https://github.com/orpheanlive/Qt-video.git
二、内容
.h
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMediaPlayer>
#include <QAudioOutput>
#include <QVideoWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QMediaPlayer *player;
QAudioOutput *audioOutput;
QString drtTime;
QString posTime;
private slots:
void onPlaybackStateChanged(QMediaPlayer::PlaybackState state);
void onDurationChanged(qint64 duration);
void onPositionChanged(qint64 position);
void onMediaStatusChanged(QMediaPlayer::MediaStatus status);
void onErrorOccurred(QMediaPlayer::Error error, const QString &errorString);
void on_file_clicked();
void on_play_clicked();
void on_pause_clicked();
void on_stop_clicked();
void on_sound_clicked();
void onVolumeSliderChanged(int value);
void onProgressSliderReleased();
};
#endif // MAINWINDOW_H
.cpp
cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QFileDialog>
#include <QDir>
#include <QFileInfo>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 初始化媒体播放器
player = new QMediaPlayer(this);
audioOutput = new QAudioOutput(this);
player->setAudioOutput(audioOutput);
// 设置视频输出到UI中的videoWidget
player->setVideoOutput(ui->videoWidget);
// 连接信号槽
connect(player, &QMediaPlayer::playbackStateChanged, this, &MainWindow::onPlaybackStateChanged);
connect(player, &QMediaPlayer::durationChanged, this, &MainWindow::onDurationChanged);
connect(player, &QMediaPlayer::positionChanged, this, &MainWindow::onPositionChanged);
connect(player, &QMediaPlayer::mediaStatusChanged, this, &MainWindow::onMediaStatusChanged);
connect(player, &QMediaPlayer::errorOccurred, this, &MainWindow::onErrorOccurred);
// 设置初始音量
audioOutput->setVolume(0.7);
// 初始化按钮状态
ui->play->setEnabled(true);
ui->pause->setEnabled(false);
ui->stop->setEnabled(false);
qDebug() << "Media player initialized successfully";
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onPlaybackStateChanged(QMediaPlayer::PlaybackState state)
{
qDebug() << "Playback state:" << state;
switch (state) {
case QMediaPlayer::StoppedState:
ui->play->setEnabled(true);
ui->pause->setEnabled(false);
ui->stop->setEnabled(false);
break;
case QMediaPlayer::PlayingState:
ui->play->setEnabled(false);
ui->pause->setEnabled(true);
ui->stop->setEnabled(true);
break;
case QMediaPlayer::PausedState:
ui->play->setEnabled(true);
ui->pause->setEnabled(false);
ui->stop->setEnabled(true);
break;
default:
break;
}
}
void MainWindow::onDurationChanged(qint64 duration)
{
qDebug() << "Duration changed:" << duration;
ui->progressSlider->setRange(0, duration);
int sec = duration / 1000;
int min = sec / 60;
sec = sec % 60;
int hour = min / 60;
min = min % 60;
if (hour > 0) {
drtTime = QString::asprintf("%02d:%02d:%02d", hour, min, sec);
} else {
drtTime = QString::asprintf("%02d:%02d", min, sec);
}
ui->timeLabel->setText(posTime + " / " + drtTime);
}
void MainWindow::onPositionChanged(qint64 position)
{
if (!ui->progressSlider->isSliderDown()) {
ui->progressSlider->setValue(position);
}
int sec = position / 1000;
int min = sec / 60;
sec = sec % 60;
int hour = min / 60;
min = min % 60;
if (hour > 0) {
posTime = QString::asprintf("%02d:%02d:%02d", hour, min, sec);
} else {
posTime = QString::asprintf("%02d:%02d", min, sec);
}
ui->timeLabel->setText(posTime + " / " + drtTime);
}
void MainWindow::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
{
qDebug() << "Media status:" << status;
}
void MainWindow::onErrorOccurred(QMediaPlayer::Error error, const QString &errorString)
{
qDebug() << "Media player error:" << error << errorString;
ui->fileNameLabel->setText("错误: " + errorString);
}
void MainWindow::on_file_clicked()
{
QString currentpath = QDir::currentPath();
QString dlgtitle = "请选择视频文件";
QString filter = "视频文件 (*.mp4 *.avi *.mkv *.mov *.wmv *.flv);;"
"所有文件 (*.*)";
QString strfile = QFileDialog::getOpenFileName(this, dlgtitle, currentpath, filter);
if (strfile.isEmpty()) {
qDebug() << "No file selected";
return;
}
QFileInfo fileinfo(strfile);
QString fileName = fileinfo.fileName();
ui->fileNameLabel->setText("文件: " + fileName);
qDebug() << "Selected file:" << strfile;
// 停止当前播放
player->stop();
// 设置媒体源
QUrl fileUrl = QUrl::fromLocalFile(strfile);
player->setSource(fileUrl);
qDebug() << "Setting source to:" << fileUrl;
}
void MainWindow::on_play_clicked()
{
player->play();
}
void MainWindow::on_pause_clicked()
{
player->pause();
}
void MainWindow::on_stop_clicked()
{
player->stop();
ui->progressSlider->setValue(0);
posTime = "00:00";
ui->timeLabel->setText(posTime + " / " + drtTime);
}
void MainWindow::on_sound_clicked()
{
bool muted = audioOutput->isMuted();
audioOutput->setMuted(!muted);
// 更新按钮文本
if (audioOutput->isMuted()) {
ui->sound->setText("静音");
} else {
ui->sound->setText("声音");
}
}
void MainWindow::onVolumeSliderChanged(int value)
{
float volume = value / 100.0f;
audioOutput->setVolume(volume);
// 自动静音/取消静音
if (value == 0 && !audioOutput->isMuted()) {
audioOutput->setMuted(true);
ui->sound->setText("静音");
} else if (value > 0 && audioOutput->isMuted()) {
audioOutput->setMuted(false);
ui->sound->setText("声音");
}
}
void MainWindow::onProgressSliderReleased()
{
qint64 position = ui->progressSlider->value();
player->setPosition(position);
}