ffmpeg 教程學習筆記(1)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章