
目錄一、先給一句話定性二、swr_convert 函數原型三、參數逐個拆重點在“樣本不是字節”① SwrContext *s② out[]/ in[]—— 不是 void*packedS16 / S32 / U8planarFLTP / S16P③ in_count/ out_count單位是什么四、返回值到底什么意思五、最經典的坑殘留 FIFO90%人踩現象原因正確 flush 姿勢六、AVFrame 流派的“標準模板”解碼 → swr → SDL / D3D七、S16 packed → SDL 最小完整例子八、常見翻車表血淚九、swr_convert 內部在干嘛十、一句話總結覺得有用就請您幫忙點贊轉發收藏吧您的鼓勵是我創作的動力多謝看官。由于能力水平有限文中的錯誤或不嚴謹的地方在所難免還請批評指正。swr_convert是 FFmpeg 中libswresample庫的核心函數用于執行音頻重采樣操作。它能夠將音頻流的?采樣率?、?采樣格式?如從浮點轉為整型或?聲道布局?如從單聲道轉為立體聲進行轉換且不會改變音頻的播放時長。做音頻播放 / 錄音 / 轉碼的人遲早都會撞上這一句swr_convert(swr_ctx, out_buf, out_samples, in_buf, in_samples);抄能跑但一問為什么返回值是輸出幀數in_samples 怎么給planar 怎么擺殘留數據在哪?今天把swr_convert拆干凈不繞術語。一、先給一句話定性swr_convert 不是“格式轉換器”是音頻流水線工人負責 采樣率 / 聲道布局 / 樣本格式 / 位深 全部打包干完。核心任務只有三個重采樣SRC 聲道重排channel layout packed ? planar二、swr_convert 函數原型int swr_convert(struct SwrContext *s, uint8_t *const out[], int out_count, const uint8_t *const in[], int in_count);看著簡單其實 4 組語義上下文 輸出地址 / 想要多少樣本 輸入數據 / 實際多少樣本三、參數逐個拆重點在“樣本不是字節”①SwrContext *s一次初始化反復用swr_alloc_set_opts(nullptr, AV_CH_LAYOUT_STEREO, // out layout AV_SAMPLE_FMT_S16, // out fmt 48000, // out rate AV_CH_LAYOUT_5POINT1_BACK, // in layout AV_SAMPLE_FMT_FLTP, // in fmt 44100, 0, nullptr);layout rate fmt 缺一不可②out[]/in[]—— 不是 void*packedS16 / S32 / U8uint8_t* out[1] { (uint8_t*)pcm16 }; swr_convert(s, out, ...);planarFLTP / S16Puint8_t* out[2]; out[0] left; out[1] right;規則planar data[i] 每聲道一塊packed data[0] 全擠一起AVFrame::data 原樣傳就行③in_count/out_count單位是什么單聲道樣本數per channel sample count參數意思in_count輸入每個聲道多少幀out_count我最多能吃多少幀不是字節不是 packet size例1024 幀立體聲in_count 1024; // FLTP: data[0][1024], data[1][1024]四、返回值到底什么意思int ret swr_convert(...);ret 本次輸出的 per-channel sample 數ret含義0輸出樣本數0FIFO 里攢著呢0出錯常見誤解“我給了 1024為啥返回 882”因為48000 → 44100 ratio 44100/48000 ≈ 0.91875五、最經典的坑殘留 FIFO90%人踩現象最后幾秒聲音沒了每次 flush 都有一小截原因swr 內部有 FIFO不夠一幀不吐正確 flush 姿勢while ((ret swr_convert(swr, out, out_max, nullptr, 0)) 0) { write_pcm(out, ret); }口訣innullptr, in_count0 沖 FIFO六、AVFrame 流派的“標準模板”解碼 → swr → SDL / D3DAVFrame* dec got_frame; uint8_t* out[1] { audio_buf }; int out_nb swr_get_out_samples(swr, dec-nb_samples); int ret swr_convert(swr, out, out_nb, (const uint8_t**)dec-data, dec-nb_samples); // ret 實際可播放樣本數swr_get_out_samples()先問大小避免 alloc 太小七、S16 packed → SDL 最小完整例子int dst_nb swr_get_out_samples(swr_ctx, frame-nb_samples); uint8_t* dst (uint8_t*)malloc(dst_nb * 2 * 2); uint8_t* out[1] { dst }; swr_convert(swr_ctx, out, dst_nb, (const uint8_t**)frame-data, frame-nb_samples); SDL_QueueAudio(dev, dst, dst_nb * 4); free(dst);八、常見翻車表血淚癥狀真兇聲音加速in/out rate 反了爆音planar 當 packed聲道左右反layout 沒設最后沒聲沒 flush返回負out_count 太小九、swr_convert 內部在干嘛[in frame] ↓ delay / compensation ↓ 重采樣polyphase filter ↓ 聲道混合downmix / upmix ↓ planar ? packed ↓ [FIFO] → out不是一幀進一幀出十、一句話總結swr_convert 給樣本數吃樣本數返回輸出樣本數結束必須 nullptr/0 flushplanar 用 data[]永遠別碰字節數。