libmad 解码mp3并且播放测试

2023-11-07

测试环境:window64  codeblock(mingw64)


下载libmad源码后发现自带的minimad.c是用了linux的API,所以修改了下,将

F:\d.mp3音乐文件解码后将pcm数据写入F:\d.pcm,并且用ffplay播放


一开始写入mp3全部的数据,minimad会发出decoding error 0x0101 (lost synchronization)等错误。

但是后面还是解码了,不明白为什么,所以去看了下mp3文件格式,发现mp3由标签头和音频数据帧组成

音频数据帧开头有11bit的同步字节,所以就明白了需要去掉标签头将后面的帧数据送入即可。

译码完成后用ffplay播放原生PCM数据

ffplay -f s16le -ac 2 -ar 44100 d.pcm

-f指定格式为有符号16bit pcm小端序   short 16 little endian (端序的话看你在输出回调里面怎么写)

-ac指定音频通道数audio channel(根据你的mp3文件的通道决定,用ffmpeg -i d.mp3就可以看)

-ar指定音频采样率44100Hz(根据你的mp3文件的采样率决定,用ffmpeg -i d.mp3就可以看)

结果如下:


代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <io.h>
# include "mad.h"

/**
  libmad测试
**/
static int decode(unsigned char const *, unsigned long);
static FILE *fout;
//得到文件的大小
int file_size(char* filename)
{
    FILE *fp=fopen(filename,"r");
    if(!fp) return -1;
    fseek(fp,0L,SEEK_END);
    int size=ftell(fp);
    fclose(fp);
    return size;
}
int main()
{
  char *fdm,*fdm2;
  FILE *p;
  char label[10];
  int label_size;
  int fileSize;
  fileSize=file_size("F:\\d.mp3");
  if(_access("F:\\d.pcm",F_OK)==0)remove("F:\\d.pcm");//如果存在就删除
  fout=fopen("F:\\d.pcm","wb");
  if(fout==NULL){
    printf("create file failed\n");
    return -1;
  }
  p=fopen("F:\\d.mp3","rb");
  if(p==NULL){
    printf("open file failed\n");
    return -1;
  }
  if(fread(label,sizeof(char),10,p)>0){
    //计算标签大小
    label_size=((label[6]&0x7F)<<21)|((label[7]&0x7F)<<14)|((label[8]&0x7F)<<7)|((label[9]&0x7F));
    label_size+=10;
    printf("label size=%d\nfileSize=%d\n",label_size,fileSize);
  //分配音频数据帧缓冲区
      fdm2=fdm=malloc(fileSize-label_size);
      if(fdm==NULL){
        printf("malloc failed\n");
      }
      fread(fdm,sizeof(char),label_size-10,p);//去掉标签头数据,剩下的就是音频数据帧
  }else return -1;

   printf("read %d bytes\n",fread(fdm,sizeof(char),fileSize-label_size,p));
   printf("decode ok %s\n",decode(fdm,fileSize-label_size)==0?"OK":"failed");
   free(fdm2);
   fclose(p);
   fclose(fout);
  return 0;
}


struct buffer {
  unsigned char const *start;
  unsigned long length;
};
/**
输入回调函数,一次性写入所有音频数据帧
**/
static
enum mad_flow input(void *data,
		    struct mad_stream *stream)
{
  struct buffer *buffer = data;

  if (!buffer->length)
    return MAD_FLOW_STOP;

  mad_stream_buffer(stream, buffer->start, buffer->length);

  buffer->length = 0;

  return MAD_FLOW_CONTINUE;
}

/*
转换24bit pcm为16bit pcm
 */
static inline
signed int scale(mad_fixed_t sample)
{
  /* round */
  sample += (1L << (MAD_F_FRACBITS - 16));

  /* clip */
  if (sample >= MAD_F_ONE)
    sample = MAD_F_ONE - 1;
  else if (sample < -MAD_F_ONE)
    sample = -MAD_F_ONE;

  /* quantize */
  return sample >> (MAD_F_FRACBITS + 1 - 16);
}

/*
输出回调函数,每译码完成一帧音频数据,就调用一次
 */
