qt实现一个MP4视频播放器

gitee源码

需求分析

1. 使用IOC容器
2. 使用接口编程
3. 能播放,暂停,倍数等基本功能

环境

1. qt6.4.2
2. windows
3. C++
使用qt6.4.2是因为qt6.3.1没有QMediaPlayer模块

代码

1. 接口实现

class video_Api : public QObject
{
    Q_OBJECT
public:
    virtual void play() = 0;                                    //开始播放
    virtual void pause() = 0;                                   //暂停
    virtual void stop() = 0;                                    //停止
    virtual void play_path(QString path) = 0;                   //设置播放路径
    virtual void set_video_output(QGraphicsVideoItem* item) = 0;//设置视频输出
    virtual void set_voice_output() = 0;                        //设置声音输出
    virtual int return_video_duration() = 0;                    //返回视频长度
    virtual void set_video_rate(float value) = 0;               //设置播放速率
    virtual int return_play_stat() = 0;                         //返回视频状态
    virtual QString return_play_source() = 0;                   //返回当前播放视频
public slots:
    virtual void set_play_position(int value) = 0;              //设置播放位置
    virtual void set_play_voice(int value) = 0;                 //设置声音大小
public:
    enum player_stat
    {
        StoppedState,
        PlayingState,
        PausedState
    };
signals:
    void position_change(qint64 value);                         //更新播放进度

protected:
    explicit video_Api(QObject *parent = nullptr);
};

2. 接口子类实现

class default_Video_Api : public video_Api
{
    Q_OBJECT
public:
    static default_Video_Api*getInstance()
    {
        if(instance == nullptr)
        {
            instance = new default_Video_Api();
        }
        return instance;
    }

public:
    void play();                                    //播放
    void pause();                                   //暂停
    void stop();                                    //停止
    void play_path(QString path);                   //设置播放路径
    void set_video_output(QGraphicsVideoItem* item);//设置视频输出
    void set_voice_output();                        //设置声音输出
    int return_video_duration();                    //返回视频长度
    void set_video_rate(float value);               //设置播放速率
    int return_play_stat();                         //返回视频状态
    QString return_play_source();                   //返回当前播放视频
public slots:
    void set_play_position(int value);              //设置播放位置
    void set_play_voice(int value);                 //设置声音大小
protected:
    default_Video_Api();
protected slots:
    void position_changed(qint64 value);

private:
    QMediaPlayer *player;   //播放器
    QAudioOutput *voice;    //声音器
    static default_Video_Api *instance;
};
default_Video_Api* default_Video_Api::instance = nullptr;

void default_Video_Api::play()
{
    player->play();
}

void default_Video_Api::pause()
{
    player->pause();
}

void default_Video_Api::stop()
{
    player->stop();
}

void default_Video_Api::play_path(QString path)
{
    player->setSource(QUrl::fromLocalFile(path));
}

void default_Video_Api::set_video_output(QGraphicsVideoItem *item)
{
    player->setVideoOutput(item);
}

void default_Video_Api::set_voice_output()
{
    player->setAudioOutput(voice);
}

int default_Video_Api::return_video_duration()
{
    return player->duration();
}

void default_Video_Api::set_video_rate(float value)
{
    player->setPlaybackRate(value);
}

int default_Video_Api::return_play_stat()
{
    return player->playbackState();
}

QString default_Video_Api::return_play_source()
{
    return player->source().toString();
}

void default_Video_Api::set_play_position(int value)
{
    player->setPosition(value);
}

void default_Video_Api::set_play_voice(int value)
{
    float avalue = value*0.01;
    voice->setVolume(avalue);
}

default_Video_Api::default_Video_Api()
{
    player = new QMediaPlayer;
    voice = new QAudioOutput;
    connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(position_changed(qint64)));

}

void default_Video_Api::position_changed(qint64 value)
{
    emit position_change(value);
}

3. IOC容器实现

//IOC容器
template <class T>
class IOCcontainer
{
public:
    IOCcontainer()
    {

    };
    ~IOCcontainer()
    {


    };

    //注册需要创建对象的getInstance,通过唯一的标识符,以便于以后查找
    template <class driver>
    void registerType(QString str_key)
    {
        std::function < T* ()> function = []
        {

            return driver::getInstance();
        };
        registerType(str_key, function);
    }

