【寫在前面】
前面我介紹了視頻解碼的流程,發現基礎講得有點少。
因此這裏附上一些額外的基礎內容:https://blog.csdn.net/u011283226/article/details/101024093
本篇主要內容:
1、FFmpeg音頻解碼基本流程
2、libswresample的基本使用方法
【正文開始】
實際上音頻解碼和視頻解碼的流程是一樣的,因此就不花篇幅講流程了。
這裏先簡單說一下不同的地方:
//找到音頻流的索引
audioIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
在第二個參數,改爲 AVMEDIA_TYPE_AUDIO 即可。
然後從解複用到解碼出 PCM,和視頻解碼的流程是一樣的。
視頻解碼見:https://blog.csdn.net/u011283226/article/details/100868821
當然,本篇文章就這樣結束也不太好,那麼就簡單講一下關於 libswresample 的使用方法吧。
libswresample 是FFmpeg提供的重採樣( Resample )庫,所謂的重採樣也可以簡單理解爲:樣本轉換,因此 libswresample 提供一組高度優化的樣本轉換函數,不管是採樣類型,聲道格式等等都可以進行轉換。
要想使用 libswresample,首先得分配一個SwrContext ,它有兩種分配方式:
1、使用 swr_alloc() 分配一個 SwrContext 指針,並且必須使用 av_opt_set_*() 來設置參數。
具體的參數在 FFmpeg 源碼下的 libswresample / options.c 中。
如果你下載了Qt的源碼,那麼其中就包含了FFmpeg的源碼( 因爲 Chromium 源碼包含FFmpeg,而Qt包含 Chromium ),它在 qtwebengine 中。
2、使用 swr_alloc_set_opts() 分配的同時設置一些參數。
SwrContext *swrContext = swr_alloc_set_opts(nullptr, int64_t(codecContext->channel_layout), AV_SAMPLE_FMT_S32, codecContext->sample_rate,
int64_t(codecContext->channel_layout), codecContext->sample_fmt, codecContext->sample_rate,
0, nullptr);
swr_init(swrContext);
我使用第二種方式分配,因爲這裏不需要那麼多參數。
注意,分配了 SwrContext 後,必須使用 swr_init() 來進行初始化。
然後,當我們使用 avcodec_receive_frame() 獲取到一幀解碼的數據後,就可以進行轉換了:
int size = av_samples_get_buffer_size(nullptr, frame->channels, frame->nb_samples, AV_SAMPLE_FMT_S32, 0);
uint8_t *buf = new uint8_t[size];
swr_convert(swrContext, &buf, frame->nb_samples, const_cast<const uint8_t**>(frame->data), frame->nb_samples);
delete[] buf;
1、使用 av_samples_get_buffer_size() 來獲取給定音頻參數所需的緩衝大小。
2、new (分配) 一個緩衝區。
3、使用 swr_convert() 來進行轉換,in -> out。
因爲FFmpeg的註釋已經足夠詳細了,所以我從不講參數。
4、轉換完成後的數據存儲在 buf 中了,記住別忘了 delete。
【結語】
本篇實在是沒什麼好寫的,因爲FFmpeg的抽象,所以解碼視頻和音頻的流程基本差不多。
不過,解碼字幕的時候倒是有些不同,這在後面會進行講解的。
最後,附上項目地址:https://github.com/mengps/FFmpeg-Learn,可以自己嘗試一下。