采用sonic库实现音频倍速播放(变速不变调)
目录
音频倍速实现
对重采样后的音频进行处理
while (!isExit) {
AVFrame *frame =adecode->Recv();
if (!frame) {
break;
}
pts = adecode->pts - ap->GetNoPlayMs();
//重采样
int size = res->StartResample(frame, pcm);
if (size <= 0) {
//av_frame_free(&frame);
break;
}
int numSamplesPerChannel = size / (2 * audioChannels);;
// 拷贝 PCM 数据到 short 缓冲区
//size/2为采样点总数,而在sonic的输入缓冲为short类型的数组,每个元素对应一个采样点
memcpy(sonicInput, pcm, (size/2)*sizeof(short));
// 写入 sonic (自动处理多声道交错)
sonicWriteShortToStream(sonic, sonicInput, numSamplesPerChannel);
// 从sonic读取处理后的音频,返回每通道的采样点数
int outSamples = 0;
int outSize = 0; // 转回字节数
//outSize = outSamples * 2 * audioChannels;//计算总字节数
while (!isExit) {
outSamples = sonicReadShortFromStream(sonic, sonicOutput, maxSamples / 2);
if (outSamples <= 0) break;
outSize += outSamples * 2 * audioChannels;//计算总字节数
}
// 播放处理后的音频
while (!isExit && outSize > 0) {
if (outSize > ap->GetFree()) {
msleep(1);
continue;
}
if (ap) {
ap->Write((unsigned char*)sonicOutput, outSize);
}
break;
}
}
重采样之后得到pcm数据,在pcm缓冲区中,然后计算每通道的采样总数
将pcm数据拷贝到sonic的输入缓冲区sonicInput
然后写入sonic进行处理sonicWriteShortToStream
读取处理后的pcm数据到sonic输出缓冲区中
最后将pcm数据写入QAudioOutput缓冲区播放
初始化操作
if (pcm) delete[] pcm;
if (sonicInput) delete[] sonicInput;
if (sonicOutput) delete[] sonicOutput;
audioChannels = param->channels;
maxSamples = param->sample_rate * 2 * param->channels; // 2秒缓冲
pcm = new unsigned char[maxSamples * 2]; // 16位采样
sonicInput = new short[maxSamples]; // 16位采样
sonicOutput = new short[maxSamples]; // 16位采样
// 初始化sonic
if (sonic) {
sonicDestroyStream(sonic);
}
sonic = sonicCreateStream(param->sample_rate, param->channels);
sonicSetSpeed(sonic, speed); // 默认1倍速
sonicSetPitch(sonic, 1.0f); // 保持音调不变
sonicSetRate(sonic, 1.0f); // 保持采样率不变
sonicSetVolume(sonic, 1.0f); // 音量设为1.0
sonicSetQuality(sonic, 0); // 高质量模式
每次打开文件delete掉上一次的缓冲区记录通道数,动态设置缓冲区大小,重新开辟缓冲区
初始化sonic
音频倍速接口实现
void AudioThread::setSpeed(float speed)
{
mux.lock();
this->speed = speed;
if (sonic) {
sonicSetSpeed(sonic, speed);
}
mux.unlock();
}
通过接口设置sonic倍速
视频倍速实现
首先音视频同步采用的时以音频时钟为基准,视频向音频对齐
if (frame_last_pts == 0) {
delay = 0;
}
else
{
delay = (frame->pts - frame_last_pts)/speed;
}
//当理论帧间隔不合理时采用上一帧的帧间隔
if (delay <= 0 || delay >= 1000.0) {
/* if incorrect delay, use previous one */
delay = frame_last_delay;
}
frame_last_delay = delay;
frame_last_pts = frame->pts;
diff = (frame->pts - synpts)/speed;
- 每次计算理论帧间隔时需要考虑倍速
- 在计算视频与音频时钟差值diff时需要考虑倍速
同时添加改变speed的接口,其余部分无需改变
详细代码介绍参考上一篇博客:https://blog.csdn.net/m0_62092496/article/details/151289799?spm=1001.2014.3001.5501
sonic中函数详解
-
int sonicWriteShortToStream(sonicStream stream, short *samples, int numSamples);参数说明:
stream:sonicStream类型,指向已初始化的Sonic音频流对象,由sonicCreateStream创建
samples:sonic的输入缓冲区,类型为short*,存放重采样后的pcm数据,每个存储单元为一 个采样点或按声道顺序排列的多声道采样点(如立体声按左、右声道交替存储)。
numSamples:每声道的总采样点数(例如2声道的总采样点数为:numSamples * 2)
返回值:
1:成功将数据写入流的输入缓冲区。
0:失败(通常是内存分配失败,如缓冲区扩容失败)。 -
int sonicReadShortFromStream(sonicStream stream, short *samples, int maxSamples);参数说明:
stream:sonicStream类型,指向已初始化的Sonic音频流对象,由sonicCreateStream创建
samples:sonic的输出缓冲区,类型为short*,存放sonic处理后的pcm数据,输出数据格式与 输入一致(单声道 / 多声道按顺序排列)。
maxSampes:输出缓冲区可接收的最大采样点总数(按单声道计算)。实际写入的采样点数 量不会超过该值,避免缓冲区溢出。
返回值:
成功:实际读取的采样点总数(按单声道计算)。
0 :当前输出缓冲区中没有可读取的数据(不代表错误,可能需要继续写入输入数据或等 待处理)。
更多推荐



所有评论(0)