C++ QT视频音乐播放器

C++/QT视频音乐播放器

如需安装运行环境或远程调试,可加扣905733049, 或扣2945218359由专业技术人员远程协助!

运行结果如下:

主要代码:

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include 
#include 
#include 
#include 
#include 

#include "AppConfig.h"
#include "Base/FunctionTransfer.h"

#include "Widget/SetVideoUrlDialog.h"
#include "Widget/mymessagebox_withTitle.h"

Q_DECLARE_METATYPE(VideoPlayerState)

MainWindow::MainWindow(QWidget *parent) :
    DragAbleWidget(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this->getContainWidget());

    FunctionTransfer::init(QThread::currentThreadId());

    ///初始化播放器
    VideoPlayer::initPlayer();

    setWindowFlags(Qt::FramelessWindowHint);//|Qt::WindowStaysOnTopHint);  //使窗口的标题栏隐藏
//    setAttribute(Qt::WA_TranslucentBackground);

    //因为VideoPlayer::PlayerState是自定义的类型 要跨线程传递需要先注册一下
    qRegisterMetaType();

    mPopMenu = new QMenu(this);

    mAddVideoAction              = new QAction(QIcon("images/open.png"), QStringLiteral("打开网络流"), this);
    mEditVideoAction             = new QAction(QIcon("images/open.png"), QStringLiteral("修改数据"), this);
    mDeleteVideoAction           = new QAction(QIcon("images/open.png"), QStringLiteral("删除"), this);
    mClearVideoAction            = new QAction(QIcon("images/open.png"), QStringLiteral("清空"), this);

    mPopMenu->addAction(mAddVideoAction);
//    mPopMenu->addAction(mEditVideoAction);
//    mPopMenu->addSeparator();       //添加分离器
    mPopMenu->addAction(mDeleteVideoAction);
    mPopMenu->addAction(mClearVideoAction);

    connect(mAddVideoAction,     &QAction::triggered, this, &MainWindow::slotActionClick);
    connect(mEditVideoAction,    &QAction::triggered, this, &MainWindow::slotActionClick);
    connect(mDeleteVideoAction,  &QAction::triggered, this, &MainWindow::slotActionClick);
    connect(mClearVideoAction,   &QAction::triggered, this, &MainWindow::slotActionClick);

    connect(ui->pushButton_open, &QPushButton::clicked, this, &MainWindow::slotBtnClick);
    connect(ui->toolButton_open, &QPushButton::clicked, this, &MainWindow::slotBtnClick);
    connect(ui->pushButton_clear,&QPushButton::clicked, this, &MainWindow::slotBtnClick);
    connect(ui->pushButton_play, &QPushButton::clicked, this, &MainWindow::slotBtnClick);
    connect(ui->pushButton_volume, &QPushButton::clicked, this, &MainWindow::slotBtnClick);

    connect(ui->horizontalSlider, SIGNAL(sig_valueChanged(int)), this, SLOT(slotSliderMoved(int)));
    connect(ui->horizontalSlider_2, SIGNAL(valueChanged(int)), this, SLOT(slotSliderMoved(int)));

    ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu);

    connect(ui->listWidget, &QListWidget::itemDoubleClicked, this, &MainWindow::slotItemDoubleClicked);
    connect(ui->listWidget, &QListWidget::customContextMenuRequested, this, &MainWindow::slotCustomContextMenuRequested);

    ui->page_video->setMouseTracking(true);
    ui->widget_videoPlayer->setMouseTracking(true);
