QT根据QTAv实现播放器

1 篇文章 0 订阅
1 篇文章 0 订阅

         最近心血来潮突然想自己实现一个播放器的功能,说来过程还有丢丢曲折的,一开始是用

QtMultimedia 来实现的,结果发现需要安装解码器,所以又跑去安装了 K-Lite。然后功能都可以使用了,自己就屁颠屁颠的打包成exe放到另一台没有安装解码器的电脑上去运行,结果不能播放视频- -。最后一通搜索,决定使用QTAv来实现。

        该实现最大的好处就是打包后可以放到另一台不用搭环境的win上正常运行~

先上贴图:

 

大致功能点说明:

        1: 可打开单个文件,多个文件,和遍历文件夹

        2:实现视频文件拖拽到窗口播放,文件拖拽到exe上,直接打开exe和播放文件

        3:记录播放历史,上一次设置的音量

        4:进程最小化,进程最大化,全屏

        5:点击画面可暂停/继续播放

        6:音量slider浮动显示,倍速上拉选

        7: 快进,上一集,暂停/继续播放,下一集,快退,倍速,音量,截图

        8:历史记录可删,双击历史记录播放

        9:视频进度条点击,拖拽跳转

上主程序代码(备注还是挺详细的,毕竟QT我也不熟)~

全部源码下载:

