ffpmeg笔记:(2)学习一个开源小demo:qt+sdl+ffmpeg,计算时间戳
创始人
2025-05-31 15:45:36

文章目录

  • 前言
  • 1.源码和编译方法
    • 1.1编译方法:
  • 2.源码简单介绍
    • 2.1 播放线程类 PlayThread
      • 2.1.1 计算当前播放进度时间
    • 2.2 主界面类 MainWindow
      • 2.2.1 在Qt widget中显示视频
      • 2.2.2 控制区域的自动隐藏和再现

前言

这个小demo实现了下面的功能:

1.打开文件。
2.播放。
3.暂停。
4.停止。
5.进度条显示,视频时长,当前进度时间。
6.控制面板隐藏和再现。

应该实现却没有实现的功能:

1.倍速播放
2.滑动进度条指定播放位置
3.音量调节

demo的效果:

https://www.bilibili.com/video/BV1Vv4y1j7sw/?spm_id_from=333.999.0.0&vd_source=f724775496aa565e12020e8529f8b274

1.源码和编译方法

原工程:https://gitee.com/tgtsml/QtPlayer
改动后工程:https://gitee.com/huangweide001/hwd-qt-demo/tree/master/QtPlayer-004

1.1编译方法:

我使用的版本是 Qt 5.14.1
1.使用qtCreator打开《QtSdlPlayer.pro》;
2.选择Qt的工具集 MinGW_64_bit;
3.构建项目,在工程目录下自动生成bin目录,用于存放exe文件。把下面的文件拷贝到本bin目录:

3.1 《3rdlib\ffmpeg-4.4-full_build-shared\bin*》
3.2 《3rdlib\SDL2\bin*》

4.在Qt中点击运行。

2.源码简单介绍

2.1 播放线程类 PlayThread

类PlayThread主要完成音视频的播放流程,相关的原理性介绍参考雷神的文章:最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)。
在播放流程的基础上,增加了几个发送信号的函数:

class PlayThread : public QThread
{Q_OBJECTvoid run() override;signals:void signal_updateDisplayImage(QImage img);	//	发送画面更新信号void signal_updateTotalTime(QTime time);	//	发送视频的长度void signal_updatePlayedTime(QTime time);	//	发送播放进度时间void signal_PlayedDone(void);				//	发送播放完毕信号
......
}    

这些信号对应主界面类MainWindow的槽函数。

2.1.1 计算当前播放进度时间

在这里插入图片描述
AVRational vedio_time_base= pFormatCtx->streams[videoindex]->time_base;
current_play_time = pFrame->pts * av_q2d(vedio_time_base);
在更新视频帧的位置加入计算当前进度时间的代码,单位为秒;因为一秒有约30个视频帧,不必每次更新视频帧时一起更新时间;所以做一下判断,只有秒数发生变化,才通知主界面更新当前进度时间。

                    ticks = pFrame->pts * av_q2d(vedio_time_base);		//计算当前时间戳//当进度秒数有变化时,发送信号通知界面if(old_sec != ticks){old_sec = ticks;qDebug()<

2.2 主界面类 MainWindow

类 MainWindow显示界面包括视频区域和控制区域,控制区域当鼠标移动时显示,鼠标停止动作3秒后隐藏。和PlayThread的信号对应的槽函数:

class MainWindow : public QMainWindow
{Q_OBJECT
public:MainWindow(QWidget *parent = nullptr);~MainWindow();void slot_updateCurrentImage(QImage img);void slot_updateTotalTime(QTime time);void slot_updatePlayedTime(QTime time);void slot_PlayedDone(void);
......
}    

2.2.1 在Qt widget中显示视频

本demo显示视频的方式是在视频解码时,生成一个QImage的对象,再把QImage通过信号和槽函数的方式传输。
在类PlayThread中生成QImage,并发送信号:

	sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx_Video->height, pFrameYUV->data, pFrameYUV->linesize);QImage tmpImg((uchar *)out_buffer_video, pCodecCtx_Video->width, pCodecCtx_Video->height,QImage::Format_RGB32);QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示emit signal_updateDisplayImage(image);  //发送界面刷新信号

在类MainWindow中的槽函数接收QImage:

void MainWindow::slot_updateCurrentImage(QImage img)
{m_currentImage = img;update();
}
void MainWindow::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.setBrush(Qt::black);painter.drawRect(0, 0, this->width(), this->height());if (m_currentImage.size().width() <= 0){return;}QImage img = m_currentImage.scaled(this->size(), Qt::KeepAspectRatio);int x = this->width() - img.width();int y = this->height() - img.height();painter.drawImage(x/2.0, y/2.0, img);
}

2.2.2 控制区域的自动隐藏和再现

在类MainWindow的构造函数中,开启一个定时器,每次启动后,单次触发。

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
......m_timerToHideControlBar = new QTimer(this);m_timerToHideControlBar->setSingleShot(true);	//	单次触发//	定时时间到,触发进度条隐藏的动作connect(m_timerToHideControlBar, &QTimer::timeout, [=](){ui->widget_playControlWgt->setVisible(false);});
}

鼠标按下或者移动时,显示进度条,并启动3秒的定时:

void MainWindow::restartControlBarHideTimer()
{if(! ui->widget_playControlWgt->isVisible() || m_timerToHideControlBar->isActive()){m_timerToHideControlBar->stop();ui->widget_playControlWgt->setVisible(true);}m_timerToHideControlBar->start(3000);
}
void MainWindow::mousePressEvent(QMouseEvent *event)
{restartControlBarHideTimer();QMainWindow::mousePressEvent(event);
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{restartControlBarHideTimer();QMainWindow::mouseMoveEvent(event);
}

相关内容

热门资讯

原创 茅... 在高端白酒领域,贵州茅台无疑是耀眼的明星,其核心产品飞天茅台的官方指导零售价长期锁定在1499元。然...
原创 霸... 婚礼在常州,张俊杰迎娶高海纯,话题立马炸开,强强联合,还是门不当户不对,围观都在评,张俊杰早年苦,睡...
苏酒三强一把手首聚,坐在一起已... 来源:市场资讯 (来源:云酒头条) “破除内卷、勇挑大梁、同振苏酒”三大共识,背后很可能是江苏...
聊聊美食文化那些易被忽略却超关... 探讨美食文化时,绝不能只局限于“吃什么”,以及这样浅显层面的“怎么吃”。在我想的看来,美食文化有的更...
聊聊美食文化那些易忽视却重要的... 美食所蕴含的文化可不单单只是关乎吃何种食物,它与历史相连接,且关联到社会,还和个人记忆有着紧密联系,...