//    ui->page_video->installEventFilter(this);
    ui->widget_videoPlayer->installEventFilter(this);
    ui->widget_container->installEventFilter(this);

    mCurrentIndex = 0;
    mCurrentItem = nullptr;
    mIsNeedPlayNext = false;

    mPlayer = new VideoPlayer();
    mPlayer->setVideoPlayerCallBack(this);

    mTimer = new QTimer; //定时器-获取当前视频时间
    connect(mTimer, &QTimer::timeout, this, &MainWindow::slotTimerTimeOut);
    mTimer->setInterval(500);

    mTimer_CheckControlWidget = new QTimer; //用于控制控制界面的出现和隐藏
    connect(mTimer_CheckControlWidget, &QTimer::timeout, this, &MainWindow::slotTimerTimeOut);
    mTimer_CheckControlWidget->setInterval(2500);

    mAnimation_ControlWidget  = new QPropertyAnimation(ui->widget_controller, "geometry");

    ui->stackedWidget->setCurrentWidget(ui->page_open);
    ui->pushButton_pause->hide();

    resize(1024,768);
    setTitle(QStringLiteral("我的播放器-V%1").arg(AppConfig::VERSION_NAME));

    mVolume = mPlayer->getVolume();

    std::thread([=]
    {
        while (1)
        {
            AppConfig::mSleep(500);

            static QPoint lastPoint = QPoint(0, 0);

            FunctionTransfer::runInMainThread([=]()
            {
                QPoint point = QCursor::pos();

                if (this->geometry().contains(point))
                {
                    if (lastPoint != point)
                    {

                        mTimer_CheckControlWidget->stop();
                        mTimer_CheckControlWidget->start();

                        lastPoint = point;
                    }
                }
            });
        }

    }).detach();
}

MainWindow::~MainWindow()
{
qDebug()<<__FUNCTION__;

    AppConfig::saveConfigInfoToFile();
    AppConfig::removeDirectory(AppConfig::AppDataPath_Tmp);

    delete ui;
}

void MainWindow::showOutControlWidget()
{

    mAnimation_ControlWidget->setDuration(800);

    int w = ui->widget_controller->width();
    int h = ui->widget_controller->height();
    int y = ui->widget_container->height() - ui->widget_controller->height();

    if (ui->widget_controller->isHidden())
    {
        ui->widget_controller->show();
        mAnimation_ControlWidget->setStartValue(ui->widget_controller->geometry());
    }
    else
    {
        mAnimation_ControlWidget->setStartValue(ui->widget_controller->geometry());
    }

//    mAnimation_ControlWidget->setKeyValueAt(0, QRect(0, 0, 00, 00));
//    mAnimation_ControlWidget->setKeyValueAt(0.4, QRect(20, 250, 20, 30));
//    mAnimation_ControlWidget->setKeyValueAt(0.8, QRect(100, 250, 20, 30));
//    mAnimation_ControlWidget->setKeyValueAt(1, QRect(250, 250, 100, 30));
    mAnimation_ControlWidget->setEndValue(QRect(x, y, w, h));
    mAnimation_ControlWidget->setEasingCurve(QEasingCurve::Linear); //设置动画效果

    mAnimation_ControlWidget->start();

}

void MainWindow::hideControlWidget()
{
    mAnimation_ControlWidget->setTargetObject(ui->widget_controller);

    mAnimation_ControlWidget->setDuration(300);

    int w = ui->widget_controller->width();
    int h = ui->widget_controller->height();
    int x = 0;
    int y = ui->widget_container->height() + h;

    mAnimation_ControlWidget->setStartValue(ui->widget_controller->geometry());
    mAnimation_ControlWidget->setEasingCurve(QEasingCurve::Linear); //设置动画效果

    mAnimation_ControlWidget->start();
}


void MainWindow::setVideoNums(const int &nums)
{
    ui->label_num->setText(QStringLiteral("%1个文件").arg(nums));
}

void MainWindow::addVideoFiles(const QStringList &videoFileList)
{
    if (!videoFileList.isEmpty())
    {
        QString filePath = videoFileList.first();
        AppConfig::gVideoFilePath = QFileInfo(filePath).absoluteDir().path();
        AppConfig::saveConfigInfoToFile();
    }

    for (QString filePath : videoFileList)
    {
        addVideoFile(filePath);
    }
}

void MainWindow::addVideoFile(const QString &filePath)
{
    QFileInfo fileInfo(filePath);

    QListWidgetItem *item = new QListWidgetItem();
    ui->listWidget->addItem(item);

    mVideoFileList.append(filePath);

    setVideoNums(mVideoFileList.size());
}

