使用ffmpeg和sdl实现多路音频混合播放

24 篇文章 3 订阅


前言

音频的播放通常是单例的,在进程内通常一个播放设备只能打开一次,且只支持一个写入。写播放器的时候,会遇到需要实现多开同时播放多个视频,比如视频剪辑工具的多轨道播放。这个时候就需要采用一定的方法,比如音频混合。本文将提供一种基于ffmpeg和sdl实现的音频多路混合的方法。


一、 如何实现?

1、回调式打开设备

为实现多路共用一个播放设备,只能采用SDL的回调式打开音频设备。
回调方法

static std::map<void*, std::function<void(void* userdata, Uint8* stream, int len)>> _audioCallbacks;//记录每一路音频的回调方法
//总的回调方法
static void _audio_callback_sum(void* userdata, uint8_t* stream, int len)
{
	memset(stream, 0, len);
	std::unique_lock< std::mutex >lck(_mtx);
	//调用每一路的回调方法
	for (auto i : _audioCallbacks)
	{
		i.second(userdata, stream, len);
	}
}

打开音频

static SDL_AudioSpec _wanted_spec, _spec;
_wanted_spec.channels = 2;
_wanted_spec.freq = 44100;
_wanted_spec.format = AUDIO_F32SYS;
_wanted_spec.silence = 0;
_wanted_spec.samples = 1024;
_wanted_spec.callback = _audio_callback_sum;
 SDL_OpenAudio(&_wanted_spec, &_spec) == 0;

2、注册多路回调

注册一路音频回调示例如下

_audioCallbacks[pFrame] = [&](void* userdata, Uint8* stream, int len) {
	//此处实现单独一路的播放逻辑
	
};

3、写入队列

每一路音频都创建一个音频队列,将解码的音频数据写入队列,下面是使用AVAudioFifo作为音频队列的例子。

if (av_audio_fifo_space(fifo) >= samples)
{
	av_audio_fifo_write(fifo, (void**)&data, (int)samples);
	break;
}

4、混合音频

在音频单独的回调中即上面_audioCallbacks注册的方法中,进行数据混合,示例如下。

//读取音频队列数据 
int read = av_audio_fifo_read(fifo, (void**)&data, _spec.samples);
//开始混合
SDL_MixAudioFormat(stream, data, _spec.format, newLen, SDL_MIX_MAXVOLUME);

二、完整代码

1、头文件

simple_audio_play.h

#pragma once
/// <summary>
/// 播放音频
/// 此方法同步阻塞,播放完成后返回
/// 支持多路播放,可放在线程中播放,线程安全。
/// </summary>
/// <param name="input">输入url</param>
/// <param name="exitFlag">中断标记</param>
/// <returns></returns>
int simple_audio_play(const char* input, int* exitFlag)

2、具体实现

https://download.csdn.net/download/u013113678/87873259


三、使用示例

1、播放音频

int exitflag= false;	
simple_audio_play("D:\\test_music.wav", &exitflag);

2、多路播放音频

#include"simple_audio_play.h"
void main() {
	int exitflag = false;
	auto t1 = new std::thread([&]() {
		while (!exitflag) {
			simple_audio_play("D:\\test_music.wav", &exitflag);
		}
		});
	auto t2 = new std::thread([&]() {
		while (!exitflag) {
			simple_audio_play("D:\\test.mp4", &exitflag);
		}
		});
	system("pause");
	exitflag = true;
	t1->join();
	t2->join();
}

总结

以上就是今天要的内容了,采用ffmpeg结合sdl实现音频多路播放还是比较容易的,都有相关的接口去调用,只要设计实现整体的上层逻辑即可。但是一开始基本没有头绪,通过一番尝试后找到关键方法SDL_MixAudioFormat后,实现起来还是很简单的,这个是实践才能得到的知识。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CodeOfCC

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

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

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

打赏作者

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

抵扣说明:

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

余额充值