ffmpeg 教程学习笔记(1)

ffmpeg 教程学习笔记 音频播放不正常问题

文章目录

    • ffmpeg 教程学习笔记 音频播放不正常问题
  • 前言
  • 一、开发环境
  • 二、修改过程
    • 1.导入头文件
    • 2.定义一个全局变量,用于存储重采样的标准(属性)
    • 3.在设置完 wanted_spec 的属性参数并打开音频文件之后,为上面我们所新定义的采样标准初始化。
    • 4.修改官方例程中的解码函数 audio_decode_frame()
  • 总结


前言

最近在学习 ffmpeg 官网例程,例程3之后的播放音频部分总是有问题,表现为:代码可以编译通过,但播放时音频都是杂音,隐隐约约能够听出旋律(我哭了。。。)。
经过多方查找终于找到了原因 ------- 没有进行音频重采样!


一、开发环境

ffmpeg 4.1 + sdl 1.2.15 + vs2015

二、修改过程

1.导入头文件

因为是要进行重采样,所以要将相应的头文件包含进来。

#include 

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

你可能感兴趣的:(ffmpeg学习笔记,ffmpeg,c++,sdl,经验分享)