• 62605阅读
  • 78回复

用Qt和FFmpeg写了个播放器 QtAV库 [复制链接]

上一主题 下一主题
离线novesky
 

图酷模式  只看楼主 正序阅读 楼主  发表于: 2012-11-03
— 本帖被 XChinux 设置为精华(2016-03-16) —
关键词: 播放器ffmpeg
阅读README很重要
欢迎大家来参与主页 http://wang-bin.github.io/QtAV

2015.12.21 QtAV 1.9.0

QtAV 1.9.0 发布了,该版本改进内容包括:
- 支持Windows Store。应用商店搜索qtav
- 给FFmpeg提交了winrt多线程支持的补丁,性能大有提升,已合并至上游
- 修复iOS部署和运行错误一些问题
- XAudio2 崩溃问题
- Android: 支持content协议,修复从相册打开无法播放问题;windows上编译、部署问题修复

- VA-API: 改善n卡支持;加入hevc, vp9,未测;EGL零拷贝渲染支持,性能最好,需要va-api 0.38(ubuntu15.10)和Qt>=5.5及intel显卡。其他一些改进
- 使用OpenGL, GLSL新接口,OpenGL ES3优化
- 支持播放前一帧
- QMLPlayer: 可以按住预览框拖动,处理安卓的home键、返回键...

- 其他更新请看
下载

2014.12.27 QtAV 1.4.2
- 提高seek速度。要感谢wm4(mpv主力开发者)的指点
- 优化音视频同步逻辑,软解播放高分辨率高帧率视频完胜其他播放器。其他播放器几乎不能看,包括硬解,除了mpv+vaapi。以后将有更好的优化。windows下效果略差。4k 120fps测试视频: http://pan.baidu.com/s/1sj6s40l
- 修复VA-API解码图像下方多出一条模糊的线问题。修复使用libav9时vaapi可能不工作的问题。
- ffmpeg运行时支持hevc dxva硬解的话就启用硬解。目前要使用LAVFilters的ffmpeg。
- Cedarv硬解优化
- 增加可扩展的视频输入源接口。支持qrc资源文件里的音视频播放(QtMultimedia还不支持)
- 异步加载
- 修复使用openal时多个播放器实例播放音频不正常问题
- 修复播放下一帧问题
- 修复截图不是当前帧问题。简化截图接口
- 修复qml视频画面抖动问题
- 正确处理文件名中的特殊字符。
- libass改为动态加载。依赖 https://github.com/wang-bin/capi
- 支持链接到ffmpeg静态库
- rgb48支持。opengl只支持rgb48le

2014.09.10 QtAV 1.4.0
下载:https://sourceforge.net/projects/qtav/files/release/1.4.0
- OpenGL优化,支持更多的格式,支持QML,对于Qt>=5.4支持opengl动态切换
- VAAPI: GLX直接渲染支持,性能大幅提升。检测显卡是否4k以防止系统崩溃.
- DXVA: 更多解码表面以提升性能防止画面抖动
- OSX的VDA硬解支持
- Android支持,部署更简单
- 字幕支持,包括qml
- OpenAL 改进,支持大多数平台
- FFmpeg的libavfilter支持
- 音频播放接口改变
- 简化OSX的部署和安装包制作
- bug修复

2014.05.30 QtAV1.3.4
- CUDA:修复播放时花屏、画面顺序跳动等问题
- VAAPI,DXVA:之前VAAPI的性能很差。现在intel gpu使用sse4.1来拷贝解码数据,性能提升明显。 VAAPI支持drm
- 使用ffmpeg新的硬解接口
- 修复切换解码器后画面显示不对甚至崩溃问题
- 加入avcodec、avformat和各解码器的一些高级选项。
- metadata 支持
- 优先使用流信息里的显示比例。感谢 Sandro Cavazzoni
- 修复文件名编码问题。之前貌似日语文件名打不开
- 修复带图片的音频不显示图片和不能拖动进度的问题
- 支持将QtAV安装为Qt的模块方便开发应用
详情见 http://wang-bin.github.io/qtav.org/blog/1.3.4.html


2014.01.29 QtAV 1.3.1

