QML绘制参考链接:https://blog.csdn.net/cxc233/article/details/80382696
ffmpeg参考链接:http://blog.yundiantech.com/?log=blog&id=11
视频绘制类
继承QQuickPaintedItem可以使用QPainter接口将一帧解码QImage绘制到Qml上面。(XVideo是QQuickPaintedItem的子类)当接收到一帧(QImage)的时候直接调用update()更新
视频解码类
ffmpeg解码的代码网上很多例子,可参考开头给出的链接,这里主要讲一下视频同步的问题。
视频同步
参考的链接中给出的同步方案有一种是通过对音频时间的记录音频的时间来显示视频达到同步的效果,因工作中得到的视频文件中没有音频,所以此方法不适用。另一种方法是通过记录播放时的主时钟时间与视频数据中的时间比较来达到视频同步,本文章就采用这种方法。
这里简单贴一段代码:
int64_t start_time = av_gettime();
while (1)
{
if (av_read_frame(pFormatCtx, packet) < 0)
{
break; //这里认为视频读取完了
}
int64_t realTime = av_gettime() - start_time; //主时钟时间
while(pts > realTime)
{
msleep(10);
realTime = av_gettime() - start_time; //主时钟时间
}
if (packet->stream_index == videoStream)
{
...
...
pts = packet->dts;
pts *= 1000000 * av_q2d(mVideoState.video_st->time_base);
...
...
if(got_picture)
{
...
emit sig_GetOneFrame(image);
}
}
...
}
视频暂停/播放,停止功能
因为视频的同步播放是基于系统主时钟实现的,所以暂停和播放功能必须对记录的start_time作调整,否则暂停后播放就会有一种"追赶"的现象。
下面贴出关键代码:
int64_t start_time = av_gettime();
while (1)
{
if( mPlayerState == Pause ) {
emit sig_GetOneFrame(QImage()); //发送信号
break;
}
if( mPlayerState == Stop ) {
b_hasStopped = true;
msleep(10);
continue;
}
//暂停重新开启,重置启动时间
if( b_hasStopped ) {
start_time = av_gettime() - pts;
}
if (av_read_frame(pFormatCtx, packet) < 0)
{
break; //这里认为视频读取完了
}
...
if(git_picture)
{
...
emit sig_GetOneFrame(image); //发送信号
b_hasStopped = false;
}
}
这里在暂停再次播放后,将start_time重新设置,其中pts为视频已播放的时间。
播放界面
界面做的很粗糙,进度条的跳转功能还未完成。
代码下载地址:https://download.csdn.net/download/w54a3teg64c7bd/10686106