海军 发表于 2023-4-22 18:06

基于QT和opencv的视频播放器

CMakeLists.txt
cmake_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();
}

海军 发表于 2023-4-22 20:40

urdarling 发表于 2023-4-22 20:17
着岂不是编译一下直接就可以用了

是的,直接编译就可以用了,不过提前要搭建好opencv和Qt环境,将cmaklist文件里的opencv路径改成你自己安装opencv的路径即可

雾都孤尔 发表于 2023-4-22 18:27

支持原创,感谢分享。

sdieedu 发表于 2023-4-22 20:08

非常感谢您的作品

urdarling 发表于 2023-4-22 20:17

着岂不是编译一下直接就可以用了

52spress 发表于 2023-4-22 20:57

学习一下。

Gxiaojia 发表于 2023-4-22 20:58

膜拜大佬学习一下

lijiyu 发表于 2023-4-22 22:11

大佬牛逼,视频播放有声音吗

wuailaoyan 发表于 2023-4-22 23:02

感谢分享,学习了。

tbloy 发表于 2023-4-23 00:13

做视频行业的,过来学习一下。
页: [1] 2 3
查看完整版本: 基于QT和opencv的视频播放器