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容器实现
template <class T>
class IOCcontainer
{
public:
IOCcontainer()
{
};
~IOCcontainer()
{
};
template <class driver>
void registerType(QString str_key)
{
std::function < T* ()> function = []
{
return driver::getInstance();
};
registerType(str_key, function);
}
T* resolve(QString str_key)
{
if (m_createMap.find(str_key) == m_createMap.end())
{
return nullptr;
}
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. 界面设计
![界面](https://i-blog.csdnimg.cn/blog_migrate/13409ec8f9cca008a91e1690b6e4d8d4.png)
5. 界面功能实现
- 初始化
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
core = QString("default");
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)));
}
- 播放
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());
}
- 暂停
void MainWindow::on_pushButton_pause_clicked()
{
m_video_Api->pause();
}
- 停止
void MainWindow::on_pushButton_stop_clicked()
{
m_video_Api->stop();
}
- 倍数
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);
}
}
- 上一个
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);
}
- 下一个
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);
}
- 添加播放文件
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);
ui->listWidget->addItem(fileInfos.fileName());
}
- 删除播放文件
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;
}
}
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());
}
- 进度条
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);
}
- 音量条
void MainWindow::on_horizontalSlider_voice_sliderMoved(int position)
{
m_video_Api->set_play_voice(position);
ui->label_voice_value->setText(QString::number(position));
}
结果展示
![结果](https://i-blog.csdnimg.cn/blog_migrate/b4e80dae8b57319417c06ef7a4681745.png)
总结
1. 主要是结合了IOC容器和单例的学习
2. 对设计模式(创建型)有了更加深入的了解
3. 对未来ffmmpeg模块,我只需要将其抽象成接口,然后就跟core为ffmmpeg,在初始化一遍
就完成了ffmmpeg模块功能加载,这无一不体现设计模式的可扩展性。