ffmpeg 教程學習筆記 音頻播放不正常問題
文章目錄
前言
最近在學習 ffmpeg 官網例程,例程3之後的播放音頻部分總是有問題,表現爲:代碼可以編譯通過,但播放時音頻都是雜音,隱隱約約能夠聽出旋律(我哭了。。。)。
經過多方查找終於找到了原因 ------- 沒有進行音頻重採樣!
一、開發環境
ffmpeg 4.1 + sdl 1.2.15 + vs2015
二、修改過程
1.導入頭文件
因爲是要進行重採樣,所以要將相應的頭文件包含進來。
#include <libswresample/swresample.h>
2.定義一個全局變量,用於存儲重採樣的標準(屬性)
AVFrame wanted_frame;
3.在設置完 wanted_spec 的屬性參數並打開音頻文件之後,爲上面我們所新定義的採樣標準初始化。
wanted_frame.format = AV_SAMPLE_FMT_S16;
wanted_frame.sample_rate = spec.freq;
wanted_frame.channel_layout = av_get_default_channel_layout(spec.channels);
wanted_frame.channels = spec.channels;
4.修改官方例程中的解碼函數 audio_decode_frame()
int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf, int buf_size) {
static AVPacket pkt;
static uint8_t *audio_pkt_data = NULL;
static int audio_pkt_size = 0;
static AVFrame frame;
int len1, data_size = 0;
SwrContext* swr_ctx = nullptr;
for (;;) {
while (audio_pkt_size > 0) {
int got_frame = 0;
len1 = avcodec_decode_audio4(aCodecCtx, &frame, &got_frame, &pkt);
if (len1 < 0) {
/* if error, skip frame */
audio_pkt_size = 0;
break;
}
audio_pkt_data += len1;
audio_pkt_size -= len1;
data_size = 0;
if (got_frame) {
data_size = av_samples_get_buffer_size(NULL,
aCodecCtx->channels,
frame.nb_samples,
aCodecCtx->sample_fmt,
1);
assert(data_size <= buf_size);
memcpy(audio_buf, frame.data[0], data_size);
}
/*****************************這裏開始是新添加的重採樣相關代碼**************************************/
if (frame.channels > 0 && frame.channel_layout == 0)
frame.channel_layout = av_get_default_channel_layout(frame.channels);
else if (frame.channels == 0 && frame.channel_layout > 0)
frame.channels = av_get_channel_layout_nb_channels(frame.channel_layout);
if (swr_ctx)
{
swr_free(&swr_ctx);
swr_ctx = nullptr;
}
swr_ctx = swr_alloc_set_opts(nullptr, wanted_frame.channel_layout, (AVSampleFormat)wanted_frame.format, wanted_frame.sample_rate,
frame.channel_layout, (AVSampleFormat)frame.format, frame.sample_rate, 0, nullptr);
if (!swr_ctx || swr_init(swr_ctx) < 0)
{
cout << "swr_init failed:" << endl;
break;
}
int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, frame.sample_rate) + frame.nb_samples,
wanted_frame.sample_rate, wanted_frame.format, AVRounding(1));
int len2 = swr_convert(swr_ctx, &audio_buf, dst_nb_samples,
(const uint8_t**)frame.data, frame.nb_samples);
if (len2 < 0)
{
cout << "swr_convert failed\n";
break;
}
return wanted_frame.channels * len2 * av_get_bytes_per_sample((AVSampleFormat)wanted_frame.format);
/******************************新加的代碼至此結束*****************************/
if (data_size <= 0) {
/* No data yet, get more frames */
continue;
}
/* We have data, return it and come back for more later */
return data_size;
}
if (pkt.data)
av_free_packet(&pkt);
if (global_video_state->quit) {
return -1;
}
if (packet_queue_get(&global_video_state->audioq, &pkt, 1) < 0) {
return -1;
}
audio_pkt_data = pkt.data;
audio_pkt_size = pkt.size;
}
}
好啦,這樣就算是改完啦。我這裏改完之後音頻播放就已經正常了。
對了,做好在 main 函數前加一個
#undef main
來解決sdl中也有 main 函數從而導致編譯不過的問題。(都是踩過的坑啊,,,眼淚不爭氣的流了下來)
總結
以上就是關於ffmpeg官方教程中音頻播放不正常的解決方法。當然了,這個是在我這邊的環境下通過的代碼,希望對各位迷路的小夥伴有幫助吧。
新手上路,水平有限。若是本文有什麼不妥之處還望各位大牛不吝指出,共同交流,本人在此先謝過啦。
參考資料
https://www.cnblogs.com/wangguchangqing/p/5788805.html