资源下载

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget){
    ui->setupUi(this);
    Widgets::registerRenderers();

    showList = false;
    timer = new QTimer(this);

    setObjectName("myWiget");
    setWindowTitle("播放器");
    setWindowIcon(QIcon(":/resources/myLogo.ico"));
    setStyleSheet("#myWiget{border-image:url(:/resources/backImg.png);}");
    setContentsMargins(0,0,0,0);

    resize(1280,720);

    //实例化布局
    this->vbox = new QVBoxLayout(this);// 上下排列布局
    vbox->setContentsMargins(0,0,0,0);

    // **********************************************************************************初始化管理栏***************
    this->hboxTop = new QHBoxLayout(this);
    hboxTop->setContentsMargins(0,0,0,0);
    bar = new QMenuBar();
    bar->setStyleSheet("margin: 2px 0;width:50px;background-color:rgba(0,0,0,0);color:white;");//透明背景色
    bar->setAutoFillBackground(false);
    bar->setMinimumWidth(70);
    bar->setMaximumWidth(70);

    // 一级菜单
    file = bar->addMenu("文件");
//    file->setStyleSheet("background-color:none;");//background-color:green;
    file->setMinimumWidth(150);
    file->setAutoFillBackground(false);
    QList<QAction*> list;
    QAction *action1=new QAction("打开文件");//QAction(QIcon(":/resource/image/向右箭头.jpg"),"action1");  可显示图标
    QAction *action2=new QAction("多个文件");
    QAction *action3=new QAction("打开文件夹");
    QAction *action4=new QAction("退出");
    list.append(action1);
    list.append(action2);
    list.append(action3);
    list.append(action4);
    file->addActions(list);
//    file->addMenu("打开文件");// 下级菜单
    hboxTop->addWidget(bar);

    fileVal = new QLabel();
    fileVal->setStyleSheet("color:white;");
    fileVal->setText("播放的文件名..........");
    fileVal->setAlignment(Qt::AlignCenter);// 文字 居中
    hboxTop->addWidget(fileVal);

    hideButton = new QPushButton();
    QPixmap pi = QPixmap(":/resources/hide.png");
    hideButton->setStyleSheet("background-color:rgba(0,0,0,0);");
    QIcon btnBack = QIcon(pi);
    hideButton->setIcon(btnBack);
    QSize s = QSize(50,25);
    hideButton->setIconSize(s);
    hideButton->setMaximumWidth(50);
    hboxTop->addWidget(hideButton);

    maxButton = new QPushButton();
    maxButton->setStyleSheet("background-color:rgba(0,0,0,0);");
    QPixmap maxpi = QPixmap(":/resources/maxPro.png");
    QIcon maxbtnBack = QIcon(maxpi);
    maxButton->setIcon(maxbtnBack);
    QSize s2 = QSize(50,25);
    maxButton->setIconSize(s2);
    maxButton->setMaximumWidth(50);
    maxButton->setMinimumWidth(50);
    hboxTop->addWidget(maxButton);

    closeButton = new QPushButton();
//    closeButton->setStyleSheet("background-color:rgba(0,0,0,0);");
    QPixmap closepi = QPixmap(":/resources/closePro.png");
    QIcon closebtnBack = QIcon(closepi);
    closeButton->setIcon(closebtnBack);
    QSize s3 = QSize(50,25);
    closeButton->setIconSize(s3);
    closeButton->setMaximumWidth(50);
    closeButton->setMinimumWidth(50);
    hboxTop->addWidget(closeButton);


    // **********************************************************************************初始化播放栏***************
    QWidget* video = new QWidget(this);// 使用wiget来实现大小自适应,QHBoxLayout只能被动的被子组件撑起来
    video->setContentsMargins(0,0,0,0);
    this->hboxVideo = new QHBoxLayout(this);
    hboxVideo->setContentsMargins(0,0,0,0);
    //实例化媒体播放器及视频播放
    mOut = new VideoOutput(this);;
    mPlayer = new AVPlayer(this);
    mPlayer->setRenderer(mOut);
    // 默认实时流 连接方式是UDP模式,可能出现丢包,卡顿等,改为tcp模式
    QHash<QString, QVariant> dict;
    dict.insert("rtsp_transport", "tcp");
    mPlayer->setOptionsForFormat(dict);
    // 开启解码加速
    mPlayer->setVideoDecoderPriority(QStringList() << "CUDA" << "D3D11" << "DXVA" << "FFmpeg");//"VAAPI"

    // 新增一个大小随显示屏走的button,且设置为透明的
    QVBoxLayout* gbox = new QVBoxLayout(mOut->widget());
    b2 = new QPushButton(this);

    QPixmap statpi2 = QPixmap(":/resources/stat2.png");
    QIcon statbtnBack2 = QIcon(statpi2);
    b2->setIcon(statbtnBack2);
    b2->setIconSize(QSize(0,0));

    b2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    b2->setStyleSheet("background-color:rgba(0,0,0,0);");
    gbox->addWidget(b2);
    mOut->widget()->setLayout(gbox);
    hboxVideo->addWidget(mOut->widget());

//    hboxVideo->setStretchFactor(videoWidget,1);// 设置该控件为可伸缩,其他控件自动设置为不可伸缩

    showListButton = new QPushButton(this);
    showListButton->setMaximumWidth(20);
    // 设置宽度固定,高度随父组件大小
    showListButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
    showListButton->setStyleSheet("border-image:url(:/resources/showList.png);");

    hboxVideo->addWidget(showListButton);

    // 历史列表
    listWidget = new QListWidget(this);
//    listWidget->setStyleSheet("background-color:white;color:black;");
    listWidget->setMaximumWidth(270);
    listWidget->setMinimumWidth(270);
    hboxVideo->addWidget(listWidget);

    video->setLayout(hboxVideo);
    // **********************************************************************************初始化视频时间显示栏***************
    this->hboxVideoTime = new QHBoxLayout(this);
    hboxVideoTime->setContentsMargins(0,0,0,0);
    timeLable = new QLabel("00:00:00/00:00:00",this);
    timeLable->setStyleSheet("color:white;");//margin-bottom:3px;
    hboxVideoTime->addWidget(timeLable);

    // **********************************************************************************初始化视频进度条显示栏***************
    this->hboxVideoIndex = new QHBoxLayout(this);
    hboxVideoIndex->setContentsMargins(0,0,0,0);
    timeSlider = new QSlider(this);
    timeSlider->setContentsMargins(0,0,0,0);
    // groove表示槽的部分,handle表示滑块,add-page表示未滑过的槽部分,sub-page 表示已滑过的槽部分
    // 横向展示
    timeSlider->setOrientation(Qt::Horizontal);// Vertical
    QString timeSliderStr = "";//"margin:3px;background-color:white;";
    // 主体样式(样式中注意 horizontal 和 vertical)
    timeSliderStr += "QSlider{border-color: #bcbcbc;}QSlider::groove:horizontal {border: 1px solid #999999;height: 6px;"
                     "left: 5px; right: 5px;}";// 左右留出一定位置,这样进度键才能显示全
    // 滑块样式
    timeSliderStr.append("QSlider::handle:horizontal {border: 0px;border-image: url(:/resources/rate.png);"
            "width: 13px;margin: 0px -7px 0px -7px;}");
    // 已划过槽的样式
    timeSliderStr.append("QSlider::sub-page:horizontal {background-color:#87CEEB;height: 8px;}");//padding: 2px 0;
    timeSlider->setStyleSheet(timeSliderStr);
    timeSlider->installEventFilter(this);// 重载eventFilter事件
    hboxVideoIndex->addWidget(timeSlider);

    // **********************************************************************************初始化视频操作显示栏***************
    this->hboxVideoWork = new QHBoxLayout(this);
    hboxVideoWork->setContentsMargins(0,0,0,0);
    // 布局:间隔/组件1/间隔/组件2
    hboxVideoWork->addStretch();

    btnLeft = new QLabel("    ");
    btnLeft->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    hboxVideoWork->addWidget(btnLeft);
    hboxVideoWork->addStretch();

    backButton = new QPushButton();
    backButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap backpi = QPixmap(":/resources/back.png");
    QIcon backbtnBack = QIcon(backpi);
    backButton->setIcon(backbtnBack);
    QSize s4 = QSize(85,38);
    backButton->setIconSize(s4);
    backButton->setMaximumWidth(90);
    backButton->setMinimumWidth(90);
    backButton->setMinimumHeight(50);
    backButton->setMaximumHeight(50);
    hboxVideoWork->addWidget(backButton);

    lastButton = new QPushButton();
    lastButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap lastpi = QPixmap(":/resources/last.png");
    QIcon lastbtnBack = QIcon(lastpi);
    lastButton->setIcon(lastbtnBack);
    QSize s5 = QSize(85,38);
    lastButton->setIconSize(s5);
    lastButton->setMaximumWidth(90);
    lastButton->setMinimumWidth(90);
    lastButton->setMinimumHeight(50);
    lastButton->setMaximumHeight(50);
    hboxVideoWork->addWidget(lastButton);

    statButton = new QPushButton();
    statButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap statpi = QPixmap(":/resources/stat.png");
    statbtnBack = QIcon(statpi);
    QPixmap stoppi = QPixmap(":/resources/stop.png");
    stopbtnBack = QIcon(stoppi);
    statButton->setIcon(stopbtnBack);
    QSize s6 = QSize(110,45);
    statButton->setIconSize(s6);
    statButton->setMaximumWidth(90);
    statButton->setMinimumWidth(90);
    statButton->setMinimumHeight(60);
    statButton->setMaximumHeight(60);
    hboxVideoWork->addWidget(statButton);

    nextButton = new QPushButton();
    nextButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap nextpi = QPixmap(":/resources/next.png");
    QIcon nextbtnBack = QIcon(nextpi);
    nextButton->setIcon(nextbtnBack);
    QSize s7 = QSize(85,38);
    nextButton->setIconSize(s7);
    nextButton->setMaximumWidth(90);
    nextButton->setMinimumWidth(90);
    nextButton->setMinimumHeight(50);
    nextButton->setMaximumHeight(50);
    hboxVideoWork->addWidget(nextButton);

    upButton = new QPushButton();
    upButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap uppi = QPixmap(":/resources/up.png");
    QIcon upbtnBack = QIcon(uppi);
    upButton->setIcon(upbtnBack);
    upButton->setIconSize(QSize(85,38));
    upButton->setMaximumWidth(90);
    upButton->setMinimumWidth(90);
    upButton->setMinimumHeight(50);
    upButton->setMaximumHeight(50);
    hboxVideoWork->addWidget(upButton);

    hboxVideoWork->addStretch();

    // 倍速按钮
    boxBtn = new myBoxButton(this);
    boxBtn->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);color:white;");
    QStringList l;
    l<<"2.0x"<<"1.5x"<<"1.3x"<<"1.0x"<<"0.8x"<<"0.5x"<<"0.3x";
    boxBtn->addtextItems(l);
    boxBtn->setText("1.0x");
    hboxVideoWork->addWidget(boxBtn);


    // 音量按钮
    soundButton = new QPushButton();
    soundButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap soundpi = QPixmap(":/resources/sound.png");
    soundbtnBack = QIcon(soundpi);
    QPixmap unsoundpi = QPixmap(":/resources/unsound.png");
    unsoundbtnBack = QIcon(unsoundpi);
    soundButton->setIcon(soundbtnBack);
    soundButton->setIconSize(QSize(45,45));
    soundButton->setMaximumWidth(50);
    soundButton->setMinimumWidth(50);
    soundButton->setMinimumHeight(50);
    soundButton->setMaximumHeight(50);
    soundButton->installEventFilter(this);
    hboxVideoWork->addWidget(soundButton);

    volumeSlider = new myFloatSlider(this);
    // groove表示槽的部分,handle表示滑块,add-page表示未滑过的槽部分,sub-page 表示已滑过的槽部分
    // 纵向展示
    volumeSlider->setOrientation(Qt::Vertical);