void MainWindow::clear()
{
    stopPlay();
    ui->listWidget->clear();
    mVideoFileList.clear();

    setVideoNums(mVideoFileList.size());
}

void MainWindow::startPlay()
{
    playVideo(0);
}

void MainWindow::stopPlay()
{
    if (mCurrentItem != nullptr)
    {
        mCurrentItem->setBackgroundColor(QColor(0, 0, 0, 0));
    }

    mCurrentItem = nullptr;

    mIsNeedPlayNext = false;
    mPlayer->stop(true);
}

void MainWindow::playVideo(const int &index)
{
    int playIndex = index;

//    ///播放到最后一个后,从头开始播放
//    {
//        if ((playIndex < 0) || (mVideoFileList.size() <= playIndex))
//        {
//            playIndex = 0;
//        }
//    }

    if (index >= 0 && mVideoFileList.size() > playIndex)
    {
        mCurrentIndex = playIndex;

        QString filePath = mVideoFileList.at(playIndex);

qDebug()<<__FUNCTION__<listWidget->setCurrentRow(playIndex);
        QListWidgetItem *item = ui->listWidget->item(playIndex);

        if (mCurrentItem != nullptr)
        {
            mCurrentItem->setBackgroundColor(QColor(0, 0, 0, 0));
        }

        mCurrentItem = item;

        mCurrentItem->setBackgroundColor(QColor(75, 92, 196));
    }
}

void MainWindow::playVideoFile(const QString &filePath)
{
    mIsNeedPlayNext = false;
    mPlayer->stop(true);
    mPlayer->startPlay(filePath.toStdString());
}

void MainWindow::slotSliderMoved(int value)
{
    if (QObject::sender() == ui->horizontalSlider)
    {
        mPlayer->seek((qint64)value * 1000000);
    }
    else if (QObject::sender() == ui->horizontalSlider_2)
    {
        mPlayer->setVolume(value / 100.0);
        ui->label_volume->setText(QString("%1").arg(value));
    }
}

void MainWindow::slotTimerTimeOut()
{
    if (QObject::sender() == mTimer)
    {
        qint64 Sec = mPlayer->getCurrentTime();

        ui->horizontalSlider->setValue(Sec);

		QString curTime;
		QString sStr = QString("0%1").arg(Sec % 60);
		if (hStr == "00")
		{
			curTime = QString("%1:%2").arg(mStr.right(2)).arg(sStr.right(2));
		}
		else
		{
			curTime = QString("%1:%2:%3").arg(hStr).arg(mStr.right(2)).arg(sStr.right(2));
		}

        ui->label_currenttime->setText(curTime);
    }
    else if (QObject::sender() == mTimer_CheckControlWidget)
    {
        mTimer_CheckControlWidget->stop();
        hideControlWidget();
    }
}


void MainWindow::doAdd()
{
    QStringList fileList = QFileDialog::getOpenFileNames(
               this, QStringLiteral("选择要播放的文件"),
                AppConfig::gVideoFilePath,//初始目录
                QStringLiteral("视频文件 (*.flv *.rmvb *.avi *.MP4 *.mkv);;")
                +QStringLiteral("音频文件 (*.mp3 *.wma *.wav);;")
                +QStringLiteral("所有文件 (*.*)"));

    if (!fileList.isEmpty())
    {
        addVideoFiles(fileList);
    }

    ///第一次添加,则直接播放
    if (mVideoFileList.size() == fileList.size())
    {
        startPlay();
    }
}

void MainWindow::doAddStream()
{
    SetVideoUrlDialog dialog;

//        dialog.setVideoUrl(AppConfig::gVideoFilePath);

    if (dialog.exec() == QDialog::Accepted)
    {
        QString s = dialog.getVideoUrl();

        if (!s.isEmpty())
        {
            mIsNeedPlayNext = false;
            mPlayer->stop(true); //如果在播放则先停止
            mPlayer->startPlay(s.toStdString());

            AppConfig::gVideoFilePath = s;
            AppConfig::saveConfigInfoToFile();
        }
    }
}

