如何将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);
}
// ...
相关文章:
如何将MP3或WAV文件解码成PCM文件
文章目录 概要整体架构流程技术细节 概要 本文介绍使用 FFmpeg,将MP3或WAV文件解码成PCM文件的方法。 整体架构流程 首先,使用的 FFmpeg 库要支持 MP3/WAV 解码功能,即编译的时候要加上(编译 FFmpeg 库可以参考:Win…...
OpenAI 推出 GPT-4o mini,一种更小、更便宜的人工智能模型
OpenAI 最近推出了新型人工智能模型 GPT-4o mini,以其较小体积和低成本受到关注。这款模型在文本和视觉推理任务上性能优越,且比现有小型模型更快、更经济。GPT-4o mini 已向开发者和消费者发布,企业用户将在下周获得访问权限。 喜好儿网 在…...
Nacos 服务发现(订阅)源码分析(服务端)
前言: 前文我们分析了 Nacos 服务发现(订阅)的流程,从 Nacos Client 端的源码分析了服务发现的过程,服务发现最终还是要调用 Nacos Server 端来获取服务信息,缓存到客户端本地,并且会定时向 Na…...
DICOM CT\MR片子免费在线查看工具;python pydicom包加载查看;mayavi 3d查看
DICOM CT\MR片子免费在线查看工具 参考: https://zhuanlan.zhihu.com/p/668804209 dicom格式: DICOM(Digital Imaging and Communications in Medicine)是医学数字成像和通信的标准。它定义了医学图像(如CT、MRI、X…...
VSCode远程连接Ubuntu/Linux
文章目录 前言SSH(Secure Shell)简介主要功能工作原理常见的 SSH 客户端和服务器 Ubuntu安装sshvscode远程插件安装远程插件开始远程连接 打开文件夹新建终端 总结 前言 在现代开发环境中,远程工作和跨平台开发变得越来越普遍。Visual Studi…...
【Nginx80端口被占用】80端口被System占用如何解决【已解决】
【Nginx80端口被占用】80端口被System占用如何解决【已解决】 01 问题背景 Nginx 版本 1.19及以上80端口被System占用,无法kill tcp6 0 0 :::111 :::* LISTEN 1/systemd tcp6 0 0 :::80 :::* LISTEN 1/systemd 执行以下代码无效&…...
云计算的发展历程与边缘计算
云计算的发展历程 初期发展(1960s-1990s) 概念萌芽:云计算的概念可以追溯到1960年代,当时约翰麦卡锡(John McCarthy)提出了“计算将来可能成为一种公共设施”的想法。这个概念类似于现代的云计算…...
199.二叉树的右视图(DFS)
给定一个二叉树的根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4] 输出: [1,3,4] 示例 2: 输入: [1,null,3] 输出: [1,3] 示例 3: 输入: [] 输出: [] 解题…...
机器学习基础入门(1)
最近也在努力的想要学习些机器学习的知识,目前正在了解各个概念及术语,下面就把学习到的概念都列出来。 人工智能 (AI) Artificial intelligence 人工智能生成内容(AIGC) 机器学习(ML) Machine Learning …...
mybatis的xml中,where标签不自动删除多余的and之类的问题
遇到了这个莫名其妙的问题,起初是很疑惑的,where标签好像失灵了一般不会自动删除掉 多余的and 看了眼sql语句,发现还是有and没被删除。 后来重新写了遍后发现又没事了。真的是神人。 然后就研究了好一会,发现!&#…...
RK3588 编译opencvopencv_contrib记录
RK3588 编译opencv&opencv_contrib记录 1. 下载文件1.1 opencv源码1.2 安装cmake 2.开始编译2.1 提示缺少boostdesc_bgm.i 等问题2.2 提示缺少某hpp头文件2.3 其它问题 3. 设置环境变量4. 测试5.参考 1. 下载文件 1.1 opencv源码 需要opencv和opencv-contrib的版本号保持…...
Eureka: 微服务架构中的服务发现与注册实践
Eureka介绍与使用教程 你好,我是悦创。 Eureka 是 Netflix 开发的一款服务发现(Service Discovery)工具,它主要用于云中基于微服务架构的应用程序。Eureka使服务实例能够动态地注册自己,而其他服务实例可以通过 Eure…...
8、添加第三方包
目录 1、安装Django Debug Toolbar Django的一个优势就是有丰富的第三方包生态系统。这些由社区开发的包,可以用来快速扩展应用程序的功能集 1、安装Django Debug Toolbar Django Debug Toolbar位于名列前三的第三方包之一 这是一个用于调试Debug Web应用程序的有…...
【算法】算法模板
算法模板 文章目录 算法模板简介数组字符串列表数学树图动态规划 简介 博主在LeetCode网站中学习算法的过程中使用到并总结的算法模板,在算法方面算是刚过初学者阶段,竞赛分数仅2000。 为了节省读者的宝贵时间,部分基础的算法与模板未列出。…...
特征工程方法总结
方法有以下这些 首先看数据有没有重复值、缺失值情况 离散:独热 连续变量:离散化(也成为分箱) 作用:1.消除异常值影响 2.引入非线性因素,提升模型表现能力 3.缺点是会损失一些信息 怎么分:…...
Unity | AssetBundle
1 定义 Unity中的一种特殊资源包格式,用于存储和分发游戏资源。这些资源可以包括模型、纹理、音频文件、预制体、场景等。 AssetBundle允许开发者在游戏运行时动态加载和卸载资源,从而实现灵活的资源管理。 2 使用场景 1、资源管理 有效管理游戏中的资…...
【虚幻引擎】C++网络通信TCP和HTTP实战开发全流程,以接入科大讯飞星火大模型和文心一言千帆大模型为案例讲解
本套课程介绍了使用我们的虚幻C去写开发我们的插件开发,如何使用我们的虚幻C 封装我们的TCP和HTTP,如何使用的我们虚幻C子系统,如何根据第三方文档去写接口请求,如何通过我们的加密算法去签名我们的URL,如何声明我们的…...
.NET单元测试使用AutoFixture按需填充的方法总结
AutoFixture是一个.NET库,旨在简化单元测试中的数据设置过程。通过自动生成测试数据,它帮助开发者减少测试代码的编写量,使得单元测试更加简洁、易读和易维护。AutoFixture可以用于任何.NET测试框架,如xUnit、NUnit或MSTest。 默…...
求职学习day5
安排明天hr面 投一下平安可能。 hr面准备,复习java核心技术,复习java项目。 正视自己,调整心态。 也是很早接触了javaguide但是没有持续学习,项目介绍 | JavaGuide,面试前复习一下感觉还是很有收获的。 还有一些…...
微服务常用的中间件有哪些?都有什么用途?
前言 最近整理一下我们的项目使用了哪些中间件,借此机会也来分享一下,在微服务架构中我们常用的那些中间件,都有什么作用,为什么要使用中间件。 消息中间件-RocketMQ 比如RocketMQ,RocketMQ 是一个开源的分布式消息…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...