//    volumeSlider->setInvertedAppearance(true);// 反向
    volumeSlider->installEventFilter(this);// 重载eventFilter事件

    volumeSlider->setRange(0,100);
    volumeSlider->setValue(100);
    volumeSlider->hide();

    // 最大化按钮
    tomaxButton = new QPushButton();
    tomaxButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap toMaxpi = QPixmap(":/resources/max.png");
    QIcon toMaxbtnBack = QIcon(toMaxpi);
    tomaxButton->setIcon(toMaxbtnBack);
    tomaxButton->setIconSize(QSize(70,40));
    tomaxButton->setMaximumWidth(60);
    tomaxButton->setMinimumWidth(60);
    tomaxButton->setMinimumHeight(50);
    tomaxButton->setMaximumHeight(50);
    hboxVideoWork->addWidget(tomaxButton);

    // 截图按钮
    cutButton = new QPushButton();
    cutButton->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    QPixmap cutpi = QPixmap(":/resources/cut.png");
    QIcon cutbtnBack = QIcon(cutpi);
    cutButton->setIcon(cutbtnBack);
    cutButton->setIconSize(QSize(70,40));
    cutButton->setMaximumWidth(60);
    cutButton->setMinimumWidth(60);
    cutButton->setMinimumHeight(50);
    cutButton->setMaximumHeight(50);
    hboxVideoWork->addWidget(cutButton);

    // 添加一个label,使得btn不贴边
    btnRight = new QLabel("    ");
    btnRight->setStyleSheet("margin:0 0 5px 0;background-color:rgba(0,0,0,0);");
    hboxVideoWork->addWidget(btnRight);