static
enum mad_flow output(void *data,
		     struct mad_header const *header,
		     struct mad_pcm *pcm)
{
  unsigned int nchannels, nsamples;
  mad_fixed_t const *left_ch, *right_ch;
  unsigned char *buf;
  int index;

  nchannels = pcm->channels;
  nsamples  = pcm->length;
  left_ch   = pcm->samples[0];
  right_ch  = pcm->samples[1];
  buf = malloc(nsamples*nchannels*2);

  index=0;
  while (nsamples--) {
    signed int sample;

    sample = scale(*left_ch++);
    *(buf+2*nchannels*index+0)=(sample >> 0) & 0xff;
    *(buf+2*nchannels*index+1)=(sample >> 8) & 0xff;

    if (nchannels == 2) {
      sample = scale(*right_ch++);
      *(buf+2*nchannels*index+2)=(sample >> 0) & 0xff;
      *(buf+2*nchannels*index+3)=(sample >> 8) & 0xff;
    }
    index++;
  }
  fwrite(buf,sizeof(char),pcm->length*nchannels*2,fout);
  free(buf);
  return MAD_FLOW_CONTINUE;
}

/*
错误回调函数,有错误就调用
 */
static
enum mad_flow error(void *data,
		    struct mad_stream *stream,
		    struct mad_frame *frame)
{
  struct buffer *buffer = data;

  fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
	  stream->error, mad_stream_errorstr(stream),
	  stream->this_frame - buffer->start);

  return MAD_FLOW_CONTINUE;
}

/*
译码
 */
static
int decode(unsigned char const *start, unsigned long length)
{
  struct buffer buffer;
  struct mad_decoder decoder;
  int result;

  buffer.start  = start;
  buffer.length = length;
  //初始化译码器,设置回调函数
  mad_decoder_init(&decoder, &buffer,
		   input, 0 /* header */, 0 /* filter */, output,
		   error, 0 /* message */);
  //运行译码器
  result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);

  mad_decoder_finish(&decoder);

  return result;
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

libmad 解码mp3并且播放测试 的相关文章

  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么