库相关:
- OpenAL初步支持
- 修复硬件解码时seek、网络丢包等情况下崩溃问题
- CedarX硬解支持。可以在pcDuino上硬解。感谢 Miroslav Bendik. 可以看他的视频 http://www.youtube.com/watch?v=u3mvDe3GBPI
- FFmpeg log和错误处理
- AVDictionary 支持
- Hi10bits 使用软解
- 还有其他诸多改进
播放器相关:
ctrl+滚动滚轮进行缩放,禁止屏保等
同时加入了界面更加 cool 的 QMLPlayer例子,在windows、mac、linux上都有不错的体验

2013.12.19 QtAV 1.3.0 发布
- windows下dxva硬解初步支持,目前拖动时间可能会有崩溃问题。vaapi目前性能很差
- 可选择音轨
- 可调节亮度、饱和度等
- 循环播放、播放列表、历史记录
- HEVC支持(FFmpeg)
- 优化网络电视界面、其他界面等
以下功能是库里支持但player未加ui的
- 一个视频播放多个输出窗口支持,支持裁剪,自定义filter




2013.07.04 QtAV1.2.2

改进的是音频播放,之前播放mp3和部分视频爆音的问题已无
任意控制播放速度(见图,或Ctrl+上/下来加减速度)
音量控制控件


1.2.1主要更新:
视频显示质量控制
修复显示比例不正确的问题。可以设为任意比例
修复一些崩溃、内存泄漏等错误


2013.05.27 QtAV1.2.0发布:
更新很多东西,主要有
1. player例子加入gui界面,易于操控。自带一些网络电视
2. 独创的播放时渲染引擎无缝动态切换。可以方便地对比各种渲染引擎的cpu使用率
3. X11下XV的支持(Qt4 only)
4. bug修复等





2013-03015
    新增了几个渲染方式,如opengl, direct2d, gdi。在我电脑上direct2d对性能提升非常明显。增加了OSD(现在的设计很烂),原来的O键改成了切换OSD。Ctrl+O是打开文件。
    切换视频大小比例按R。
    完善了qmake的工程框架,移植了很多Qt5里qmake内置函数到Qt4,用qmake语法写的,支持编译检测。若要重新配置请删除编译目录里的.qmake.cache再qmake,mingw可能qmake一次不够,需要两次(还没找到原因,我的pro写得太复杂了)。linux下支持make deb来生成安装包。
    支持VC(我vs2010编译出来的无法运行,2012正常,不解),方法见github 上的wiki。支持Qt5

    命令行:player [-vo qt|gl|d2d|gdi] [url/path]filename
    或者把player改名成player-gl, player-d2d, player-gdi也可以

2013-01-13更新
    已经比较稳定了。目前有一些国内外的开发者在使用了,用来显示摄像头实时视频蛮多的。
    还有很多东西要开发,比如组件化、硬件加速等


源码:https://github.com/wang-bin/QtAV
由于github即将关闭文件上传的功能,所以在sourceforge上也建了一个,可以下载mingw下编译所需的库

win下编译要用到的库如ffmpeg,portaudio可以在https://sourceforge.net/projects/qtav/files/depends 下载
希望对大家有所帮助。

了解了下视频解码和音视频同步的原理,于是一口气写了个播放器,感觉并不难。音频播放使用portaudio,在linux上貌似有问题。功能还比较简单,能正常播放视频。对比了mplayer、迅雷看看播放4G大小的视频的资源使用,它们都要200多M的内存,我的只要50多点,挺意外的。




支持快进快退、暂停继续、音量调节、单帧控制、截图等

TODO:字幕,长宽比例 etc


















离线foxgod

只看该作者 78楼 发表于: 2017-09-04
ffmepg是不是需要sdk一起才能播放视频呢
离线xushuai_sio

只看该作者 77楼 发表于: 2016-05-11
厉害,学习了
离线姜小白

只看该作者 76楼 发表于: 2016-04-05
顶一个。。。
我整理的一些文章,持续更新中,有兴趣的小伙伴可以关注。
https://xiaozhuanlan.com/sorghum-cpp?rel=sorghum

Qt技术交流:QQ2499971906
离线qq413317226

只看该作者 75楼 发表于: 2016-04-04
厉害
离线shallow_wy