//    hboxVideoWork->setAlignment(Qt::AlignCenter);// 所有组件居中,没有设置间隔的时候,如果要组件居中,可以用这个方式

    // 从上到下把横向容器放到竖向容器中
    vbox->addLayout(hboxTop);
    vbox->addWidget(video);
    vbox->addLayout(hboxVideoTime);
    vbox->addLayout(hboxVideoIndex);
    vbox->addLayout(hboxVideoWork);
    vbox->setStretchFactor(video,1);

    // 设置窗口的容器为竖向容器
    setLayout(this->vbox);

    connect(showListButton,SIGNAL(clicked()),this,SLOT(showListFc())); //绑定历史列表显隐事件
    connect(this->listWidget,SIGNAL(itemDoubleClicked(QListWidgetItem*)),this,SLOT(doubleClickPlay(QListWidgetItem*)));//历史列表双击事件
    connect(this->timer,SIGNAL(timeout()),this,SLOT(updateTime())); //显示已播放时间/总时间
    connect(this->mPlayer,SIGNAL(durationChanged(qint64)),this,SLOT(setTimeSlider(qint64)));// 总时长变化
    connect(b2,SIGNAL(clicked()),this,SLOT(playerClick()));// 屏幕点击
    connect(timeSlider,SIGNAL(valueChanged(int)),this,SLOT(timeChanged(int)));
    connect(volumeSlider,SIGNAL(valueChanged(int)),this,SLOT(volumeChanged(int)));
    connect(backButton,SIGNAL(clicked()),this,SLOT(backFc())); //回退事件
    connect(lastButton,SIGNAL(clicked()),this,SLOT(lastFc())); //上一个视频事件
    connect(statButton,SIGNAL(clicked()),this,SLOT(statFc())); //暂停/继续事件
    connect(nextButton,SIGNAL(clicked()),this,SLOT(nextFc())); //下一个视频事件
    connect(upButton,SIGNAL(clicked()),this,SLOT(upFc())); //快进事件
    connect(action1,SIGNAL(triggered()),this,SLOT(openFile())); //打开单个文件事件
    connect(action2,SIGNAL(triggered()),this,SLOT(openFiles())); //打开多个文件事件
    connect(action3,SIGNAL(triggered()),this,SLOT(openDir())); //打开文件夹事件
    connect(action4,SIGNAL(triggered()),this,SLOT(closePro())); //退出进程事件
    connect(soundButton,SIGNAL(clicked()),this,SLOT(openOrCloseVolume())); //开启或关闭音量
    connect(tomaxButton,SIGNAL(clicked()),this,SLOT(tomax())); //开启或关闭音量
    connect(hideButton,SIGNAL(clicked()),this,SLOT(hidePro())); //最小化按钮
    connect(maxButton,SIGNAL(clicked()),this,SLOT(maxPro())); //程序最大化按钮
    connect(closeButton,SIGNAL(clicked()),this,SLOT(closePro())); //退出进程按钮
    connect(cutButton,SIGNAL(clicked()),this,SLOT(cutPro())); // 截屏按钮
    connect(mPlayer->videoCapture(), SIGNAL(imageCaptured(QImage)), SLOT(saveImage(QImage)));//视频图片抓取成功信号
    connect(boxBtn,SIGNAL(currentTextChanged(QString)),this,SLOT(selectSpeed(QString)));// 倍速切换事件


    // 初始化历史列表
    showListFc();
    // 支持悬浮
    setAttribute(Qt::WA_Hover);
    // 支持键盘事件
    setFocusPolicy(Qt::StrongFocus);

    // 每0.5s更新一次时间进度
    timer->start(700);
    // 接收文件放下事件
    setAcceptDrops(true);

    // 初始化和加载文件地址
    data = new QFile(QApplication::applicationDirPath() + "/data");
    if(data->open(QIODevice::ReadWrite|QIODevice::Text)){
        QTextCodec *codec = QTextCodec::codecForName("GBK");
        QByteArray datas = data->readAll();
        oldStr = codec->toUnicode(datas);//QString(datas);
        QJsonParseError jsonError;
        QJsonDocument jspnDoc = QJsonDocument::fromJson(oldStr.toStdString().c_str(),&jsonError);
        if (jspnDoc.isEmpty() || (jsonError.error != QJsonParseError::NoError)) {
            qDebug()<<"文件内容json反转失败!清空文件数据.....";
            nowVolume = 100;
            data->close();
        }else{
            QJsonObject jsonObj = jspnDoc.object();
            li = jsonObj.value("list").toArray();
            nowVolume = jsonObj.value("volume").toInt();
            volumeSlider->setValue(nowVolume);
            mPlayer->audio()->setVolume(nowVolume/100.0);
            for(int i=0;i<li.size();i++){
                QJsonObject fileInfo = li.at(i).toObject();
                QString url = fileInfo.value("url").toString();
                int nameIndex = url.lastIndexOf("/");
                if(nameIndex == -1){
                    nameIndex = url.lastIndexOf("\\");
                }
                QString name = url.mid(nameIndex+1);
                QListWidgetItem *item = new QListWidgetItem(name,listWidget);
                item->setData(Qt::ToolTipRole,url);
                item->setText(name);
//                listWidget->addItem(item);

                QWidget *w = new QWidget(listWidget);
                QHBoxLayout *layout=new QHBoxLayout(w);
                layout->setAlignment(Qt::AlignRight);
                QPushButton *pushButton=new QPushButton("x",w);
                pushButton->setMaximumWidth(20);
                pushButton->setMinimumWidth(20);
                pushButton->setMinimumHeight(20);
                pushButton->setMaximumHeight(20);
                layout->addStretch();
                layout->addWidget(pushButton);
                item->setSizeHint(QSize(20,35));
                w->show();
                w->setLayout(layout);
                listWidget->setItemWidget(item,w);
                widgetItemMap[pushButton] = item;
                connect(pushButton,SIGNAL(clicked()),this,SLOT(delItem())); //删除项
            }
            data->close();
        }
    }else{
        qDebug()<<"创建文件失败!!";
    }
}

Widget::~Widget(){
    saveData();
    timer->stop();
//    mPlayer->stop();
//    delete mPlayer;
    delete ui;
}
void Widget::dropEvent(QDropEvent *e){
    int first = true;
    foreach (const QUrl &url, e->mimeData()->urls()){
        //加载视频文件
        QString urlStr = url.url();
        if(first){
            first = false;
            mPlayer->play(urlStr);
        }
        if(urlStr.endsWith(".mkv") || urlStr.endsWith(".mp4")
                || urlStr.endsWith(".mp3") || urlStr.endsWith(".avi")){
            if(oldStr.contains(urlStr)){
                continue;
            }
            oldStr.append(";"+urlStr);
            int nameIndex = urlStr.lastIndexOf("/");
            QString name = urlStr.mid(nameIndex+1);
            QListWidgetItem *item = new QListWidgetItem(name,this->listWidget);
            item->setData(Qt::ToolTipRole,urlStr);
            item->setText(name);
            fileVal->setText(name);

            QWidget *w = new QWidget(listWidget);
            QHBoxLayout *layout=new QHBoxLayout(w);
            layout->setAlignment(Qt::AlignRight);
            QPushButton *pushButton=new QPushButton("x",w);
            pushButton->setMaximumWidth(20);
            pushButton->setMinimumWidth(20);
            pushButton->setMinimumHeight(20);
            pushButton->setMaximumHeight(20);
            layout->addStretch();
            layout->addWidget(pushButton);
            item->setSizeHint(QSize(20,35));
            w->show();
            w->setLayout(layout);
            listWidget->setItemWidget(item,w);
            widgetItemMap[pushButton] = item;
            connect(pushButton,SIGNAL(clicked()),this,SLOT(delItem())); //删除项
            QJsonObject fileInfoObj;
            fileInfoObj.insert("url",urlStr);
            li.append(fileInfoObj);
        }
    }
}
void Widget::dragEnterEvent(QDragEnterEvent *e){
    if (e->mimeData()->hasUrls()){
        e->acceptProposedAction();
    }
}