void MainWindow::doDelete()
{
    QList RowList;

    QList selectedItemList = ui->listWidget->selectedItems();

    for (QListWidgetItem* item : selectedItemList)
    {
        int rowValue = ui->listWidget->row(item);

        int index = RowList.size();
        for (int i=0;i value)
            {
                index = i;
                break;
            }
        }

        RowList.insert(index, rowValue);
    }
qDebug()<<__FUNCTION__<listWidget->takeItem(row);

            if (mCurrentItem == item)
            {
                mCurrentItem = nullptr;
            }

            delete item;

            if (row <= mCurrentIndex)
            {
                mCurrentIndex --;
            }
        }
    }

    setVideoNums(mVideoFileList.size());
}

void MainWindow::doClear()
{
    int ret = MyMessageBox_WithTitle::showWarningText(QStringLiteral("警告"),
                                                       QStringLiteral("确定要清空所有数据么?"),
                                                       QStringLiteral("确定"),
                                                       QStringLiteral("取消"));

    if (ret == QDialog::Accepted)
    {
        clear();
    }
}

void MainWindow::slotBtnClick(bool isChecked)
{
    if (QObject::sender() == ui->pushButton_play)
    {
        mPlayer->play();
    }
    else if (QObject::sender() == ui->pushButton_pause)
    {
        mPlayer->pause();
    }
    else if (QObject::sender() == ui->pushButton_stop)
    {
        mIsNeedPlayNext = false;
        mPlayer->stop(true);
    }
    else if (QObject::sender() == ui->pushButton_open)
    {
        doAdd();
    }
    else if (QObject::sender() == ui->pushButton_clear)
    {
        doClear();
    }
    else if (QObject::sender() == ui->toolButton_open)
    {
        doAddStream();
    }
    else if (QObject::sender() == ui->pushButton_volume)
    {
       qDebug()<setMute(isMute);

        if (isMute)
        {
            mVolume = mPlayer->getVolume();

            ui->horizontalSlider_2->setValue(0);
            ui->horizontalSlider_2->setEnabled(false);
            ui->label_volume->setText(QString("%1").arg(0));
        }
        else
        {
            int volume = mVolume * 100.0;
            ui->horizontalSlider_2->setValue(volume);
            ui->horizontalSlider_2->setEnabled(true);
            ui->label_volume->setText(QString("%1").arg(volume));
        }

    }

}


void MainWindow::slotItemDoubleClicked(QListWidgetItem *item)
{
    if (QObject::sender() == ui->listWidget)
    {
        int index = ui->listWidget->row(item);
        playVideo(index);
    }
}

void MainWindow::slotCustomContextMenuRequested()
{
//    QPoint point(ui->listWidget->mapFromGlobal(QCursor::pos()));//获取控件的全局坐标

//    int h = ui->tableWidget->horizontalHeader()->height();

//    point.setY(point.y() - h);

//    QTableWidgetItem *item = ui->tableWidget->itemAt(point);

//    if (item == NULL || !item->isSelected())
//    {
//        ui->tableWidget->clearSelection();

//        mAddUserAction->setEnabled(true);
//        mEditUserAction->setEnabled(false);
//        mDeleteUserAction->setEnabled(false);
//        mExportAction->setEnabled(false);
//        mUploadAction_Selected->setEnabled(false);
//    }
//    else
//    {
//        mAddUserAction->setEnabled(false);
//        mEditUserAction->setEnabled(true);
//        mDeleteUserAction->setEnabled(true);
//        mExportAction->setEnabled(true);
//        mUploadAction_Selected->setEnabled(true);
//    }

    mPopMenu->exec(QCursor::pos());
}

void MainWindow::slotActionClick()
{
    if (QObject::sender() == mAddVideoAction)
    {
        doAddStream();
    }
    else if (QObject::sender() == mEditVideoAction)
    {

    }
    else if (QObject::sender() == mDeleteVideoAction)
    {
        doDelete();
    }
    else if (QObject::sender() == mClearVideoAction)
    {
        doClear();
    }
}

