<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SDL播放音頻PCM

          共 8960字,需瀏覽 18分鐘

           ·

          2024-03-25 12:00

          0f2c438694136e1cdcba7180ac22edf8.webp

          PS:從思維中解放出來的開始就是認識到你不是一個思考問題的實體——思考者

          SDL 是一個很好用跨平臺多媒體開發(fā)庫,可以方便的使用 SDL 來學習音視頻,本文將介紹如何使用 SDL 播放 PCM 數(shù)據(jù),主要內容如下:

          1. SDL介紹

          2. SDL_AudioSpec

          3. SDL_AudioCallback

          4. FFmpeg提取PCM數(shù)據(jù)

          5. 播放本地PCM文件

          SDL介紹

          SDL(Simple DirectMedia Layer)是一套開放源代碼的跨平臺多媒體開發(fā)庫,使用 C 語言編寫,SDL 提供了數(shù)種控制圖像、聲音、輸出入的函數(shù),讓開發(fā)者只要用相同或是相似的代碼就可以開發(fā)出跨多個平臺(Linux、Windows、Mac OS X等)的應用軟件,目前 SDL 多用于開發(fā)游戲、模擬器、媒體播放器等多媒體應用領域,其架構圖如下:

          dd357cab78e2e5c9fed0b36e501167ef.webp

          后續(xù)主要是借助 SDL 來測試音頻、視頻的播放功能,后面中提到的 SDL 都是用的 SDL2 版本。

          SDL_AudioSpec

          SDL_AudioSpec 是 SDL 中表示音頻輸出格式的一個結構體,同時也包含當前音頻設備需要更多數(shù)據(jù)時調用的回調函數(shù),其定義如下:

                

          1/**
          2 *  The calculated values in this structure are calculated by SDL_OpenAudio().
          3 *  For multi-channel audio, the default SDL channel mapping is:
          4 *  2:  FL FR                       (stereo)
          5 *  3:  FL FR LFE                   (2.1 surround)
          6 *  4:  FL FR BL BR                 (quad)
          7 *  5:  FL FR LFE BL BR             (4.1 surround)
          8 *  6:  FL FR FC LFE SL SR          (5.1 surround - last two can also be BL BR)
          9 *  7:  FL FR FC LFE BC SL SR       (6.1 surround)
          10 *  8:  FL FR FC LFE BL BR SL SR    (7.1 surround)
          11 */

          12typedef struct SDL_AudioSpec{
          13    int freq;                   /**< DSP frequency -- samples per second */
          14    SDL_AudioFormat format;     /**< Audio data format */              
          15    Uint8 channels;             /**< Number of channels: 1 mono, 2 stereo */ 
          16    Uint8 silence;              /**< Audio buffer silence value (calculated) */
          17    Uint16 samples;             /**< Audio buffer size in sample FRAMES (total samples divided by channel count) */
          18    Uint16 padding;             /**< Necessary for some compile environments */
          19    Uint32 size;                /**< Audio buffer size in bytes (calculated) */
          20    SDL_AudioCallback callback; /**< Callback that feeds the audio device (NULL to use SDL_QueueAudio()). */
          21    void *userdata;             /**< Userdata passed to callback (ignored for NULL callbacks). */
          22} SDL_AudioSpec;

          SDL_AudioSpec具體信息如下:

          • freq:音頻采樣率,即每秒采樣數(shù),單位 Hz,采樣率越高,音頻質量越好,但占用的帶寬和存儲空間也越大。

          • format:音頻數(shù)據(jù)格式。

          • channels:音頻通道數(shù),常見的如 1 表示單聲道,2 表示立體聲。

          • silence:表示靜音音量值,常為 0。

          • samples:采樣幀的音頻緩沖區(qū)大小,以采樣數(shù)量為單位,可以看[[關于采樣的理解]]。

          • padding:內部填充字段,不需要使用,一般用于兼容。

          • size:音頻緩沖區(qū)總大小,以字節(jié)數(shù)為單位。用于表示緩沖區(qū)能夠容納的音頻數(shù)據(jù)的最大量,這個字段的值通常等于 samples * channels * format / 8。

          • callback:填充音頻緩沖區(qū)的回調函數(shù)。

          SDL_AudioCallback

          SDL_AudioCallbackSDL_AudioSpec結構體中的回調函數(shù),在音頻設備需要數(shù)據(jù)的時候回調該函數(shù),定義如下:

                

          1typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,int len);

          SDL_AudioCallback 回調函數(shù)參數(shù)如下:

          • userdata:用戶自定義數(shù)據(jù)。

          • stream:該指針指向需要填充的音頻緩沖區(qū),回調函數(shù)需要通過填充這個緩沖區(qū)中的數(shù)據(jù)來提供音頻信息。

            • 對于播放音頻而言,緩沖區(qū)中的數(shù)據(jù)需要被播放出來。

            • 對于錄制音頻而言,數(shù)據(jù)則需要被寫入到音頻文件中。

          • len:音頻緩沖區(qū)大小,以字節(jié)為單位,回調函數(shù)需要在這個緩沖區(qū)中填充 len 個字節(jié)的音頻數(shù)據(jù)。

          SDL_AudioCallback 回調函數(shù)的簡單實現(xiàn)見下文案例。

          FFmpeg提取PCM數(shù)據(jù)

          先使用 FFmpeg 提取用來測試的 PCM 數(shù)據(jù),通過如下命令從 mp4 文件中提取 20s 的 pcm 音頻數(shù)據(jù),如下:

                

          1ffmpeg -i xxx.mp4 -t 20 -codec:a pcm_s16le -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm

          提取完畢后使用 ffplay 驗證是否可以播放:

                

          1ffplay -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm

          確認播放正常后可以使用 SDL 播放 PCM 音頻了。

          播放本地PCM文件

          下面使用 SDL 來讀取本地 PCM 文件來播放,主要步驟如下:

          1. 打開PCM文件:

                

          1FILE *pcmFile = fopen(path, "rb");

          1. 初始化SDL為音頻場景:

                

          1SDL_Init(SDL_INIT_AUDIO);

          1. 填充SDL_AudioSpec音頻參數(shù):

                

          1SDL_AudioSpec audioSpec;
          2audioSpec.freq = 44100;  
          3audioSpec.format = AUDIO_S16SYS;  
          4audioSpec.channels = 2;  
          5audioSpec.samples = 1024;   // 1024/44100 = 0.0232199546485261 約等于23.2ms,也就是23.2ms至少回調一次  
          6audioSpec.silence = 0;  
          7audioSpec.callback = sdl_fill_pcm;  
          8audioSpec.userdata = NULL;

          這里的callback就是上文中的SDL_AudioCallback

          1. 使用初始化好的SDL_AudioSpec打開音頻設備:

                

          1SDL_OpenAudio(&audioSpec, NULL);

          1. 播放音頻:

                

          1SDL_PauseAudio(0);

          1. 循環(huán)從本地讀取 PCM 數(shù)據(jù):

                

          1// 數(shù)據(jù)讀取,記錄讀取的總數(shù)據(jù)
          2uint64_t dataCount = 0;
          3while (1) {
          4    // 從文件中讀取PCM數(shù)據(jù)
          5    read_buf_len = fread(audio_buf, 1, PCM_BUFFER_SIZE, pcmFile);
          6    if (read_buf_len == 0) {
          7        break;
          8    }
          9    // 統(tǒng)計讀取的總字節(jié)數(shù)
          10    dataCount += read_buf_len;
          11    // 更新數(shù)據(jù)讀取結束位置
          12    audio_end = audio_buf + read_buf_len;
          13    // 更新數(shù)據(jù)讀取開始位置
          14    audio_pos = audio_buf;
          15
          16    while (audio_pos < audio_end) {
          17        // 等待PCM數(shù)據(jù)消耗
          18        SDL_Delay(10);
          19    }
          20}

          1. 實現(xiàn) SDL_AudioCallback回調函數(shù)如下:

                

          1void sdl_fill_pcm(void *userdata, Uint8 *stream, int len) {
          2    SDL_memset(stream, 0, len);
          3    if (audio_pos >= audio_end) {
          4        return;
          5    }
          6    // 數(shù)據(jù)不夠直接讀完,否則只讀取一定長度的數(shù)據(jù)
          7    int remain_buf_len = audio_end - audio_pos;
          8    len = (remain_buf_len > len) ? len : remain_buf_len;
          9    // 拷貝數(shù)據(jù)到stream并設置音量
          10    SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME / 3);
          11    audio_pos += len;
          12}

          1. 釋放資源:

                

          1SDL_CloseAudio();
          2if (audio_buf) {  
          3    free(audio_buf);  
          4}  
          5if (pcmFile) {  
          6    fclose(pcmFile);  
          7}  
          8SDL_Quit();

          最后附上 Clion 工程的 CMakeLists.txt 文件,其內容如下:

                

          1cmake_minimum_required(VERSION 3.26)
          2project(sdf_pcm C)
          3set(CMAKE_C_STANDARD 11)
          4include_directories(E:/msys64/mingw64/include/SDL2)
          5link_directories(E:/msys64/mingw64/lib)
          6add_executable(sdl_pcm main.c)
          7target_link_libraries(sdl_pcm mingw32 SDL2 SDL2main)

          到此,SDL播放音頻 PCM 基本流程結束。

          最后推薦下秦子帥老哥最近撰寫的公眾號快速漲粉指南,有需要的童鞋可以看一下:

          推薦閱讀:


          瀏覽 71
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  先锋影音三级 | 天堂网在线免费 | 成人无码无遮又大又爽 | 就爱添逼视频免费网站 | 欧美成人性生活视频 |