当前位置 : 主页 > 编程语言 > c语言 >

MP2 音频文件解析 SDL播放

来源:互联网 收集:自由互联 发布时间:2023-09-07
场景 当前的audio.mp2文件,保存了海康NVR点播时候的音频数据,音频基本信息:单通道,采样频率16000HZ FFmpeg读取文件解码播放 int PlayMP2Audio(){char *file = "audio.mp2";AVCodecContext *pCodecCtx = NU

场景

当前的audio.mp2文件,保存了海康NVR点播时候的音频数据,音频基本信息:单通道,采样频率16000HZ


FFmpeg读取文件解码播放

int PlayMP2Audio()
{
	char *file = "audio.mp2";
	AVCodecContext *pCodecCtx = NULL;

	AVCodec *pCodec = NULL;
	AVFrame *pFrame = NULL;
	AVPacket *pPacket;
	uint8_t *pOutputAudioBuffer;

	struct SwrContext *pAudioConvertContext;

	AVFormatContext *pFormatCtx = NULL;
	if (avformat_open_input(&pFormatCtx, file, NULL, NULL) != 0) 
	{
		std::cout << "打开文件失败" << std::endl;
		return -1; 
	}

	if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
	{
		std::cout << "探测文件格式失败" << std::endl;
		return -1;
	}

	int nAudioStreamIndex = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	if (nAudioStreamIndex == -1) 
	{
		std::cout << "寻找音频流失败" << std::endl;
		return -1;
	}

	AVCodecParameters *pCodecParameters = pFormatCtx->streams[nAudioStreamIndex]->codecpar;
	pCodec = avcodec_find_decoder(pCodecParameters->codec_id);
	if (pCodec == NULL) 
	{
		std::cout << "不支持该音频格式" << std::endl;
		return -1;
	}

	pCodecCtx = avcodec_alloc_context3(pCodec);
	if (avcodec_parameters_to_context(pCodecCtx, pCodecParameters) != 0) 
	{
		std::cout << "复制音频信息失败" << std::endl;
		return -1;
	}

// 	pCodecCtx->sample_rate = 16000;
// 	pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16P;
// 	pCodecCtx->channels = 1;
// 	pCodecCtx->channel_layout = av_get_default_channel_layout(1);

	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
	{
		std::cout << "打开解码器失败" << std::endl;
		return -1; 
	}
	//打开解码器以后pCodecCtx->sample_fmt格式从AV_SAMPLE_FMT_FLTP变化为AV_SAMPLE_FMT_S16P
	pPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
	av_init_packet(pPacket);
	pFrame = av_frame_alloc();

	uint64_t nOutputChannelLayout = AV_CH_LAYOUT_MONO;//输出声道
	int nNBSample = 1152;//MP2默认的音频帧采样个数
	enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;//输出格式S16
	int nOutputSampleRate = pCodecCtx->sample_rate;
	int nOutputChannels = av_get_channel_layout_nb_channels(nOutputChannelLayout);

	int out_buffer_size = av_samples_get_buffer_size(NULL, nOutputChannels, nNBSample, out_sample_fmt, 1);
	pOutputAudioBuffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);


	if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) 
	{
		std::cout << "初始化SDL失败,错误码:" << SDL_GetError() << std::endl;
		return -1;
	}

	int nInputChannelLayout = av_get_default_channel_layout(pCodecCtx->channels);
	pAudioConvertContext = swr_alloc();
	pAudioConvertContext = swr_alloc_set_opts(pAudioConvertContext, nOutputChannelLayout, out_sample_fmt, nOutputSampleRate,
		nInputChannelLayout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);
	swr_init(pAudioConvertContext);


	bool bInitAudioDevice = false;
	while (av_read_frame(pFormatCtx, pPacket) >= 0)
	{
		if (pPacket->stream_index == 0) 
		{
			avcodec_send_packet(pCodecCtx, pPacket);
			while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) 
			{
				if (!bInitAudioDevice)
				{
					bInitAudioDevice = true;

					SDL_AudioSpec spec;
					spec.freq = nOutputSampleRate;
					spec.format = AUDIO_S16SYS;
					spec.channels = nOutputChannels;
					spec.silence = 0;
					spec.samples = pFrame->nb_samples;//这里不一定是2的幂指数次方,MP2默认是1152,否则播放声音异常
					spec.callback = read_audio_data;
					spec.userdata = pCodecCtx;

					if (SDL_OpenAudio(&spec, NULL) < 0)
					{
						std::cout << "打开音频设备失败" << std::endl;
						return -1;
					}

					SDL_PauseAudio(0);//开始播放
				}
				swr_convert(pAudioConvertContext, &pOutputAudioBuffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pFrame->data,
					pFrame->nb_samples); // 转换音频
			}

			audio_chunk = (Uint8 *)pOutputAudioBuffer;
			audio_len = out_buffer_size;
			audio_pos = audio_chunk;

			while (audio_len > 0)
			{
				SDL_Delay(1);//等待回调函数读取完缓存中的音频数据
			}
		}
		av_packet_unref(pPacket);
	}
	swr_free(&pAudioConvertContext);
	av_free(pOutputAudioBuffer);
	SDL_Quit();

	return 0;
}

备注

对于单声道的音频数据,不需要调用swr进行重采样

手动打开文件播放

指定每次读取的缓存大小是1152,否则会提示[mp2 @ 03eee300] Header missing,并且出现杂音或者破音的情况,无法听清声音

int nHasReadDataLen = 0;
	int nMP2FrameBufferSize = 1152;
	char *pMP2Buffer = (char *)calloc(nMP2FrameBufferSize, sizeof(char));

	std::ofstream ofstreamHanle;
	ofstreamHanle.open("F:/audio.mp2", std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
	while (1)
	{
		memset(pMP2Buffer, 0x00, nMP2FrameBufferSize);
		if (fread(pMP2Buffer, 1, nMP2FrameBufferSize, fp) != nMP2FrameBufferSize)
		{
			//循环读取
			fseek(fp, 0, SEEK_SET);
			fread(pMP2Buffer, 1, nMP2FrameBufferSize, fp);
			nHasReadDataLen = 0;
			break;
		}
		printf("Now Playing %10d Bytes data.\n", nHasReadDataLen);
		nHasReadDataLen += nMP2FrameBufferSize;
    //解码
    //播放
    }


上一篇:C++ 23 String Views
下一篇:没有了
网友评论