    //根据唯一的标识去查找getInstance函数
    T* resolve(QString str_key)
    {
        //没有这个构造函数
        if (m_createMap.find(str_key) == m_createMap.end())
        {
            return nullptr;
        }
        //有这个getInstance
        std::function<T*()> function = m_createMap[str_key];
        return function();
    }

    //访问对象
    T* resilveshare(QString str_key)
    {
        T* ptr = resolve(str_key);
        return ptr;
    }

private:
    void registerType(QString str_key, std::function<T* ()> creator)
    {
        //如果存在的话
        if (m_createMap.find(str_key) != m_createMap.end())
        {
            throw std::invalid_argument("已经存在这个key了");
        }
        m_createMap.emplace(str_key, creator);
    }


private:
    map<QString, std::function<T* ()>> m_createMap;

};

4. 界面设计

界面

5. 界面功能实现

  1. 初始化
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //初始化内核
    core = QString("default");

    //注册api对象
    m_video_Api_IOC.registerType<default_Video_Api>("default");

    //初始化智能指针(使用默认内核)
    m_video_Api = m_video_Api_IOC.resilveshare("default");

    //视频设置
    scene = new QGraphicsScene(this);

    videoItem = new QGraphicsVideoItem;
    videoItem->setFlags(QGraphicsVideoItem::ItemIsFocusable);

    ui->graphicsView->setScene(scene);
    m_video_Api->set_video_output(videoItem);
    scene->addItem(videoItem);
    duration = 0;
    QString process_time = QString("%1s/%2s")
            .arg(QString::number(0))
            .arg(QString::number(duration/1000));
    //声音设置
    m_video_Api->set_voice_output();
    m_video_Api->set_play_voice(100);
    ui->horizontalSlider_voice->setMaximum(100);
    ui->horizontalSlider_voice->setValue(100);
    ui->label_voice_value->setText("100");
    //倍数设置
    rate = 1.0;
    ui->pushButton_rate->setText("1.0");
    m_video_Api->set_video_rate(rate);

    //槽连接
    connect(m_video_Api,SIGNAL(position_change(qint64)),this,SLOT(onPositionChanged(qint64)));
}
  1. 播放
void MainWindow::on_pushButton_play_clicked()
{
    m_video_Api->play();
    //获取播放总时长-------------------------------------
    duration = m_video_Api->return_video_duration();
    ui->horizontalSlider_process->setMaximum(duration);
    QString process_time = QString("%1s/%2s")
            .arg(QString::number(0))
            .arg(QString::number(duration/1000));
    ui->label_process->setText(process_time);
    //适应大小------------------------------------------
    videoItem->setSize(ui->graphicsView->size());
}


  1. 暂停
void MainWindow::on_pushButton_pause_clicked()
{
    m_video_Api->pause();
}


  1. 停止
void MainWindow::on_pushButton_stop_clicked()
{
    m_video_Api->stop();
}

  1. 倍数
void MainWindow::on_pushButton_rate_clicked()
{
    if(rate == 1.0)
    {
        rate = 2.0;
        ui->pushButton_rate->setText("2.0");
        m_video_Api->set_video_rate(rate);
    }
    else if(rate == 2.0)
    {
        rate = 0.5;
        ui->pushButton_rate->setText("0.5");
        m_video_Api->set_video_rate(rate);
    }
    else if(rate == 0.5)
    {
        rate = 1.0;
        ui->pushButton_rate->setText("1.0");
        m_video_Api->set_video_rate(rate);
    }
    //m_video_Api->set_video_rate(rate);
}


  1. 上一个
void MainWindow::on_pushButton_last_clicked()
{
    //获取当前播放视频信息
    int row = ui->listWidget->currentRow();
    //列表上一个
    if(row == 0)
    {
        return;
    }
    QListWidgetItem* item = ui->listWidget->item(row-1);
    QString key = item->text();
    QString value_path;
    for(auto i = fileMap.begin();i!=fileMap.end();i++)
    {
        if(i.key() == key)
        {
            value_path = i.value();
            break;
        }
    }
    ui->listWidget->setCurrentRow(row-1);
    //设置视频源
    m_video_Api->play_path(value_path);
    //播放
    //on_pushButton_play_clicked();
}
  1. 下一个
