C語(yǔ)言使用ffmpeg和sdl實(shí)現(xiàn)多路音頻播放
前言
音頻的播放通常是單例的,在進(jìn)程內(nèi)通常一個(gè)播放設(shè)備只能打開(kāi)一次,且只支持一個(gè)寫(xiě)入。寫(xiě)播放器的時(shí)候,會(huì)遇到需要實(shí)現(xiàn)多開(kāi)同時(shí)播放多個(gè)視頻,比如視頻剪輯工具的多軌道播放。這個(gè)時(shí)候就需要采用一定的方法,比如音頻混合。本文將提供一種基于ffmpeg和sdl實(shí)現(xiàn)的音頻多路混合的方法。
一、 如何實(shí)現(xiàn)
1、回調(diào)式打開(kāi)設(shè)備
為實(shí)現(xiàn)多路共用一個(gè)播放設(shè)備,只能采用SDL的回調(diào)式打開(kāi)音頻設(shè)備。
回調(diào)方法
static std::map<void*, std::function<void(void* userdata, Uint8* stream, int len)>> _audioCallbacks;//記錄每一路音頻的回調(diào)方法 //總的回調(diào)方法 static void _audio_callback_sum(void* userdata, uint8_t* stream, int len) { memset(stream, 0, len); std::unique_lock< std::mutex >lck(_mtx); //調(diào)用每一路的回調(diào)方法 for (auto i : _audioCallbacks) { i.second(userdata, stream, len); } }
打開(kāi)音頻
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、注冊(cè)多路回調(diào)
注冊(cè)一路音頻回調(diào)示例如下
_audioCallbacks[pFrame] = [&](void* userdata, Uint8* stream, int len) { //此處實(shí)現(xiàn)單獨(dú)一路的播放邏輯 };
3、寫(xiě)入隊(duì)列
每一路音頻都創(chuàng)建一個(gè)音頻隊(duì)列,將解碼的音頻數(shù)據(jù)寫(xiě)入隊(duì)列,下面是使用AVAudioFifo作為音頻隊(duì)列的例子。
if (av_audio_fifo_space(fifo) >= samples) { av_audio_fifo_write(fifo, (void**)&data, (int)samples); break; }
4、混合音頻
在音頻單獨(dú)的回調(diào)中即上面_audioCallbacks注冊(cè)的方法中,進(jìn)行數(shù)據(jù)混合,示例如下。
//讀取音頻隊(duì)列數(shù)據(jù) int read = av_audio_fifo_read(fifo, (void**)&data, _spec.samples); //開(kāi)始混合 SDL_MixAudioFormat(stream, data, _spec.format, newLen, SDL_MIX_MAXVOLUME);
二、完整代碼
1、頭文件
simple_audio_play.h
#pragma once /// <summary> /// 播放音頻 /// 此方法同步阻塞,播放完成后返回 /// 支持多路播放,可放在線(xiàn)程中播放,線(xiàn)程安全。 /// </summary> /// <param name="input">輸入url</param> /// <param name="exitFlag">中斷標(biāo)記</param> /// <returns></returns> int simple_audio_play(const char* input, int* exitFlag)
三、使用示例
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(); }
總結(jié)
以上就是今天要的內(nèi)容了,采用ffmpeg結(jié)合sdl實(shí)現(xiàn)音頻多路播放還是比較容易的,都有相關(guān)的接口去調(diào)用,只要設(shè)計(jì)實(shí)現(xiàn)整體的上層邏輯即可。但是一開(kāi)始基本沒(méi)有頭緒,通過(guò)一番嘗試后找到關(guān)鍵方法SDL_MixAudioFormat后,實(shí)現(xiàn)起來(lái)還是很簡(jiǎn)單的,這個(gè)是實(shí)踐才能得到的知識(shí)。
到此這篇關(guān)于C語(yǔ)言使用ffmpeg和sdl實(shí)現(xiàn)多路音頻播放的文章就介紹到這了,更多相關(guān)C語(yǔ)言多路音頻播放內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vs2019 MFC實(shí)現(xiàn)office界面的畫(huà)圖小項(xiàng)目
本文主要介紹了vs2019 MFC實(shí)現(xiàn)office界面的畫(huà)圖小項(xiàng)目,對(duì)大家入門(mén)有一定的幫助,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06Matlab實(shí)現(xiàn)灰色預(yù)測(cè)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Matlab實(shí)現(xiàn)灰色預(yù)測(cè),文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以了解一下2022-05-05C++簡(jiǎn)單實(shí)現(xiàn)Dijkstra算法
這篇文章主要為大家詳細(xì)介紹了C++簡(jiǎn)單實(shí)現(xiàn)Dijkstra算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05OpenCV實(shí)戰(zhàn)之基于Hu矩實(shí)現(xiàn)輪廓匹配
這篇文章主要介紹了利用C++ OpenCV實(shí)現(xiàn)基于Hu矩的輪廓匹配,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)OpenCV有一定的幫助,感興趣的可以學(xué)習(xí)一下2022-01-01簡(jiǎn)單對(duì)比C語(yǔ)言中的fputs()函數(shù)和fputc()函數(shù)
這篇文章主要介紹了簡(jiǎn)單對(duì)比C語(yǔ)言中的fputs()函數(shù)和fputc()函數(shù),注意其之間的區(qū)別,需要的朋友可以參考下2015-08-08