只看该作者 74楼 发表于: 2016-03-16
为什么我源码总是编译不成功,出现一堆警告,最后程序异常结束
Starting F:\QtAV-master\build-QtAV-Desktop_Qt_5_5_1_MSVC2013_64bit-Debug\bin\extract.exe...
程序异常结束。
F:\QtAV-master\build-QtAV-Desktop_Qt_5_5_1_MSVC2013_64bit-Debug\bin\extract.exe crashed
离线tianp2010

只看该作者 73楼 发表于: 2015-12-25
非常谢谢楼主的分享, 我正再做 ffmpeg 编码部分 ,下载研究学习
离线zhuzhuwonder

只看该作者 72楼 发表于: 2015-12-23
回 novesky 的帖子
novesky:编译好qtav运行编译目录的sdk_install.bat,然后可以调用qtav模块了。选择simpleplayer_sdk.pro就是使用qtav模块脱离源码树编译,放到任何地方都能编译 (2015-12-21 23:54) 

那其他没有sdk的工程该如何独立编译呢,比如videogroup,videowall。还有videowall运行之后就只有一个9宫格,不能拖放视频进行播放,按快捷键也没有响应。
离线novesky

只看该作者 71楼 发表于: 2015-12-21
回 zhuzhuwonder 的帖子
zhuzhuwonder:请问楼主如何使用QtAV里面的例子?就比如说我想把simple player 单独拿出来整合到我的工程里面,而不想把它放在总的QtAV工程里面运行,但是单独编译这个工程会报错:
No rule to make target 'e:/QTAV/QtAV-master/examples/build-simpleplayer-Qt_4_8_6-Release/../out/lib_w .. (2015-12-17 19:52) 

编译好qtav运行编译目录的sdk_install.bat,然后可以调用qtav模块了。选择simpleplayer_sdk.pro就是使用qtav模块脱离源码树编译,放到任何地方都能编译
离线zhuzhuwonder

只看该作者 70楼 发表于: 2015-12-17
请问楼主如何使用QtAV里面的例子?就比如说我想把simple player 单独拿出来整合到我的工程里面,而不想把它放在总的QtAV工程里面运行,但是单独编译这个工程会报错:
No rule to make target 'e:/QTAV/QtAV-master/examples/build-simpleplayer-Qt_4_8_6-Release/../out/lib_win_/QtAV.dll', needed by '..\out\bin\simpleplayer.exe'.  Stop.
请问该如何操作呢?谢谢!
离线atsunlun

只看该作者 69楼 发表于: 2015-11-29
我在使用QTAV的时候,播放网络视频,不流畅。请问,我想设置它的缓存大小应该怎么做?还有随便将视频保存下来,应该怎么做?
离线electri

只看该作者 68楼 发表于: 2015-01-22
编译的时候出现了以下的错误,libQtAV.so编译没问题,倒是在编译examples时出现了以下的错误
离线qyvlik

只看该作者 67楼 发表于: 2015-01-04
ubiboot
离线fansgq

只看该作者 66楼 发表于: 2014-11-07
最新版(1.4.1)的下了,播放视频很容易崩溃。。。。
离线x_greatwall

只看该作者 65楼 发表于: 2014-09-27
太赞了,真是学习了
离线libin88211

只看该作者 64楼 发表于: 2014-07-23
楼主你好,我现在要实现播放视频文件中某指定两帧之间的视频段,或是指定时间段内的视频段能在您的这个类库基础上做吗?通过什么方式找到指定帧进行播放?如蒙答复不胜感激!
离线libin88211

只看该作者 63楼 发表于: 2014-07-23
楼主你好,你做的很不错,可以看出付出了很多努力,使用方法也很方便,但是希望您 有空了做一下文档,介绍一下类的接口使用方法,这样才有更多的人能够使用。
离线foruok

只看该作者 62楼 发表于: 2014-07-17
不知道是否可以用在 Android 上?
我的博客:http://blog.csdn.net/foruok
我的微信订阅号:程序视界
离线foruok

只看该作者 61楼 发表于: 2014-07-17
这个强悍的说,赞一个。
我的博客:http://blog.csdn.net/foruok
我的微信订阅号:程序视界
离线yangkun52131

