目录

音频倍速实现

初始化操作

音频倍速接口实现

视频倍速实现

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中函数详解

  1. int sonicWriteShortToStream(sonicStream stream, short *samples, int numSamples);

    参数说明:

    stream:sonicStream类型,指向已初始化的Sonic音频流对象,由sonicCreateStream创建
    samples:sonic的输入缓冲区,类型为short*,存放重采样后的pcm数据,每个存储单元为一             个采样点或按声道顺序排列的多声道采样点(如立体声按左、右声道交替存储)。
    numSamples:每声道的总采样点数(例如2声道的总采样点数为:numSamples * 2)
    返回值:
    1:成功将数据写入流的输入缓冲区。
    0:失败(通常是内存分配失败,如缓冲区扩容失败)。

  2. int sonicReadShortFromStream(sonicStream stream, short *samples, int maxSamples);

    参数说明:
    stream:sonicStream类型,指向已初始化的Sonic音频流对象,由sonicCreateStream创建
    samples:sonic的输出缓冲区,类型为short*,存放sonic处理后的pcm数据,输出数据格式与            输入一致(单声道 / 多声道按顺序排列)。
    maxSampes:输出缓冲区可接收的最大采样点总数(按单声道计算)。实际写入的采样点数            量不会超过该值,避免缓冲区溢出。
    返回值:
    成功:实际读取的采样点总数(按单声道计算)。
    0     :当前输出缓冲区中没有可读取的数据(不代表错误,可能需要继续写入输入数据或等            待处理)。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