前言
曾经为实现倍速播放使用过ffmpeg,对音频使用atempo滤镜即可实现变速不变调。但是当时效果并不是特别好,和soundtouch相比处理后的音质有明显的区别。最近用新版本的ffmpeg滤镜重新实现了倍速播放,发现效果变好,已经达到可接受的程度,所以在此分享具体实现。
一、ffmpeg滤镜
ffmpeg倍速滤镜一般可以用下面这几个:
(1)视频
setpts=0.5*PTS
(2)音频
atempo = 2.0
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
二、ffplay中使用滤镜
在ffplay中可以直接使用ffmpeg的滤镜,在这里实现倍速播放我们只需要处理音频,然后让时钟同步到音频即可。没有音频的情况比较简单,只需要修改视频的pts即可,这里不做说明。
1、定义字段
在VideoState中添加滤镜刷新字段,用以实现动态控制倍速。
默认值为0,当值为1时则刷新滤镜。
int req_afilter_reconfigure;
2、设置滤镜
直接使用音频滤镜即可,atempo的取值范围是0.5-2.0即倍速值。
afilters = "atempo=2";
定义一个设置倍速方法,方便使用。(作为示例没有加线程安全机制)
void set_speed(double value)
{
if (value < 0.5 || value>2)
return;
VideoState* is = (VideoState*)play;
is->speed = value;
#if CONFIG_AVFILTER
if (!is->afilters)
{
is->afilters = av_malloc(32);
}
sprintf(is->afilters, "atempo=%lf", value);
is->req_afilter_reconfigure = 1;
#endif
}
3、更新滤镜
修改了倍速后,需要播放器动态响应。在ffplay的audio_thread中已经有了更新滤镜的机制,如果音频参数修改了则会进行滤镜更新,我们只需要使用上面定义的req_afilter_reconfigure来触发其更新滤镜即可。代码如下:(作为示例没有加线程安全机制)
![](/qrcode.jpg)
if (reconfigure||is->req_afilter_reconfigure) {
is->req_afilter_reconfigure = 0;
//ffplay更新滤镜源码
}
4、调整时钟
经过滤镜处理的数据得到的avframe时间戳pts以及pkt_pos也被相应的调整了,在ffplay中播放效果是声音变快了,但时钟不变,画面也按照原来速度播放,这肯定是不符合需求的,所以需要重新调整时间相关参数。其实有一种方法,直接使用滤镜处理前的时间参数即可:由于倍速处理后nb_samples和bufferSize都变了,而时间参数(pts以及pkt_pos)不变就会使得sdl_audio_callback同步时钟发生相应变化。
在audio_thread中:
先记录avframe原来的参数
//使用原来的pts
double pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
double pos = frame->pkt_pos;
int serial = is->auddec.pkt_serial;
double duration = av_q2d((AVRational) { frame->nb_samples, frame->sample_rate });
//使用原来的pts --end
滤镜处理后使用原来的参数
//使用原来的pts
af->pts = pts;// (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
af->pos = pos;//frame->pkt_pos;
af->serial = serial;// is->auddec.pkt_serial;
af->duration = duration;// av_q2d((AVRational) { frame->nb_samples, frame->sample_rate });
//使用原来的pts --end
5、释放资源
由于上述方法中afilters指向的是av_malloc的空间,所以关闭播放器时需要将其释放。
在stream_close中添加
#if CONFIG_AVFILTER
if (is->afilters)
{
av_free(is->afilters);
is->afilters = NULL;
}
#endif
如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