当前位置: 首页 > 工具软件 > SoundTouch > 使用案例 >

ffplay使用soundtouch实现倍速播放

祁兴运
2023-12-01

ffplay自定义系列

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



前言

基于上一篇文章《ffplay使用sonic实现倍速播放》实现倍速播放后,想有个参照相对比下效果,所以用soundtouch也实现了ffplay的倍速播放。个人感觉效果比sonic要好。


一、soundtouch介绍

soundtouch是一个开源音频处理库,主要包含变速和变调功能,ijkplayer就是使用soundtouch实现视频变速的。
soundtouch是基于c++实现的,编译方式中提供了静态库和动态库。静态库提供c++形式的接口。动态库有c语言形式的函数包装提供,但其头文件添加了非c++错误宏,即一定要在c++环境中使用。


二、ffplay中使用soundtouch

由上述内容可知,虽然soundtouch有一套c语言接口,但soundtouch一定要在c++环境中使用。想在ffplay中使用只能再用c语言包装soundtouch,或者将ffplay改成c++实现。但是由于ffplay.c是完全基于c语言的语法,改成c++后需要修改的地方比较多,比较麻烦,故本文采用c语言包装soundtouch。

1、包装接口

下面是接口定义,实现根据具体需求,静态库则使用SoundTouch.h的类和对象,动态库则使用SoundTouchDLL.h中的c语言接口。

#ifndef CSOUNDTOUCH_H
#define CSOUNDTOUCH_H
#ifdef __cplusplus
extern "C" {
#endif
	typedef void* cSoundTouch;
	const char* cSoundTouch_getVersionString();
	int cSoundTouch_getVersionId();
	cSoundTouch cSoundTouch_create();
	void cSoundTouch_destroy(cSoundTouch soundTouch);
	void cSoundTouch_setRate(cSoundTouch soundTouch, double newRate);
	void cSoundTouch_setTempo(cSoundTouch soundTouch, double newTempo);
	void cSoundTouch_setRateChange(cSoundTouch soundTouch, double newRate);
	void cSoundTouch_setTempoChange(cSoundTouch soundTouch, double newTempo);
	void cSoundTouch_setPitch(cSoundTouch soundTouch, double newPitch);
	void cSoundTouch_setPitchOctaves(cSoundTouch soundTouch, double newPitch);
	void cSoundTouch_setPitchSemiTones(cSoundTouch soundTouch, int newPitch);
	void cSoundTouch_setChannels(cSoundTouch soundTouch, int numChannels);
	void cSoundTouch_setSampleRate(cSoundTouch soundTouch, int srate);
	double cSoundTouch_getInputOutputSampleRatio(cSoundTouch soundTouch);
	void cSoundTouch_flush(cSoundTouch soundTouch);
	void cSoundTouch_putSamples(cSoundTouch soundTouch, float* samples, int numSamples);
	void cSoundTouch_putSamples_i16(cSoundTouch soundTouch, short* samples, int numSamples);
	int cSoundTouch_receiveSamples(cSoundTouch soundTouch, float* output, int maxSamples);
	int cSoundTouch_receiveSamples_i16(cSoundTouch soundTouch, short* output, int maxSamples);
	void cSoundTouch_clear(cSoundTouch soundTouch);
	int cSoundTouch_setSetting(cSoundTouch soundTouch, int settingId, int value);
	int cSoundTouch_getSetting(cSoundTouch soundTouch, int settingId);
	int cSoundTouch_numUnprocessedSamples(cSoundTouch soundTouch);
	int cSoundTouch_numChannels(cSoundTouch soundTouch);
	int cSoundTouch_numSamples(cSoundTouch soundTouch);
#ifdef __cplusplus
};
#endif
#endif

2、初始化

根据上述接口直接调用cSoundTouch_create即可创建一个soundtouch对象。

(1)、定义字段

可以在VideoState中添加soundtouch 字段

cSoundTouch soundTouch;

(2)、初始化

在stream_component_open中case AVMEDIA_TYPE_AUDIO:的末尾初始化soundtouch。

is->soundTouch = cSoundTouch_create();
cSoundTouch_setSampleRate(is->soundTouch, sample_rate);
cSoundTouch_setChannels(is->soundTouch, nb_channels);

3、倍速处理

在audio_decode_frame中处理重采样后的音频数据,写回音频数据,并调整相关参数。

(1)、定义字段

倍速处理时需要一个速度参数。并且当处理后的数据过大时需要建立新的缓冲区,需要定义一个自己的缓冲区。

double speed;
char* speed_buf;
int speed_buf_size;

(2)、处理数据

在audio_decode_frame中重采样后,更新时钟之前放置如下代码

double speed = is->speed;
	if (speed != 1)
	{
		//设置倍速
		cSoundTouch_setTempo(is->soundTouch, speed);
		//写入音频数据
		cSoundTouch_putSamples_i16(is->soundTouch, is->audio_buf, af->frame->nb_samples);	
		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 = cSoundTouch_receiveSamples_i16(is->soundTouch, is->audio_buf, numSamples);
		//更新参数
		resampled_data_size = new_nb_samples * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
		af->frame->nb_samples = numSamples;
	}

4、释放资源

在stream_component_close中的case AVMEDIA_TYPE_AUDIO中释放资源

if (is->speed_buf)
{
	av_free(is->speed_buf);
	is->speed_buf = NULL;
}
if (is->soundTouch)
{
	cSoundTouch_destroy(is->soundTouch);
	is->soundTouch = NULL;
}

三、附录

soundtouch官网有提供生源码以及成好的库下载:http://www.surina.net/soundtouch/download.html

 类似资料: