如何将MP2音频文件解析并使用SDL播放器进行长尾词处理?

2026-04-10 09:011阅读0评论SEO资讯
  • 内容介绍
  • 相关推荐

本文共计731个文字,预计阅读时间需要3分钟。

如何将MP2音频文件解析并使用SDL播放器进行长尾词处理?

场景:当前audio.mp2文件,保存了海康NVR点播时的音频数据,音频基本信息:单通道,采样频率16000Hz。使用FFmpeg读取文件解码播放。

cint PlayMP2Audio(char *file){ AVCodecContext *pCodecCtx=NULL; // 初始化解码器等操作...}

场景

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


如何将MP2音频文件解析并使用SDL播放器进行长尾词处理?

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; //解码 //播放 }


本文共计731个文字,预计阅读时间需要3分钟。

如何将MP2音频文件解析并使用SDL播放器进行长尾词处理?

场景:当前audio.mp2文件,保存了海康NVR点播时的音频数据,音频基本信息:单通道,采样频率16000Hz。使用FFmpeg读取文件解码播放。

cint PlayMP2Audio(char *file){ AVCodecContext *pCodecCtx=NULL; // 初始化解码器等操作...}

场景

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


如何将MP2音频文件解析并使用SDL播放器进行长尾词处理?

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; //解码 //播放 }