只看该作者 60楼 发表于: 2014-07-16
解码器是最新的ffmpeg版本,我用任何一个版本都一样。有的视频没事。一般有色块的播放的时候都是同一个地方出现。
离线novesky

只看该作者 59楼 发表于: 2014-06-03
回 yangkun52131 的帖子
yangkun52131:播放器很不错。有个问题,视频有时候解码应该是滤镜不行,经常出现色块。还有同一个视频,若不加音轨两个视频竟然不同步。 (2014-05-30 16:27)

出现色块是QtAV哪个版本?什么视频什么解码器?
没音频的同步有问题我也发现了,平时都测有音频的
离线yangkun52131

只看该作者 58楼 发表于: 2014-05-30
播放器很不错。有个问题,视频有时候解码应该是滤镜不行,经常出现色块。还有同一个视频,若不加音轨两个视频竟然不同步。
离线a408815041

只看该作者 57楼 发表于: 2014-05-10
6666666
Qt专业定制, widget\qml。upnp\onvif\GB28181\播放器。
QQ: 408815041
email: zyb920@hotmail.com
离线xsjqqq123

只看该作者 56楼 发表于: 2014-03-22
Qt5.2.1 mingw的如何编译它啊?没学过编译原理之类的,业余爱好。那些depends如何处理?放在哪?
离线blueseait

只看该作者 55楼 发表于: 2014-03-11
我发现videographicsitem这个工程在mac上运行是有声音的,player没有声音,不知道怎么回事。
离线blueseait

只看该作者 54楼 发表于: 2014-03-07
谢谢楼主指导,按你的方法做程序在mac上面已经可以运行了,但是播放没有声音,只有视频,我用brew install portaudio 安装了portaudio也不行,不知道声音出来还需要怎么做,不好意思,mac和视频初学者又来麻烦缕主了,谢谢!
离线novesky

只看该作者 53楼 发表于: 2014-02-28
回 blueseait 的帖子
blueseait:你好楼主,感谢你一直以来的努力和对开源的支持,也让我等学到了不少关于视频方面的知识,最近想在mac ox上学习一下,用你的最新版本,设置了cpath|library_path等环境变量,编译通过了,但是运行出现找不到库的错误:
dyld: Library not loaded: @rpath/Frameworks/libQtAV.1.dyl .. (2014-02-26 14:35) 

要把libQtAV.1.dylib拷到player.app/Contents/Frameworks下。另外,最后用macdeployqt打包的话会有问题,要手工把QtCreator里相应的Qt库拷过来,qt的打包工具问题很多。
离线blueseait

只看该作者 52楼 发表于: 2014-02-26
我补充一下:我的编译和运行环境是Qt5.2.1,在qtcreator中设置的环境变量,并在qtcreator中编译和运行时出现上述问题的。望楼主不吝指教!
离线blueseait

只看该作者 51楼 发表于: 2014-02-26
你好楼主,感谢你一直以来的努力和对开源的支持,也让我等学到了不少关于视频方面的知识,最近想在mac ox上学习一下,用你的最新版本,设置了cpath|library_path等环境变量,编译通过了,但是运行出现找不到库的错误:
dyld: Library not loaded: @rpath/Frameworks/libQtAV.1.dylib
  Referenced from: /users/nphd/workspace/QtAV-master/build/bin/player.app/Contents/MacOS/player
  Reason: image not found
请问下楼主在mac上面编译运行需要做哪些设置才能正常运行,出现我这个问题是什么原因呢,谢谢楼主!

离线novesky

只看该作者 50楼 发表于: 2013-12-31
回 49楼(blueseait) 的帖子
有dxva相关的头文件和库,然后configure配置下,配置可以看我播放器 关于 对话框里的ffmpeg信息
离线blueseait

只看该作者 49楼 发表于: 2013-12-31
1.3版本功能上有很大进步,但是如果要支持dxva硬解码需要重新编译ffmpeg并且加入dxva的外部包支持,我在网上找了一下没有找到关于FFMPEG与DXVA结合编译的文章,不知道楼主可否指导一下如何如何编译出支持DXVA的FFMPEG?
离线chenjieat

只看该作者 48楼 发表于: 2013-12-26
太赞了,我的目标啊!
离线carmen816

