基于QT和opencv的视频播放器
CMakeLists.txtcmake_minimum_required(VERSION 3.5)
project(player VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(OpenCV_DIR "/usr/local/include/opencv4")
set(OpenCV_LIBS opencv_core opencv_imgproc opencv_highgui opencv_imgcodecs)
find_package(OpenCV REQUIRED)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(${PROJECT_NAME}
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET player APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
if(ANDROID)
add_library(${PROJECT_NAME} SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(${PROJECT_NAME}
${PROJECT_SOURCES}
)
endif()
endif()
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${OpenCV_LIBS})
set_target_properties(${PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
install(TARGETS ${PROJECT_NAME}
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(${PROJECT_NAME})
endif()
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMessageBox>
#include <QFileDialog>
#include <opencv2/opencv.hpp>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void showFrame(const cv::Mat &frame);
private slots:
void on_playButton_clicked();
void on_stopButton_clicked();
void choose_video_file();
void on_horizontalSlider_sliderMoved(int position);
void importFrame();
private:
Ui::MainWindow *ui;
cv::VideoCapture capture;
QString file_name;
qint64 position=50;
QTimer *timer;
cv::Mat frame;
int video_width=0;
int video_height=0;
double duration=0;
int total_frames=0;
double fps = 0;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QRect rect =ui->label->geometry();
video_width = rect.width();
video_height = rect.height();
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(importFrame()));
connect(ui->action, SIGNAL(triggered()), this, SLOT(choose_video_file()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_playButton_clicked()
{
if (file_name.isEmpty()) {
QMessageBox::warning(this, "警告", "请选择文件再播放");
}else{
capture = cv::VideoCapture(file_name.toStdString());
if (!capture.isOpened()){
QMessageBox::critical(this, tr("严重警告"), tr("这个视频文件有问题"));
}
total_frames = (int)capture.get(cv::CAP_PROP_FRAME_COUNT);
fps = capture.get(cv::CAP_PROP_FPS);
duration = total_frames / fps;
ui->horizontalSlider->setMaximum(duration);
capture.set(cv::CAP_PROP_POS_FRAMES, position);
timer->start(30);
}
}
void MainWindow::on_stopButton_clicked()
{
timer->stop();
}
void MainWindow::on_horizontalSlider_sliderMoved(int position)
{
qDebug()<<position;
ui->horizontalSlider->setSliderPosition(position / fps);
capture.set(cv::CAP_PROP_POS_FRAMES, position);
timer->start(30);
}
void MainWindow::showFrame(const cv::Mat &frame){
cv::Mat rgb;
cv::cvtColor(frame, rgb, cv::COLOR_BGR2RGB);
QImage image((uchar*)rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888);
ui->label->setPixmap(QPixmap::fromImage(image));
}
void MainWindow::importFrame()
{
capture >> frame;
if (!frame.empty()){
position = capture.get(cv::CAP_PROP_POS_FRAMES);
ui->horizontalSlider->setSliderPosition(position / fps);
cv::flip(frame,frame,180);
cvtColor(frame, frame, cv::COLOR_BGR2RGB);
QImage srcQImage = QImage((uchar*)(frame.data), frame.cols, frame.rows, QImage::Format_RGB888);
QPixmap pix_map = QPixmap::fromImage(srcQImage);
pix_map = pix_map.scaled(800, 600);
ui->label->setPixmap(pix_map);
ui->label->show();
}
}
void MainWindow::choose_video_file(){
file_name = QFileDialog::getOpenFileName(
this,
tr("open a file."),
".",
tr("video files(*.avi *.mp4 *.wmv *.flv *.mpeg *.m4v *.mov *.asf *.f4v *.rmvb *.rm *.3gp *.ogv)"));
if (file_name.isEmpty()) {
QMessageBox::warning(this, "警告", "请选择文件再播放");
}
}
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>428</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="playButton">
<property name="text">
<string>Play</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopButton">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="horizontalSlider">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>27</height>
</rect>
</property>
<widget class="QMenu" name="menu">
<property name="title">
<string>文件</string>
</property>
<addaction name="action"/>
</widget>
<addaction name="menu"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="action">
<property name="text">
<string>打开视频文件</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
} urdarling 发表于 2023-4-22 20:17
着岂不是编译一下直接就可以用了
是的,直接编译就可以用了,不过提前要搭建好opencv和Qt环境,将cmaklist文件里的opencv路径改成你自己安装opencv的路径即可 支持原创,感谢分享。 非常感谢您的作品 着岂不是编译一下直接就可以用了 学习一下。 膜拜大佬学习一下 大佬牛逼,视频播放有声音吗 感谢分享,学习了。 做视频行业的,过来学习一下。