void Widget::delItem(){
    QObject* widget = sender();
    if(widget->inherits("QPushButton")){// 判断类型
        QPushButton* btn = static_cast<QPushButton*>(widget);
        QObject* p = btn->parent();
        QListWidgetItem* item = widgetItemMap[btn];

        oldStr.replace(item->toolTip(),"");
        for(int i=0;i<li.size();i++){
            QJsonValue v = li[i];
            if(v.toObject().value("url") == item->toolTip()){
                li.removeAt(i);
                break;
            }
        }
        QJsonObject dataJson;
        dataJson.insert("list",li);
        if(data->open(QIODevice::ReadWrite|QIODevice::Text | QIODevice::Truncate)){
            QJsonDocument doc(dataJson);
            QString strRet = QString(doc.toJson(QJsonDocument::Indented));
            QTextStream ins(data);
            ins<<strRet<<endl;
            data->close();
        }
        delete btn;
        delete item;
        widgetItemMap.remove(btn);
    }else{
        qDebug()<<":is not QPushButton=";
    }
}

void Widget::showListFc(){
    if(!showList){
        showList = true;
        listWidget->show();
        showListButton->setStyleSheet("border-image:url(:/resources/hideList.png);");
    }else{
        showList = false;
        listWidget->hide();
        showListButton->setStyleSheet("border-image:url(:/resources/showList.png);");
    }
}

void Widget::doubleClickPlay(QListWidgetItem *item){
    /*
     * 1、获取listWidget中下标位置
     * 2、设置媒体源、播放选中的歌曲
     * 3、修改名字
     * 4、修改图标
     * 5、定时器启动
    */
    int inde = this->listWidget->currentRow(); //获取当前下标
    QString url = item->data(Qt::ToolTipRole).toString();
    fileVal->setText(item->text());
    mPlayer->play(url);
}

void Widget::updateTime(){
    if(mPlayer->state() == AVPlayer::State::PlayingState || mPlayer->state() == AVPlayer::State::PausedState){
        // 播放或暂停状态
        //获取总时间跟当前播放时长
        qint64 dur = this->mPlayer->duration();
        qint64 pos = this->mPlayer->position();
        //实例化两个对象,用来显示
        QTime durTime(0,0,0);
        QTime posTime(0,0,0);
        this->timeLable->setText(posTime.addMSecs(int(pos)).toString("HH:mm:ss") + "/" + durTime.addMSecs(int(dur)).toString("HH:mm:ss"));
        timeSlider->setValue(pos);
    }
}

void Widget::setTimeSlider(qint64 duration){
    this->timeSlider->setRange(0,int(duration));
}
void Widget::videoPosChange(qint64 duration){
    timeSlider->setValue(duration);
    mPlayer->setPosition(duration);
}
void Widget::timeChanged(int value){
}
void Widget::volumeChanged(int value){
    volumeSlider->setValue(value);
    if(mPlayer->state() == AVPlayer::State::PlayingState || mPlayer->state() == AVPlayer::State::PausedState){
        // 范围:0-1
        mPlayer->audio()->setVolume(value/100.0);
    }
    nowVolume = value;
}