///打开文件失败
void MainWindow::onOpenVideoFileFailed(const int &code)
{
    FunctionTransfer::runInMainThread([=]()
    {
        QMessageBox::critical(NULL, "tips", QString("open file failed %1").arg(code));
    });
}

///打开SDL失败的时候回调此函数
void MainWindow::onOpenSdlFailed(const int &code)
{
    FunctionTransfer::runInMainThread([=]()
    {
        QMessageBox::critical(NULL, "tips", QString("open Sdl failed %1").arg(code));
    });
}

///获取到视频时长的时候调用此函数
void MainWindow::onTotalTimeChanged(const int64_t &uSec)
{
    FunctionTransfer::runInMainThread([=]()
    {
        qint64 Sec = uSec/1000000;

        ui->horizontalSlider->setRange(0,Sec);

		QString totalTime;
		QString mStr = QString("0%1").arg(Sec / 60 % 60);
		QString sStr = QString("0%1").arg(Sec % 60);
		if (hStr == "00")
		{
			totalTime = QString("%1:%2").arg(mStr.right(2)).arg(sStr.right(2));
		}
		else
		{
			totalTime = QString("%1:%2:%3").arg(hStr).arg(mStr.right(2)).arg(sStr.right(2));
		}

        ui->label_totaltime->setText(totalTime);
    });
}

///播放器状态改变的时候回调此函数
void MainWindow::onPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio)
{
    FunctionTransfer::runInMainThread([=]()
    {
qDebug()<<__FUNCTION__<stackedWidget->setCurrentWidget(ui->page_open);

            ui->pushButton_pause->hide();
            ui->widget_videoPlayer->clear();

            ui->horizontalSlider->setValue(0);
            ui->label_currenttime->setText("00:00");
            ui->label_totaltime->setText("00:00");

            mTimer->stop();

            if (mIsNeedPlayNext)
            {
                mCurrentIndex++;
                playVideo(mCurrentIndex);
            }

            mIsNeedPlayNext = true;
        }
        else if (state == VideoPlayer_Playing)
        {
            if (hasVideo)
            {
                ui->stackedWidget->setCurrentWidget(ui->page_video);
            }
            else
            {
                ui->stackedWidget->setCurrentWidget(ui->page_audio);
            }

            ui->pushButton_play->hide();
            ui->pushButton_pause->show();

            mTimer->start();

            mIsNeedPlayNext = true;
        }
        else if (state == VideoPlayer_Pause)
        {
            ui->pushButton_pause->hide();
            ui->pushButton_play->show();
        }
    });
}

///显示视频数据,此函数不宜做耗时操作,否则会影响播放的流畅性。
void MainWindow::onDisplayVideo(std::shared_ptr videoFrame)
{
    ui->widget_videoPlayer->inputOneFrame(videoFrame);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    mPlayer->stop(true);
}

//图片显示部件时间过滤器处理
bool MainWindow::eventFilter(QObject *target, QEvent *event)
{
    if(target == ui->widget_container)
    {
        if(event->type() == QEvent::Resize)
        {
            int x = 0;
            int y = h - ui->widget_controller->height();
            ui->widget_controller->move(x, y);
            ui->widget_controller->resize(w, ui->widget_controller->height());
        }
    }
    else if(target == ui->page_video || target == ui->widget_videoPlayer)
    {
        if(event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress)
        {
            if (!mTimer_CheckControlWidget->isActive())
            {
                showOutControlWidget();
            }

            mTimer_CheckControlWidget->stop();
            mTimer_CheckControlWidget->start();
        }
        else if(event->type() == QEvent::Enter)
        {
            showOutControlWidget();
        }
        else if(event->type() == QEvent::Leave)
        {
            mTimer_CheckControlWidget->stop();
            mTimer_CheckControlWidget->start();
        }
    }

    //其它部件产生的事件则交给基类处理
    return DragAbleWidget::eventFilter(target, event);
}

 运行结果如下

 网址参考:C++/QT视频音乐播放器

你可能感兴趣的:(C++,qt,音视频,c++)