如何将MP3或WAV文件解码成PCM文件

文章目录

    • 概要
    • 整体架构流程
    • 技术细节

概要

本文介绍使用 FFmpeg,将MP3或WAV文件解码成PCM文件的方法。

整体架构流程

首先,使用的 FFmpeg 库要支持 MP3/WAV 解码功能,即编译的时候要加上(编译 FFmpeg 库可以参考:Windows编译和使用ffmpeg):

--enable-decoder=mp3float --enable-decoder=pcm_s16le --enable-demuxer=mp3 --enable-demuxer=wav

下面的函数就是利用 FFmpeg 接口,实现将 MP3 或 WAV 文件解码成PCM文件:

#ifdef __cplusplus
extern "C" {
#endif
#include "libavutil/imgutils.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#ifndef __linux__
#include "libswscale/swscale.h"
#endif
#include "libavutil/opt.h"
#ifdef __cplusplus
}
#endif#pragma comment(lib, "libavcodec.a")
#pragma comment(lib, "libavformat.a")
#pragma comment(lib, "libavutil.a")
#pragma comment(lib, "libswresample.a")int DecodedAudioFile(const char *pFileName) {FILE *pFile = fopen("tmp.pcm", "wb");  // 输出文件AVFormatContext *pFormatCtx;AVCodecContext *pCodecCtx;AVCodec *pCodec;AVPacket *packet;AVFrame *pFrame;struct SwrContext *au_convert_ctx = NULL;av_register_all();avformat_network_init();pFormatCtx = avformat_alloc_context();if (avformat_open_input(&pFormatCtx, pFileName, NULL, NULL) != 0) {OutputDebugStringA("Couldn't open input stream.\n");return -1;}if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {OutputDebugStringA("Couldn't find stream information.\n");return -1;}av_dump_format(pFormatCtx, 0, pFileName, false);// Find the first audio streamint audioStream = -1;for (int i = 0; i < pFormatCtx->nb_streams; i++) {if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {audioStream = i;break;}}if (audioStream == -1) {OutputDebugStringA("Didn't find a audio stream.\n");return -1;}// Get a pointer to the codec context for the audio streampCodecCtx = pFormatCtx->streams[audioStream]->codec;// Find the decoder for the audio streampCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL) {OutputDebugStringA("Codec not found.\n");return -1;}// Open codecif (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {OutputDebugStringA("Could not open codec.\n");return -1;}int64_t in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);packet = (AVPacket*)av_malloc(sizeof(AVPacket));av_init_packet(packet);// Out Audio Paramuint64_t out_channel_layout = in_channel_layout;int out_nb_samples = pCodecCtx->frame_size;AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;int out_sample_rate = pCodecCtx->sample_rate;int out_channels = pCodecCtx->channels;// Out Buffer Sizeint out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);uint8_t *out_buffer = (uint8_t*)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);pFrame = av_frame_alloc();// 如果输入文件格式不是AV_SAMPLE_FMT_S16才需要if (pCodecCtx->sample_fmt != AV_SAMPLE_FMT_S16) {au_convert_ctx = swr_alloc();au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,in_channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);swr_init(au_convert_ctx);}while (av_read_frame(pFormatCtx, packet) >= 0) {if (packet->stream_index == audioStream) {int got_picture;int ret = avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, packet);if (ret < 0) {OutputDebugStringA("Error in decoding audio frame.\n");return -1;}if (got_picture > 0) {if (au_convert_ctx) {  // MP3文件格式通常是AV_SAMPLE_FMT_FLTP,要重采样、格式转换等swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t**)pFrame->data, pFrame->nb_samples);// Write PCMfwrite(out_buffer, 1, out_buffer_size, pFile);} else {  // WAV文件格式通常是AV_SAMPLE_FMT_S16,与输出文件一致,直接保存fwrite(pFrame->data[0], 1, pFrame->nb_samples * pCodecCtx->channels * 2, pFile);}}}av_free_packet(packet);}swr_free(&au_convert_ctx);fclose(pFile);av_free(out_buffer);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);return 0;
}int main() {DecodedAudioFile("test.mp3");DecodedAudioFile("test.wav");return 0;
}

技术细节

WAV 文件通常是未压缩的 PCM 音频,解码的步骤与压缩格式(如 MP3)有所不同。在解码 WAV 文件时,解码器可能会直接输出 PCM 数据,而不是像 MP3 那样的压缩数据。对于 WAV 文件,如果格式是 AV_SAMPLE_FMT_S16,则不需要使用 swr_convert,因为音频数据已经是 PCM 格式,可以直接写入文件。例如上述代码中,对文件格式的检查:

