首页 > 其他分享 >mp2 音频文件解析播放

mp2 音频文件解析播放

时间:2023-04-10 19:31:49浏览次数:41  
标签:std NULL pCodecCtx 音频文件 sample mp2 av 播放 spec

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;
}

手动打开文件播放

指定每次读取的缓存大小是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;
    //解码
    //播放
    }


标签:std,NULL,pCodecCtx,音频文件,sample,mp2,av,播放,spec
From: https://blog.51cto.com/fengyuzaitu/6181369

相关文章

  • 关于firefox,在win10下,大部分视频网站都无法正常播放的问题
    1、目前日期:2023-4-102、firefox版本:111.0.1(64位)3、win10版本:Windows10专业版22H24、尝试过网上大部分的方法,包括但不限于,firefox排障模式,翻新、彻底重装浏览器5、系统刚启动的很短的时间内,马上打开firefox浏览器,是能正常播放视频的,但是隔了几分钟后,浏览器彻底关闭后,重......
  • ios的百度网盘web版本视频播放器的字幕插件功能
    详情见https://coding.net/u/qidizi/p/pan.baidu.com.srt.plugin/git这里放一张效果图。......
  • python播放视频
    python播放视频pipinstallpygameimportpygamepygame.init()#Setthedimensionsofthewindowscreen=pygame.display.set_mode((640,480))#Loadthevideofilevideo=pygame.movie.Movie("1.mp4")#Playthevideovideo.play()#Wait......
  • AirPods Pro连接Win11 播放视频 延迟严重
    https://discussionschinese.apple.com/thread/253723622应该是windows电脑声卡驱动的省电管理问题,暂停播放闲置一会之后会休眠,继续播放会唤醒,唤醒时间过长导致延迟。在注册表中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class{4d36e96c-e325-11ce-bfc1-08002be1031......
  • [MAUI 项目实战] 手势控制音乐播放器(一): 概述与架构
    这是一篇系列博文。请关注我,学习更多.NETMAUI开发知识![MAUI项目实战]手势控制音乐播放器(一):概述与架构[MAUI项目实战]手势控制音乐播放器(二):手势交互[MAUI项目实战]手势控制音乐播放器(三):动画[MAUI项目实战]手势控制音乐播放器(四):圆形进度条在之前的博文中提到这个......
  • Qt-FFmpeg开发-视频播放(5)
    音视频/FFmpeg#QtQt-FFmpeg开发-视频播放【软/硬解码+OpenGL显示YUV/NV12】目录音视频/FFmpeg#QtQt-FFmpeg开发-视频播放【软/硬解码+OpenGL显示YUV/NV12】1、概述2、实现效果3、FFmpeg硬解码流程4、优化av_hwframe_transfer_data()性能低问题5、主要代码5.1解码代码5.2......
  • Qt-FFmpeg开发-视频播放(4)
    音视频/FFmpeg#QtQt-FFmpeg开发-视频播放【软解码+OpenGL显示YUV420P图像】目录音视频/FFmpeg#QtQt-FFmpeg开发-视频播放【软解码+OpenGL显示YUV420P图像】1、概述2、实现效果3、FFmpeg软解码流程4、主要代码4.1解码代码4.2OpenGL显示RGB图像代码5、完整源代码更多......
  • [MAUI 项目实战] 手势控制音乐播放器(二): 手势交互
    @目录原理交互实现容器控件手势开始手势运行手势结束使用控件拖拽物创建pit集合项目地址原理定义一个拖拽物,和它拖拽的目标,拖拽物可以理解为一个平底锅(pan),拖拽目标是一个坑(pit),当拖拽物进入坑时,拖拽物就会被吸附在坑里。可以脑补一下下图:你问我为什么是平底锅和坑,当然了在微软......
  • COMP20007 Task 2: C Problem
    Task2:CProblemAssignment1GeneralTask1:AlgorithmicDesignTask2:CProblemAssignmentSubmissionAcademicHonestyLatePolicyRequirements:CProgrammingProgrammingStyleMarkBreakdownAdditionalSupportAcknowledgementsTask2:CProblemOlivia'sgrandfa......
  • EasyCVR视频融合平台云端录像无法播放的问题排查与解决
    EasyCVR基于云边端协同架构,能支持海量视频的轻量化接入与汇聚管理。在视频能力上,可提供视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、平台级联等。其中,录像回看功能又支持云端录像回看以及设备录像回看。有用户反......