bool Widget::eventFilter(QObject *obj, QEvent *e){
    if (e->type() == QEvent::MouseButtonPress && obj == this->timeSlider){
        timeSliderClick(obj, e);
        // 这里不能返回true,不然按住滑块的拖动事件就终止了
//        return true;
    }else if(e->type() == QEvent::MouseButtonPress && obj == this->volumeSlider){
        volumeSliderClick(obj, e);
    }else if(e->type() == QEvent::HoverEnter && obj == this->soundButton){
        QPushButton* soundBtn = static_cast<QPushButton*>(obj);
        int x = soundBtn->x();
        int y = soundBtn->y();
//        if(volumeSlider->isHidden()){
        volumeSlider->show();
        volumeSlider->move(x,y-250);
        volumeSlider->resize(40,270);
//        }
        inVolumeSlider = false;
        return false;
    }else if(e->type() == QEvent::HoverLeave && obj == this->soundButton){
        // 异步
        QtConcurrent::run([=](){
            QThread::sleep(1);
            // 一秒后确认是否已进入音量滑动条,没有的话则隐藏音量滑动条
            if(!inVolumeSlider){
                volumeSlider->hide();
            }
        });
    }else if(e->type() == QEvent::HoverEnter && obj == this->volumeSlider){
        inVolumeSlider = true;
        volumeSlider->show();
    }else if(e->type() == QEvent::HoverLeave && obj == this->volumeSlider){
        inVolumeSlider = false;
        volumeSlider->hide();
    }

    return QWidget::eventFilter(obj, e);//返回默认的事件过滤器
}
void Widget::paintEvent(QPaintEvent* event){
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void Widget::volumeSliderClick(QObject *slider, QEvent *event){
    QSlider* sliderCtrl = static_cast<QSlider*>(slider);
    QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
    if (Qt::LeftButton == mouseEvent->button()){
        int mxpos = 0;  // 鼠标按下的位置
        int cxwnd = 0;// 滑槽长度
        int cxctl = 0;// 滑块宽度
        // 竖向进度条
        cxctl = sliderCtrl->minimumSizeHint().height();  // 滑块宽度
        cxwnd = sliderCtrl->height();
        if (sliderCtrl->invertedAppearance()){
            mxpos = mouseEvent->y();
        }else{
            mxpos = cxwnd - mouseEvent->y();
        }
        // 计算结果,并设置新计算得到的 position 值
        int scpos = sliderCtrl->minimum() +
                            (int)((sliderCtrl->maximum() - sliderCtrl->minimum()) *
                                  ((mxpos - cxctl / 2.0) / (cxwnd - cxctl)));
        if(sliderCtrl->sliderPosition() != scpos){
            sliderCtrl->setSliderPosition(scpos);
            mPlayer->audio()->setVolume(scpos/100.0);
        }
        if(sliderCtrl->value() <= 0){
            soundButton->setIcon(unsoundbtnBack);
        }else{
            soundButton->setIcon(soundbtnBack);
        }
    }
}
void Widget::timeSliderClick(QObject *slider, QEvent *event){
    QSlider* sliderCtrl = static_cast<QSlider*>(slider);
    QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
    // mouseEvent的x(),y() 可得知鼠标事件指针相对当前窗口的位置; (globalX()、globalY() 返回的是全局坐标)
    if (Qt::LeftButton == mouseEvent->button()){
        int mxpos = 0;  // 鼠标按下的位置
        int cxwnd = 0;// 滑槽长度
        int cxctl = 0;// 滑块宽度
        if (Qt::Horizontal == sliderCtrl->orientation()){
            // 横向进度条
            cxwnd = sliderCtrl->width();
            if (sliderCtrl->invertedAppearance()){
                // 判断进度条是否反转类型(即最大最小值相反)
                mxpos = cxwnd - mouseEvent->x();
            }else{
                mxpos = mouseEvent->x();
            }
        }else{
            // 竖向进度条
            cxctl = sliderCtrl->minimumSizeHint().height();  // 滑块宽度
            cxwnd = sliderCtrl->height();
            if (sliderCtrl->invertedAppearance()){
                mxpos = mouseEvent->y();
            }else{
                mxpos = cxwnd - mouseEvent->y();
            }
        }
        // 计算结果,并设置新计算得到的 position 值
        int scpos = sliderCtrl->minimum() +
                            (int)((sliderCtrl->maximum() - sliderCtrl->minimum()) *
                                  ((mxpos - cxctl / 2.0) / (cxwnd - cxctl)));
        if(sliderCtrl->sliderPosition() != scpos){
            sliderCtrl->setSliderPosition(scpos);
            mPlayer->setPosition(scpos);
        }
    }
}

void Widget::backFc(){
    // 获取当前播放时长
    qint64 pos = this->mPlayer->position();
    long long time = QDateTime::currentDateTime().toMSecsSinceEpoch();// 获取时间戳
    if(time > leatFreTime + 1500){
        // 上次快退间隔超过5秒,则一级快退
        freLevel = 0;
    }else{
        freLevel ++;
        if(freLevel > 2){
            freLevel = 2;
        }
    }
    if(pos <= 5000+10000*freLevel){
        // 回退到最初
        mPlayer->setPosition(0);
    }else{
        mPlayer->setPosition(pos - (5000+10000*freLevel));
    }
    leatFreTime = time;
}

void Widget::lastFc(){
    int num = listWidget->count();
    if(num <= 0){
        return;
    }
    QListWidgetItem* item = NULL;
    if(num == 1){
        item = listWidget->item(0);
    }else{
        int nowFileIndex = -1;
        QString nowName = fileVal->text();
        for(int i=0;i<num;i++){
            QListWidgetItem* pItem = listWidget->item(i);
            if(pItem->text() == nowName){
                nowFileIndex = i-1;
                break;
            }
        }
        if(nowFileIndex == -1 || nowFileIndex >= num){
            nowFileIndex = 0;
        }
        item = listWidget->item(nowFileIndex);
    }

    if(item != NULL){
        fileVal->setText(item->text());
        item->setSelected(true);
    }
}
void Widget::statFc(){
    int state = this->mPlayer->state();
    if(state == AVPlayer::State::PlayingState){
        // 暂停,修改图标
        mPlayer->pause(!mPlayer->isPaused());
        b2->setIconSize(QSize(150,75));
        statButton->setIcon(statbtnBack);
    }else if(state == AVPlayer::State::PausedState){
        // 继续播放,修改图标
        mPlayer->pause(!mPlayer->isPaused());
        b2->setIconSize(QSize(0,0));
        statButton->setIcon(stopbtnBack);
    }

}
void Widget::openOrCloseVolume(){
    int num = volumeSlider->value();
    if(num <= 0){
        volumeSlider->setValue(oldVolume);
        soundButton->setIcon(soundbtnBack);
    }else{
        oldVolume = num;
        volumeSlider->setValue(0);
        soundButton->setIcon(unsoundbtnBack);
    }
}
void Widget::nextFc(){
    int num = listWidget->count();
    if(num <= 0){
        return;
    }
    QListWidgetItem* item = NULL;
    if(num == 1){
        item = listWidget->item(0);
    }else{
        int nowFileIndex = -1;
        QString nowName = fileVal->text();
        for(int i=0;i<num;i++){
            QListWidgetItem* pItem = listWidget->item(i);
            if(pItem->text() == nowName){
                nowFileIndex = i+1;
                break;
            }
        }
        if(nowFileIndex == -1 || nowFileIndex >= num){
            nowFileIndex = 0;
        }
        item = listWidget->item(nowFileIndex);
    }

    if(item != NULL){
        fileVal->setText(item->text());
        item->setSelected(true);
//        item->setCheckState(Qt::Checked);//Qt::Unchecked
    }
}
void Widget::upFc(){
    // 获取当前播放时长
    qint64 pos = this->mPlayer->position();
    // 获取总时长
    qint64 all = this->mPlayer->duration();
    long long time = QDateTime::currentDateTime().toMSecsSinceEpoch();// 获取时间戳
    if(time > leatFreTime + 1500){
        // 上次快进间隔超过5秒,则一级快退
        freLevel = 0;
    }else{
        freLevel ++;
        if(freLevel > 2){
            freLevel = 2;
        }
    }
    if(pos + 5000+10000*freLevel >= all){
        // 快进到结束
        mPlayer->setPosition(all);
    }else{
        mPlayer->setPosition(pos + (5000+10000*freLevel));
    }
    leatFreTime = time;
}
void Widget::openFile(){
    QString url = QFileDialog::getOpenFileName(this,"选择文件","/","音频(*.mkv *.mp4 *.mp3 *.avi)");// 父组件,标题,初始目录,文件过滤器
    if(url.isEmpty()){
        return;
    }
    int nameIndex = url.lastIndexOf("/");
    QString name = url.mid(nameIndex+1);
    fileVal->setText(name);
    mPlayer->play(url);

    if(!oldStr.contains(url)){
        qDebug()<<"oldStr....."<<oldStr<<";url="<<url;
        QListWidgetItem *item = new QListWidgetItem(name,this->listWidget);
        item->setData(Qt::ToolTipRole,url);
        item->setText(name);

        QWidget *w = new QWidget(listWidget);
        QHBoxLayout *layout=new QHBoxLayout(w);
        layout->setAlignment(Qt::AlignRight);
        QPushButton *pushButton=new QPushButton("x",w);
        pushButton->setMaximumWidth(20);
        pushButton->setMinimumWidth(20);
        pushButton->setMinimumHeight(20);
        pushButton->setMaximumHeight(20);
        layout->addStretch();
        layout->addWidget(pushButton);
        item->setSizeHint(QSize(20,35));
        w->show();
        w->setLayout(layout);
        listWidget->setItemWidget(item,w);
        widgetItemMap[pushButton] = item;
        connect(pushButton,SIGNAL(clicked()),this,SLOT(delItem())); //删除项
//        listWidget->addItem(item);
        QJsonObject fileInfo;
        fileInfo.insert("url",url);
        li.append(fileInfo);
        saveData();
        oldStr.append(";"+url);
        item->setSelected(true);
    }

}

void Widget::saveData(){
    QJsonObject dataJson;
    dataJson.insert("list",li);
    dataJson.insert("volume",nowVolume);
    if(data->open(QIODevice::ReadWrite|QIODevice::Text | QIODevice::Truncate)){
        QJsonDocument doc(dataJson);
        QString strRet = QString(doc.toJson(QJsonDocument::Indented));
        QTextStream ins(data);
        ins<<strRet<<endl;
        data->close();
    }
}
void Widget::openFiles(){
    QStringList urlList = QFileDialog::getOpenFileNames(this,"选择文件","/","音频(*.mkv *.mp4 *.mp3 *.avi)");//Image Files(*.jpg *.png);;MP4(*.mp4)
    if(urlList.size() == 0){
        return;
    }
    for(int i = 0;i < urlList.size();i++){
        int nameIndex = urlList.at(i).lastIndexOf("/");
        QString name = urlList.at(i).mid(nameIndex+1);
        fileVal->setText(name);
        if(i==0){
            mPlayer->play(urlList.at(i));
        }
        if(!oldStr.contains(urlList.at(i))){
            oldStr.append(";"+urlList.at(i));
            QListWidgetItem *item = new QListWidgetItem(name,this->listWidget);
            item->setData(Qt::ToolTipRole,urlList.at(i));
            item->setText(name);

            QWidget *w = new QWidget(listWidget);
            QHBoxLayout *layout=new QHBoxLayout(w);
            layout->setAlignment(Qt::AlignRight);
            QPushButton *pushButton=new QPushButton("x",w);
            pushButton->setMaximumWidth(20);
            pushButton->setMinimumWidth(20);
            pushButton->setMinimumHeight(20);
            pushButton->setMaximumHeight(20);
            layout->addStretch();
            layout->addWidget(pushButton);
            item->setSizeHint(QSize(20,35));
            w->show();
            w->setLayout(layout);
            listWidget->setItemWidget(item,w);
            widgetItemMap[pushButton] = item;
            connect(pushButton,SIGNAL(clicked()),this,SLOT(delItem())); //删除项
//            listWidget->addItem(item);
            QJsonObject fileInfo;
            fileInfo.insert("url",urlList.at(i));
            li.append(fileInfo);
            saveData();
        }
    }
}
void Widget::openDir(){
    QString dirUrl = QFileDialog::getExistingDirectory(this,"选择文件夹","/");
    if(dirUrl.isEmpty()){
        return;
    }
    QDir dir;
    dir.setFilter(QDir::Files | QDir::Hidden | QDir::Dirs);
    dir.setSorting(QDir::Size | QDir::Reversed);
    dir.setPath(dirUrl);
    int oldNum = li.size();
    readDir(dir);
    if(li.size() > oldNum){
        // 数据落地
        saveData();
    }
}

void Widget::closePro(){
    QApplication* app;
    app->quit();
}

void Widget::cutPro(){
    if(mPlayer->state() == AVPlayer::State::PlayingState || mPlayer->state() == AVPlayer::State::PausedState){
        // 不自动保存
        mPlayer->videoCapture()->setAutoSave(false);
        QDir d;
        if(d.mkpath(QApplication::applicationDirPath()+"/cutData")){
            mPlayer->videoCapture()->setCaptureDir(QApplication::applicationDirPath()+"/cutData");
            mPlayer->videoCapture()->capture();
        }
    }
}

void Widget::saveImage(QImage img){
    QString timeStr = QDateTime::currentDateTime().toString("yyyyMMddHHmmss");
    // 100: 质量因数,0~100或-1,100表示大型未压缩
    img.save(QApplication::applicationDirPath()+"/cutData/"+timeStr+".jpg","JPG",100);
}

void Widget::playerClick(){
    int state = this->mPlayer->state();
    if(state == AVPlayer::State::PlayingState){
        // 暂停,修改图标
        mPlayer->pause(!mPlayer->isPaused());
        b2->setIconSize(QSize(150,75));
        statButton->setIcon(statbtnBack);
    }else if(state == AVPlayer::State::PausedState){
        // 继续播放,修改图标
        mPlayer->pause(!mPlayer->isPaused());
        b2->setIconSize(QSize(0,0));
        statButton->setIcon(stopbtnBack);
    }
}

void Widget::readDir(QDir dir){
    QFileInfoList list = dir.entryInfoList();
    for (int i = 0; i < list.size(); ++i) {
        if(list.at(i).isDir()){
            // 目录
            if(!list.at(i).filePath().endsWith(".")){
                QDir loadDir(list.at(i).filePath());
                if(loadDir.exists()){
                    loadDir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::Dirs);
                    readDir(loadDir);
                }
            }
        }else{
            // 文件
            QFileInfo fileInfo = list.at(i);
            if(fileInfo.filePath().endsWith(".mkv") || fileInfo.filePath().endsWith(".mp4")
                    || fileInfo.filePath().endsWith(".mp3") || fileInfo.filePath().endsWith(".avi")){
                if(oldStr.contains(fileInfo.filePath())){
                    continue;
                }
                oldStr.append(";"+fileInfo.filePath());
                int nameIndex = fileInfo.filePath().lastIndexOf("/");
                QString name = fileInfo.filePath().mid(nameIndex+1);
                QListWidgetItem *item = new QListWidgetItem(name,this->listWidget);
                item->setData(Qt::ToolTipRole,fileInfo.filePath());
                item->setText(name);

                QWidget *w = new QWidget(listWidget);
                QHBoxLayout *layout=new QHBoxLayout(w);
                layout->setAlignment(Qt::AlignRight);
                QPushButton *pushButton=new QPushButton("x",w);
                pushButton->setMaximumWidth(20);
                pushButton->setMinimumWidth(20);
                pushButton->setMinimumHeight(20);
                pushButton->setMaximumHeight(20);
                layout->addStretch();
                layout->addWidget(pushButton);
                item->setSizeHint(QSize(20,35));
                w->show();
                w->setLayout(layout);
                listWidget->setItemWidget(item,w);
                widgetItemMap[pushButton] = item;
                connect(pushButton,SIGNAL(clicked()),this,SLOT(delItem())); //删除项
                QJsonObject fileInfoObj;
                fileInfoObj.insert("url",fileInfo.filePath());
                li.append(fileInfoObj);
            }
//            qDebug() << qPrintable(QString("%1").arg(fileInfo.size(), 10))<<";;;;;;;;path="<<fileInfo.filePath();
        }
    }
}
void Widget::keyPressEvent(QKeyEvent *event){
    if(event->key()==Qt::Key_Left){
        if(!event->isAutoRepeat()){
            backFc();
        }
    }
    if(event->key()==Qt::Key_Right){
        if(!event->isAutoRepeat()){
            upFc();
        }
    }
    if(event->key()==Qt::Key_Up){
        addVolume();
    }
    if(event->key()==Qt::Key_Down){
        subVolume();
    }
    if(event->key()==Qt::Key_Escape){
        fileVal->show();
        hideButton->show();
        maxButton->show();
        closeButton->show();
        backButton->show();
        lastButton->show();
        statButton->show();
        nextButton->show();
        upButton->show();
        tomaxButton->show();
        timeSlider->show();
        timeLable->show();
        soundButton->show();
        bar->show();
        btnRight->show();
        btnLeft->show();
        boxBtn->show();
        cutButton->show();
    }
}