// ...
// 如果输入文件格式不是AV_SAMPLE_FMT_S16才需要
if (pCodecCtx->sample_fmt != AV_SAMPLE_FMT_S16) {au_convert_ctx = swr_alloc();au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,in_channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);swr_init(au_convert_ctx);
}
// ...
if (au_convert_ctx) {  // MP3文件格式通常是AV_SAMPLE_FMT_FLTP,要重采样、格式转换等swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t**)pFrame->data, pFrame->nb_samples);// Write PCMfwrite(out_buffer, 1, out_buffer_size, pFile);
} else {  // WAV文件格式通常是AV_SAMPLE_FMT_S16,与输出文件一致,直接保存fwrite(pFrame->data[0], 1, pFrame->nb_samples * pCodecCtx->channels * 2, pFile);
}
// ...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/48126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通义千问AI模型对接飞书机器人-模型配置(2-1)

一 背景 根据业务或者使用场景搭建自定义的智能ai模型机器人&#xff0c;可以较少我们人工回答的沟通成本&#xff0c;而且可以更加便捷的了解业务需求给出大家设定的业务范围的回答&#xff0c;目前基于阿里云的通义千问模型研究。 二 模型研究 参考阿里云帮助文档&#xf…

CSRF+XSS组合攻击实战

目录 0x01安装靶场 0x02分析功能点的请求接口&#xff0c;构造恶意请求 0x03寻找xss漏洞 0x01安装靶场 下载源码&#xff0c;解压到网站根目录 1.修改数据库配置文件 打开源码&#xff0c;进入到include目录下&#xff0c;打开数据库配置文件database.inc.php 将数据库的…

linux服务器数据库备份脚本

linux服务器下面备份数据库脚本 #获取当前时间戳 now_datedate %Y%m%d; #备份保存的路径 path/app/bak/$now_date; #不存在则创建文件夹 mkdir -p $path #备份数据库 /usr/bin/mysqldump -uroot -pyl2vXBS%FjGoSfby -hlocalhost --lock-all-tables --databases sdbj > $pa…

arcgis紧凑型切片缓存(解决大范围切片,文件数量大的问题)

ArcGIS 切片缓存的紧凑型存储格式是一种优化的存储方式&#xff0c;用于提高切片缓存的存储效率和访问速度。紧凑型存储格式将多个切片文件合并为一个单一的 .bundle 文件&#xff0c;从而减少文件系统的开销和切片的加载时间。这类格式已经应用很久了&#xff0c;我记得2013我…

组内第一次会议

会议内容 1、科研平台使用 增删改查对文件 cp -r /root/mmdetection/dataset/ /root/user/wbzExperiment/mmdetection/ rm -r /root/user/yolov5-master tar -czvf test03.tar.gz test03/ unzip abc.zip 上传文件、解压文件&#xff1a;要在自己的目录中&#xff0c;进入…

昇思MindSpore 应用学习-ResNet50迁移学习-CSDN

日期 心得 昇思MindSpore 应用学习-ResNet50迁移学习 (AI 代码解析) 在实际应用场景中&#xff0c;由于训练数据集不足&#xff0c;所以很少有人会从头开始训练整个网络。普遍的做法是&#xff0c;在一个非常大的基础数据集上训练得到一个预训练模型&#xff0c;然后使用该模…

React中Hooks几个有用的 ref

先看下来自官方的介绍&#xff0c;当你希望组件“记住”某些信息&#xff0c;但又不想让这些信息 触发新的渲染 时&#xff0c;你可以使用 ref 。 如何向组件添加 ref如何更新 ref 的值ref 与 state 有何不同如何安全地使用 ref 1.给你的组件添加 ref 你可以通过从 React 导…

Isaac Lab

一、安装isaac sim conda create -n isaaclab python=3.10 conda activate isaaclab pip install torch==2.2.2 --index-url https://download.pytorch.org/whl/cu121 pip install isaacsim-rl isaacsim-replicator isaacsim-extscache-physics isaacsim-extscache-kit-sdk isa…

编织文字的魔法:探索WebKit的CSS文本效果

编织文字的魔法&#xff1a;探索WebKit的CSS文本效果 在现代网页设计中&#xff0c;文本不仅仅是信息的载体&#xff0c;更是视觉表现的重要元素。WebKit&#xff0c;作为众多浏览器的核心引擎&#xff0c;支持一系列CSS文本效果&#xff0c;使开发者能够创造出引人注目的文本…