void MainWindow::on_pushButton_next_clicked()
{
    //获取当前播放视频信息
    int row = ui->listWidget->currentRow();
    //列表下一个
    if(!ui->listWidget->item(row+1))
    {
        return;
    }
    QListWidgetItem* item = ui->listWidget->item(row+1);
    QString key = item->text();
    QString value_path;
    for(auto i = fileMap.begin();i!=fileMap.end();i++)
    {
        if(i.key() == key)
        {
            value_path = i.value();
            break;
        }
    }
    ui->listWidget->setCurrentRow(row+1);
    //设置视频源
    m_video_Api->play_path(value_path);
    //播放
    //on_pushButton_play_clicked();
}


  1. 添加播放文件

void MainWindow::on_pushButton_select_path_clicked()
{
    QString currentpath = QDir::homePath();                                     //获取系统当前目录
    QString digTitle = "请选择视频文件";                                          //打开文件对话框的标题
    QString strfilter = QString("All Files(*.*)");                              //文件过滤
    QString allfiles = QFileDialog::getOpenFileName(this,digTitle,currentpath); //打开文件

    if(allfiles.isEmpty())
    {
        QMessageBox::information(this,"提示","打开错误,路径为:"+ allfiles);
        return;
    }

    QFileInfo fileInfos(allfiles);
    fileMap.insert(fileInfos.fileName(),allfiles);
    //qDebug()<<fileMap.keys();
    //qDebug()<<fileMap.values();
    ui->listWidget->addItem(fileInfos.fileName());
}


  1. 删除播放文件
void MainWindow::on_pushButton_delete_path_clicked()
{
    int row = ui->listWidget->currentRow();
    QListWidgetItem* delete_path = ui->listWidget->takeItem(row);

    QString value;
    QString key = delete_path->text();
    for(auto i = fileMap.begin();i != fileMap.end();i++)
    {
        if(i.key() == key)
        {
            value = i.value();
            fileMap.remove(key);
            break;
        }
    }
   // qDebug()<<value;
   // qDebug()<<m_video_Api->return_play_source();
    //如果删除的视频正在播放
    if("file:///"+value == m_video_Api->return_play_source())
    {
        m_video_Api->stop();
        m_video_Api->play_path(nullptr);
    }

    QMessageBox::information(this,"提示","成功删除:"+delete_path->text());
    //qDebug()<<fileMap.keys();
    //qDebug()<<fileMap.values();

    //delete delete_path;
}


  1. 进度条

void MainWindow::onPositionChanged(qint64 position)
{
    ui->horizontalSlider_process->setValue(position);
    QString process_time = QString("%1s/%2s")
            .arg(QString::number(position/1000))
            .arg(QString::number(duration/1000));
    ui->label_process->setText(process_time);
}


void MainWindow::on_horizontalSlider_process_sliderPressed()
{
    m_video_Api->pause();
}


void MainWindow::on_horizontalSlider_process_sliderReleased()
{
    m_video_Api->play();
}


void MainWindow::on_horizontalSlider_process_sliderMoved(int position)
{
    //如果是暂停状态-----------------------------
    if(m_video_Api->return_play_stat() == 2)
    {
        m_video_Api->set_play_position(position);
    }
    QString process_time = QString("%1s/%2s")
            .arg(QString::number(position/1000))
            .arg(QString::number(m_video_Api->return_video_duration()/1000));
    ui->label_process->setText(process_time);
}

  1. 音量条

void MainWindow::on_horizontalSlider_voice_sliderMoved(int position)
{
    m_video_Api->set_play_voice(position);
    ui->label_voice_value->setText(QString::number(position));
}

结果展示

结果

总结

1. 主要是结合了IOC容器和单例的学习
2. 对设计模式(创建型)有了更加深入的了解
3. 对未来ffmmpeg模块,我只需要将其抽象成接口,然后就跟core为ffmmpeg,在初始化一遍
	就完成了ffmmpeg模块功能加载,这无一不体现设计模式的可扩展性。
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱睡觉更爱学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值