void Widget::subVolume(){
    int num = volumeSlider->value();
    if(num <= 0){
        soundButton->setIcon(soundbtnBack);
        return;
    }
    num -= 15;
    if(num <= 0){
        num = 0;
    }
    nowVolume = num;
    volumeSlider->setValue(num);
    mPlayer->audio()->setVolume(num/100.0);
}

void Widget::addVolume(){
    int num = volumeSlider->value();
    if(num <= 0){
        soundButton->setIcon(soundbtnBack);
    }
    if(num >= 100){
        return;
    }
    num += 15;
    if(num > 100){
        num = 100;
    }
    nowVolume = num;
    volumeSlider->setValue(num);
    mPlayer->audio()->setVolume(num/100.0);
}

void Widget::tomax(){
    setWindowState(Qt::WindowMaximized);
    fileVal->hide();
    hideButton->hide();
    maxButton->hide();
    closeButton->hide();
    backButton->hide();
    lastButton->hide();
    statButton->hide();
    nextButton->hide();
    upButton->hide();
    tomaxButton->hide();
    volumeSlider->hide();
    timeSlider->hide();
    timeLable->hide();
    soundButton->hide();
    bar->hide();
    btnRight->hide();
    btnLeft->hide();
    boxBtn->hide();
    cutButton->hide();

    showList = false;
    listWidget->hide();
    showListButton->setStyleSheet("border-image:url(:/resources/hideList.png);");
}