如何分清楚常见的 Git 分支管理策略Git Flow、GitHub Flow 和 GitLab Flow

Git Flow、GitHub Flow 和 GitLab Flow 是几种常见的 Git 分支管理策略&#xff0c;它们帮助开发团队更高效地管理代码库和协同开发。 Git Flow Git Flow 是一种功能强大的分支管理模型&#xff0c;由 Vincent Driessen 提出&#xff0c;适用于发布周期较长、需要严格管理发布…

【ELK】简述

ELK 堆栈的作用 大规模日志管理与分析 随着系统规模的扩大&#xff0c;应用程序、服务器和网络设备会产生大量的日志数据。ELK 堆栈可以集中收集、存储和索引这些分散在不同服务器和系统中的日志&#xff0c;方便快速检索和分析&#xff0c;帮助您快速定位系统故障、异常事件和…

Python函数基础:构建代码逻辑的基石(补全篇)

在前面我已经编写过一篇&#xff0c;python函数基础的博文&#xff0c;相信有基础的同学应该看得出来&#xff0c;那一篇的基础内容也是不全的&#xff0c;于是就有了这个补全篇。补全篇&#xff0c;补充了变量的作用与&#xff08;global与nonlocal&#xff09;、递归函数、闭…

企业在实施网络安全等级保护时需要采取哪些技术措施?

企业在实施网络安全等级保护时&#xff0c;需要采取一系列技术措施来确保信息系统的安全性。根据最新的网络安全等级保护要求&#xff0c;以下是一些关键的技术措施&#xff1a; 防火墙和入侵检测系统&#xff08;IDS/IPS&#xff09;&#xff1a;部署防火墙和入侵检测系统来监…

AI、AGI、AIGC与AIGC、NLP、LLM,ChatGPT区分

这些术语和技术都是人工智能&#xff08;AI&#xff09;领域的重要组成部分&#xff0c;它们之间有复杂的关系和相互交织的依存。以下是它们之间的关系和各自的定义&#xff1a; AI&#xff08;人工智能&#xff09;&#xff1a; 定义&#xff1a;AI是指能够执行通常需要人类智…

acwing796-子矩阵的和-前缀和

s矩阵是全局变量&#xff0c;维度n*m,从1~n和 1~m存储元素【0】【0】~【0】【m】和【0】【0】~【n】【0】分别存储的都是0.s矩阵刚开始是存储输入的元素&#xff0c;后面用于存储前缀和。 s矩阵的意思是s【i】【j】表示从【0】【0】到【i】【j】为对角线的矩阵里面所有元素的和…

多类别支持向量机(Multi-class SVM)

多类别支持向量机&#xff08;Multi-class SVM&#xff09;是一种扩展二分类支持向量机以处理多类别分类问题的方法。常见的方法有“一对一”&#xff08;one-vs-one&#xff09;和“一对多”&#xff08;one-vs-rest&#xff09;。 一、数学模型理论推导 1.1 一对多&#xf…

新的铸造厂通过 PROFIBUS 技术实现完全自动化

钢铁生产商某钢以其在厚钢板类别中极高的产品质量而闻名。其原材料&#xff08;板坯连铸机&#xff09;在钢铁厂本地生产&#xff0c;该厂最近新建了一座垂直连铸厂。该项目的一个主要目标是从一开始就完全自动化这座新工厂和整个铸造过程&#xff0c;以高成本效率实现最佳产品…

用AI对抗AI:Fortinet解锁家电制造网络安全新密码

Fortinet盛大启幕《构筑垂直行业 网络安全防线》系列研讨会。首场研讨会聚焦于家电制造领域&#xff0c;以《利用AI打造家电制造网络安全的新质力》为主题。 Fortinet中国南区资深安全顾问黄志攀深入洞察家电制造行业的网络安全挑战&#xff0c;全面解析了Fortinet如何通过全栈…

数据库系统概论:数据库系统的锁机制

引言 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;数据作为一种共享资源&#xff0c;其并发访问的一致性和有效性是数据库必须解决的问题。锁机制通过对数据库中的数据对象&#xff08;如表、行等&#xff09;进行加锁&#xff0c;以确保在同…

基于python的去除图像内部填充

1 代码功能 该代码实现了一个图像处理的功能&#xff0c;具体来说是去除图像内部填充&#xff08;或更准确地说&#xff0c;是提取并显示图像中轮廓的外围区域&#xff0c;而忽略内部填充&#xff09;。以下是该功能的详细步骤&#xff1a; 读取图像&#xff1a;使用cv2.imread…