基于上一篇文章《ffplay使用sonic实现倍速播放》实现倍速播放后,想有个参照相对比下效果,所以用soundtouch也实现了ffplay的倍速播放。个人感觉效果比sonic要好。
soundtouch是一个开源音频处理库,主要包含变速和变调功能,ijkplayer就是使用soundtouch实现视频变速的。
soundtouch是基于c++实现的,编译方式中提供了静态库和动态库。静态库提供c++形式的接口。动态库有c语言形式的函数包装提供,但其头文件添加了非c++错误宏,即一定要在c++环境中使用。
由上述内容可知,虽然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
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
根据上述接口直接调用cSoundTouch_create即可创建一个soundtouch对象。
可以在VideoState中添加soundtouch 字段
cSoundTouch soundTouch;
在stream_component_open中case AVMEDIA_TYPE_AUDIO:的末尾初始化soundtouch。
is->soundTouch = cSoundTouch_create();
cSoundTouch_setSampleRate(is->soundTouch, sample_rate);
cSoundTouch_setChannels(is->soundTouch, nb_channels);
在audio_decode_frame中处理重采样后的音频数据,写回音频数据,并调整相关参数。
倍速处理时需要一个速度参数。并且当处理后的数据过大时需要建立新的缓冲区,需要定义一个自己的缓冲区。
double speed;
char* speed_buf;
int speed_buf_size;
在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;
}
在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;
}
如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