void Widget::hidePro(){
    setWindowState(Qt::WindowMinimized);
}

void Widget::maxPro(){
    setWindowState(Qt::WindowMaximized);
}

void Widget::filePlay(QString url){
    if(url.endsWith(".mkv") || url.endsWith(".mp4")
            || url.endsWith(".mp3") || url.endsWith(".avi")){
        int nameIndex = url.lastIndexOf("\\");
        QString name = url.mid(nameIndex+1);
        fileVal->setText(name);
        mPlayer->play(url);

        if(!oldStr.contains(url) && !oldStr.contains(name)){
            QListWidgetItem *item = new QListWidgetItem(name,this->listWidget);
            item->setData(Qt::ToolTipRole,url);
            item->setText(name);

            QWidget *w = new QWidget(listWidget);
            QHBoxLayout *layout=new QHBoxLayout(w);
            layout->setAlignment(Qt::AlignRight);
            QPushButton *pushButton=new QPushButton("x",w);
            pushButton->setMaximumWidth(20);
            pushButton->setMinimumWidth(20);
            pushButton->setMinimumHeight(20);
            pushButton->setMaximumHeight(20);
            layout->addStretch();
            layout->addWidget(pushButton);
            item->setSizeHint(QSize(20,35));
            w->show();
            w->setLayout(layout);
            listWidget->setItemWidget(item,w);
            widgetItemMap[pushButton] = item;
            connect(pushButton,SIGNAL(clicked()),this,SLOT(delItem())); //删除项
            QJsonObject fileInfo;
            fileInfo.insert("url",url);
            li.append(fileInfo);
            saveData();
            oldStr.append(";"+url);
            item->setSelected(true);
        }
    }
}
void Widget::selectSpeed(QString sp){
    QString s= sp.replace("x","");
    speed = s.toDouble();
    mPlayer->setSpeed(speed);
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值