只看该作者 47楼 发表于: 2013-12-19
Re:回 42楼(carmen816) 的帖子
引用第46楼novesky于2013-12-18 14:39发表的 回 42楼(carmen816) 的帖子 :
有QQ么?

离线novesky

只看该作者 46楼 发表于: 2013-12-18
回 42楼(carmen816) 的帖子
有QQ么?
离线novesky

只看该作者 45楼 发表于: 2013-12-18
回 42楼(carmen816) 的帖子
看了下vlc的相关代码,好复杂,不过发现AVCodecContext.skip_frame = AVDISCARD_NONREF就不会崩溃了。默认的AVDISCARD_DEFAULT
只是跳过无用的包。
离线novesky

只看该作者 44楼 发表于: 2013-12-18
回 42楼(carmen816) 的帖子
AVPacket只能判断是否含有关键帧,我把没关键帧的丢了,还是崩溃。
离线novesky

只看该作者 43楼 发表于: 2013-12-17
回 42楼(carmen816) 的帖子
恩,谢谢,我回去试下。你是搞多媒体的吗?很专业啊。
离线carmen816

只看该作者 42楼 发表于: 2013-12-17
Re:回 40楼(carmen816) 的帖子
引用第41楼novesky于2013-12-17 15:35发表的 回 40楼(carmen816) 的帖子 :
很感谢你的回复,很有价值。同步那块里面的数字阿什么的有些是随便写的。同时用绝对时间(比如系统时间)来同步也想过,不过有个问题就是如果音频慢了怎么办?是重采样来降低音频播放速度还是直接丢掉一部分?我还没试过。不知道你怎么看。
硬解的话我也猜到了会和前几帧相关,但是能否丢掉特殊的帧呢?看了下I、P、B都是互相联系的,好像丢什么都不行。这样的话seek时就有问题了,直接从中间某一帧开始解,会崩溃。
另外,渲染视频画面是在gui线程,不在解码线程,这个跟Qt有关。
其他的我回家再看看。

1.硬解的话我也猜到了会和前几帧相关,但是能否丢掉特殊的帧呢?看了下I、P、B都是互相联系的,好像丢什么都不行。这样的话seek时就有问题了,直接从中间某一帧开始解,会崩溃。
       seek后,下一个I 帧之前的数据全部丢弃。音频需要跟着同步。


2.另外,渲染视频画面是在gui线程,不在解码线程,这个跟Qt有关。
       最后渲染是在GUI线程没错,但是您对于帧的处理,超时丢弃,定时等待,格式转换,outputSet->sendVideoFrame,这些是在视频解码同一线程,并不是指最后画的过程。
        视频解码线程通常情况比较忙,应该在一个空闲线程控制上述过程。


离线novesky

只看该作者 41楼 发表于: 2013-12-17
回 40楼(carmen816) 的帖子
很感谢你的回复,很有价值。同步那块里面的数字阿什么的有些是随便写的。同时用绝对时间(比如系统时间)来同步也想过,不过有个问题就是如果音频慢了怎么办?是重采样来降低音频播放速度还是直接丢掉一部分?我还没试过。不知道你怎么看。
硬解的话我也猜到了会和前几帧相关,但是能否丢掉特殊的帧呢?看了下I、P、B都是互相联系的,好像丢什么都不行。这样的话seek时就有问题了,直接从中间某一帧开始解,会崩溃。
另外,渲染视频画面是在gui线程,不在解码线程,这个跟Qt有关。
其他的我回家再看看。
离线carmen816

只看该作者 40楼 发表于: 2013-12-17
Re:回 38楼(carmen816) 的帖子
引用第39楼novesky于2013-12-15 19:18发表的 回 38楼(carmen816) 的帖子 :
这个还真不知道,为什么要这么做?
不同步音频的话应该同步什么?系统时间?我现在的是有问题,来不及画的就丢掉


