ffplay使用sonic实现倍速播放

ffplay自定义系列

第一章 自定义播放器接口
第二章 倍速播放(本章)
______第一节 sonic实现倍速播放(本节)
______第二节 soundtouch实现倍速播放
______第三节 ffmpeg滤镜实现倍速播放
第三章 dxva2硬解渲染
第四章 提供C#接口
第五章 制作wpf播放器



前言

现在的播放器通常都需要倍速播放功能,而且声音要求变速不变调。一般来说视频可以通过修改pts加速播放,音频如果通过修改采样率加速播放则会出现变调的现象,所以视频变速功能主要是实现音频的变速。音频要做到变速不变调,就要对音频数据进行一定的压缩或者拓展,我们可以使用一些音频处理库来达这种效果,比如谷歌的sonic。


一、sonic的基本用法

//创建对象
sonicStream sncStream=sonicCreateStream(sample_rate, nb_channels);
//设置倍速
sonicSetSpeed(sncStream, 1.25);
//写入音频裸流
int ret = sonicWriteFloatToStream(sncStream,audio_buf, nb_samples);
int numSamples = af->frame->nb_samples / speed;
if (ret) {
		// 从流中读取处理好的数据
		int new_nb_samples = sonicReadFloatFromStream(sncStream, audio_buf, numSamples);
	}
//销毁对象
sonicDestroyStream(is->sncStream);

二、ffplay中使用sonic

要实现倍速有一个做法是,只对声音处理,把处理后的nb_samples更新给播放器 ,并且时钟同步到音频,这样视频也会跟踪音频一起改变速度。

在ffplay中对音频数据进行处理,有两个地方比较适合,一个是音频重采样方法audio_decode_frame中,还一个是音频设备回调方法sdl_audio_callback中。这里我们选择在audio_decode_frame中对音频数据进行倍速处理。

1、初始化sonicStream

(1)、定义字段:

可以在VideoState中添加sonicStream 字段

sonicStream sncStream
(2)、初始化

初始化方法可以放在stream_component_open中伪代码如下:

static int stream_component_open(VideoState* is, int stream_index)
{    
	...ffplay源代码
	switch (avctx->codec_type) {
	case AVMEDIA_TYPE_AUDIO:
		...ffplay源代码
	    //初始化sonicStream
		is->sncStream = sonicCreateStream(sample_rate, nb_channels);
		break;
	}
}

2、倍速处理

在audio_decode_frame中重采样后的音频数据回放在is->audio_buf指向的数据中,我们只需要对其处理即可。如果倍速大于1,则直接写回is->audio_buf指向的缓冲区,如果小于1则新建一个缓冲区装载数据,然后让is->audio_buf指向此缓冲区。

(1)、定义字段

在VideoState中定义速度参数以及数据缓冲区。

double speed;
char*  speed_buf;
int    speed_buf_size;

(2)、处理数据

在audio_decode_frame中重采样后倍速处理,下列代码位置放在重采样后,更新时钟之前。

double speed = is->speed;	
if (speed != 1)
{
	//设置倍速
	sonicSetSpeed(is->sncStream, speed);
	sonicSetQuality(is->sncStream, 1);
	//写入音频数据
	int ret = sonicWriteShortToStream(is->sncStream, is->audio_buf, af->frame->nb_samples);
	if (ret) {
		//计算新的nb_samples,乘以2是为了保证sonicReadShortFromStream能一次读取全部的数据,否则可能造成累计延迟。
		int numSamples = 2 * af->frame->nb_samples / speed;
		if (speed < 1)
			//倍速小于1时使用自己的缓冲区
		{
			//计算缓冲区大小
			int size = numSamples * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
			if (is->speed_buf_size < size)
			{
				is->speed_buf = av_realloc(is->speed_buf, size);
				is->speed_buf_size = size;
			}
			is->audio_buf = is->speed_buf;
		}
		//读取处理后的数据
		int new_nb_samples = sonicReadShortFromStream(is->sncStream, is->audio_buf, numSamples);
		//重新计算数据大小
		resampled_data_size = new_nb_samples * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
		//设置新的nb_samples
		af->frame->nb_samples = new_nb_samples;
	}
}

3、释放资源

在stream_component_close中的case AVMEDIA_TYPE_AUDIO中释放资源

if (is->speed_buf)
	{
		av_free(is->speed_buf);
		is->speed_buf = NULL;
	}
if (is->sncStream) {
		sonicDestroyStream(is->sncStream);
        is->sncStream=NULL;
	}

三、参考

sonic的使用参考了这篇文章,里边附有sonic.c的完整源码

音频倍速(变速不变调)的实现_小伙儿在这儿烤地瓜-CSDN博客_音频变速不变调

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeOfCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值