亲宝软件园·资讯

展开

Qt音视频开发之利用ffmpeg实现倍速播放

feiyangqingyun 人气:0

一、前言

用ffmpeg做倍速播放,是好多年都一直没有实现的功能,有个做法是根据倍速参数,不断切换播放位置,实现效果不是很好,ffplay中的倍速就做得很好,而且声音无论倍速多少还非常柔和,有特别的降噪处理啥的,ffplay中的倍速使用的滤镜去实现,并动态调整pts/dts的值,整个处理过程看起来比较复杂,想着有没有稍微简单一点的办法,在经过一个朋友的指点下,发现在音视频同步的地方,对计算显示时间差值的时候乘以倍速比例,就可以实现倍速效果,立马测试立马见到效果,这个和动态调整pts值效果类似,无非就是让播放的时间进行倍速调整。所以这个倍速的功能推迟了好几年终于实现了,之前由于一直没有特别强烈的倍速需求推迟这没有去实现。这样实现的倍速唯一的缺点就是声音在慢速快速播放中会有停顿效果不够平滑柔和,也就是没有变调,在经过几次其他播放器比如vlc/mpv等,也有类似的问题,有部分播放器索性在非正常速度播放情况下音频直接拒绝播放,都不敢直接面对。

为了验证倍速是否和预期的效果完全一致,比如30帧的视频,0.5倍速意味着一秒钟解析15张,2倍速意味着一秒钟解析60帧,依次类推,特意统计了打印信息,发现和预想的完全一致,4倍速确实解析了120张图片,不过这种处理感觉是很占资源,可以考虑直接跳帧播放,尤其是找到关键帧跳跃播放,这样可以节约很多资源,1倍速及以下倍速,可以将所有图片解析,但是快速播放没有必要将所有的解析绘制显示,后期可以考虑将这两种方式都支持。

二、功能特点

2.1 基础功能

2.2 特色功能

2.3 视频控件

2.4 内核ffmpeg

三、体验地址

国内站点:https://gitee.com/feiyangqingyun

国际站点:https://github.com/feiyangqingyun

体验地址:http://pan.baidu.com/s/1YOVD8nkoOSYwX9KgSauLeQ 提取码:kcgz 文件名:bin_video_demo/bin_linux_video。

四、效果图

五、相关代码

bool FFmpegSync::checkPtsTime()
{
    //下面这几个时间值是参考的别人的
    bool ok = false;
    if (ptsTime > 0) {
        if (ptsTime > offsetTime + 100000) {
            bufferTime = ptsTime - offsetTime + 100000;
        }

        int offset = (type == 0 ? 1000 : 5000);
        //做梦都想不到倍速播放就这里控制个系数就行
        offsetTime = (av_gettime() - startTime) * thread->speed + bufferTime;
        if ((offsetTime <= ptsTime && ptsTime - offsetTime <= offset) || (offsetTime > ptsTime)) {
            ok = true;
        }
    } else {
        ok = true;
    }

    return ok;
}

void FFmpegSync::checkShowTime()
{
    //必须是文件(本地文件或网络文件)才有播放进度
    if (!thread->getIsFile()) {
        return;
    }

    //过滤重复发送播放时间
    bool showPosition = false;
    bool existVideo = (thread->videoIndex >= 0);
    if (type == 0) {
        //音频同步线程不能存在视频
        if (!existVideo) {
            showPosition = true;
        }
    } else if (type == 1) {
        //视频同步线程必须存在视频
        if (existVideo) {
            showPosition = true;
        }
    }

    //需要显示时间的时候发送对应进度(限定差值大于200毫秒没必要频繁发送)
    if (showPosition && (offsetTime - showTime > 200000)) {
        showTime = offsetTime;
        thread->position = showTime / 1000;
        emit receivePosition(thread->position);
    }
}

加载全部内容

相关教程
猜你喜欢
用户评论