VideoThread.cpp
        qreal pts = pkt.pts;
        d.delay = pts - d.clock->value();
        /*
         *after seeking forward, a packet may be the old, v packet may be
         *the new packet, then the d.delay is very large, omit it.
         *TODO: 1. how to choose the value
         * 2. use last delay when seeking
        */
        bool skip_render = false;
        if (qAbs(d.delay) < 2.718) {
            if (d.delay < -kSyncThreshold) { //Speed up. drop frame?
                //continue;
            }
            while (d.delay > kSyncThreshold) { //Slow down
                //d.delay_cond.wait(&d.mutex, d.delay*1000); //replay may fail. why?
                //qDebug("~~~~~wating for %f msecs", d.delay*1000);
                usleep(kSyncThreshold * 1000000UL);
                if (d.stop)
                    d.delay = 0;
                else
                    d.delay -= kSyncThreshold;
            }
            if (d.delay > 0)
                usleep(d.delay * 1000000UL);
        } else { //when to drop off?
            qDebug("delay %f/%f", d.delay, d.clock->value());
            if (d.delay > 0) {
                msleep(64);
            } else {
                // FIXME: if continue without decoding, hw decoding may crash, why?
                //audio packet not cleaned up?
                //continue;
                skip_render = true;
            }
        }
        d.clock->updateVideoPts(pts); //here?
        if (d.stop) {
            qDebug("video thread stop before decode()");
            break;
        }

        if (!dec->decode(pkt.data)) {
            pkt = Packet();
            continue;
        } else {
            int undecoded = dec->undecodedSize();
            if (undecoded > 0) {
                pkt.data.remove(0, pkt.data.size() - undecoded);
            } else {
                pkt = Packet();
            }
        }


        if (skip_render)
            continue;


msleep(64); 25帧为例,1000 / 25 = 40,这边的64值得商榷。
您将解码和帧的刷新放在一个线程中,会影响同步。
解码过程消耗时间比较长,而且解码耗时不是个固定值。会影响“与kSyncThreshold比较”。
所以那些播放器会缓冲解码后的原始音视频数据
ffplay中,使用video_thread解码后queue_picture,放入队列。在video_refresh(另一个线程)中刷视频。


PS:FIXME: if continue without decoding, hw decoding may crash, why?
        软件解码不crash,播放也会出现花屏(或者是黑屏几帧,直到下个I帧出现,看解码器的优化程度)。
        因为视频的解码时,通常解码器会参考上一个包的结果。“hw decoder”或者“hw decoder与ffmpeg之间的连接”写的不健壮那就只能crash了。。。



AudioThread.cpp
        if (!dec->decode(pkt.data)) {
            qWarning("Decode audio failed");
            qreal dt = pkt.pts - d.last_pts;
            if (dt > 0.618 || dt < 0) {
                dt = 0;
            }
            //qDebug("sleep %f", dt);
            //TODO: avoid acummulative error. External clock?
            msleep((unsigned long)(dt*1000.0));
            pkt = Packet();
            d.last_pts = d.clock->value(); //not pkt.pts! the delay is updated!
            continue;
        }
        QByteArray decoded(dec->data());
        int decodedSize = decoded.size();
        int decodedPos = 0;
        qreal delay =0;
        //AudioFormat.durationForBytes() calculates int type internally. not accurate
        AudioFormat &af = dec->resampler()->inAudioFormat();
        qreal byte_rate = af.bytesPerSecond();
        while (decodedSize > 0) {
            if (d.stop) {
                qDebug("audio thread stop after decode()");
                break;
            }
            int chunk = qMin(decodedSize, int(max_len*byte_rate));
            //AudioFormat.bytesForDuration
            qreal chunk_delay = (qreal)chunk/(qreal)byte_rate;
            pkt.pts += chunk_delay;
            d.clock->updateDelay(delay += chunk_delay);

AVClock 默认是 ClockType AudioClock
int chunk = qMin(decodedSize, int(max_len*byte_rate)); --->>> 意味着AVClock每0.02秒更新一次。
这导致您设计的AVClock不是线性的,而是离散的(相对视频而言,如果视频帧是30帧,每个视频帧间隔0.033秒,时钟和帧间隔处于同一数量级。。。),造成丢帧。


不同步音频的话应该同步什么?系统时间?
音频时间和系统时间结合。。。
下面文章的方案和ffplay所使用的如出一辙
http://www.rosoo.net/a/201203/15806.html   (三、音视频同步)

PS:十分惊叹楼主在QT,C++,架构设计等方面的造诣,使我受益匪浅。
        再次感谢楼主开源的精神。

快速回复
限100 字节
 
上一个 下一个