随机推荐

  • 【极简代码】Unity控制3D物体的自由旋转 缩放和移动

    Unity中以最少代码 控制3D物体的自由旋转 缩放和移动 using UnityEngine public class TestMatrix MonoBehaviour float scaleparam 0f Vector3 oldSca
  • (2)一文懂“AI推理芯片” 测试方法与测试指标

    1 前言 Inference是用于测试系统使用训练有素的模型处理输入和产生结果的速度 1 1 缘起 随着人工智能应用的崛起 其在不同的硬件芯片平台上的性能也逐渐变成了比较不同硬件和芯片的重要参考 然而 最初由各个芯片厂商自行公布的跑分结果往
  • ros::spin()和ros::spinOnce()介绍讲解及区别

    首先要理解的一点是 任何一个发布和订阅 都会有其对应的发布缓存区和订阅缓存区 正如advertise和subscribe函数中都有缓存数量的参数 当有发布者发布消息后 会存放在发布缓存区 如果该topic有订阅者 则从发布缓存区读取到订阅缓
  • Redis数据类型

    业务数据的特殊性 数据类型既然是用来描述数据的存储格式的 如果你不知道哪些数据未来会进入到我们来的redis中 那么对应的数据类型的选择就会出现问题 原始业务功能设计 秒杀 他这个里边数据变化速度特别的快 访问量也特别的高 用户大量涌入以后
  • kali root默认密码_Kali Linux root 默认密码是:toor

    如果你听到一个 13 岁的黑客吹嘘他是多么的牛逼 是有可能的 因为有 Kali Linux 的存在 尽管有可能会被称为 脚本小子 但是事实上 Kali 仍旧是安全专家手头的重要工具 或工具集 Kali 是一个基于 Debian 的 Linu
  • java实现读取服务器日志文件,Java实时读取日志文件

    编码实现 写日志文件 每秒写200条记录 并且记录写的时间 import java io File import java io IOException import java io RandomAccessFile import java
  • vue配置开发环境和生产环境调用不同的域名以及跨域问题

    注意 这里vue项目与后端是前后端完全分离的 所有请求后端的地址是不一样的 安装axios npm install axios 然后 npm install save axios vue axios 用到post请求时 需要安装qs imp
  • Apache RocketMQ 5.0 消息进阶:如何支撑复杂的业务消息场景?

    一致性 首先来看 RocketMQ 的第一个特性 事务消息 事务消息是 RocketMQ 与一致性相关的特性 也是 RocketMQ 有别于其他消息队列的最具区分度的特性 以大规模电商系统为例 付款成功后会在交易系统中订单数据库将订单状态更
  • #101. 级数求和(3月31日)

    一 这题很简单我们只要注意高精度就行了 我一开始就是使用int型 傻傻算半天 int型 1 任何数 都只得整数 所以我们要用double来计算 只要从1开始一直网上循环摘要当我们的sn大于p时我们就停止循环 这题就是这样只要注意高精度就行了
  • linux链接jsoncpp库时,报一堆标准库错误的解决方法

    最近在一个工程中链接jsoncpp库 Makefile文件中添加包含路径代码 I usr local include json 编译时报错 usr include stdio h 821 错误 FILE 在此作用域中尚未声明 usr inc
  • 隐患重重遭诟病 细数固态硬盘“七宗罪”

    此内容转自网络 本人认为文章内容优秀 只作收藏 作为自己的知识库 并不用他用 原文链接地址为 http ssd zol com cn 471 4715723 all html 隐患重重遭诟病 细数固态硬盘 七宗罪 2015 02 28 19
  • vue.js -- slot插槽

    slot插槽 子组件提供给父组件使用的占位符 表示父组件可以占位符中填充内容 填充的内容会替换子组件的标签 插槽显不显示 怎样显示是由父组件来控制的 而插槽在哪里显示就由子组件来进行控制 slot作用域 slot在哪里调用 就使用哪里的数据
  • 数据管道(data pipeline)与ETL管道(ETL pipeline)的区别

    数据管道与ETL管道 这两个词的意义是相近的 差别比较微小 有时候很多人会混用 ETL管道 描述的是一组进程 实现将数据从一个系统抽取出来 经过转换 最终再加载到其他数据库或数据仓库中 数据管道 是一个比ETL管道更加通用的术语 只要是实现
  • 生成式AI:为开发者设计的革命性工具

    随着人工智能技术的飞速发展 生成式AI已成为许多领域的关键技术 生成式AI是指一类人工智能技术 能够通过学习数据集的内在规律和相关性 生成全新的 真实的 有用的数据 这种技术已经被广泛应用于图像 语音 自然语言处理等领域 成为人工智能领域的
  • 以太坊虚拟机EVM的工作原理是怎样的

    以太坊虚拟机EVM的工作原理是怎样的 如果你打算尝试在以太坊区块链上开发智能合约 或者已经在该领域工作了一段时间 可能会遇到EVM一词 EMV是太坊虚拟机的缩写 虚拟机本质上是在执行代码和执行的机器之间创建一个抽象级别 需要这一层抽象来提高
  • android系统 分辨率对应资源文件

    分辨率对比 ldpi 240x320 mdpi 320x480 hdpi 480x800 480x854 xhdpi 至少960 720 xxhdpi 1280 720 或 ldpi QVGA 240 320 mdpi HVGA 320 4
  • C++const修饰变量,函数,类

    const修饰变量 const的作用是 在编写程序过程中 因为我们会调用各种函数 假如我们并不想让某个已经赋了初值的变量在程序运行过程中受到改变 因此我们用const来作为关键字来修饰 定义格式 const typename 变量名 con
  • vue中 根据判断条件添加一个或多个style,及class的写法

    style 写法
  • 【pygame】font 模块

    pygame font Pygame 中加载和表示字体的模块 函数 pygame font init 初始化字体模块 pygame font quit 还原字体模块 pygame font get init 检查字体模块是否被初始化 pyg
  • libmad 解码mp3并且播放测试

    测试环境 window64 codeblock mingw64 下载libmad源码后发现自带的minimad c是用了linux的API 所以修改了下 将 F d mp3音乐文件解码后将pcm数据写入F d pcm 并且用ffplay播放