一. 
1. 利用fffmpeg将mp3转为pcm并在pcm数据加上wav头就是一个完整的wav文件
2. 代码
#include "utils.h"
#include <libavutil/avutil.h>
#include <libavutil/attributes.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/mathematics.h>
#include <libswresample/swresample.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
#include <libswresample/swresample.h>

#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
 //下面这四个结构体是为了分析wav头的
typedef struct {
    u_int magic;      /* 'RIFF' */
    u_int length;     /* filelen */
    u_int type;       /* 'WAVE' */
} WaveHeader;

typedef struct {
    u_short format;       /* see WAV_FMT_* */
    u_short channels;
    u_int sample_fq;      /* frequence of sample */
    u_int byte_p_sec;
    u_short byte_p_spl;   /* samplesize; 1 or 2 bytes */
    u_short bit_p_spl;    /* 8, 12 or 16 bit */
} WaveFmtBody;

typedef struct {
    u_int type;        /* 'data' */
    u_int length;      /* samplecount */
} WaveChunkHeader;

#define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
#define WAV_RIFF COMPOSE_ID('R','I','F','F')
#define WAV_WAVE COMPOSE_ID('W','A','V','E')
#define WAV_FMT COMPOSE_ID('f','m','t',' ')
#define WAV_DATA COMPOSE_ID('d','a','t','a')
int insert_wave_header(FILE* fp, long data_len)
{
    int len; 
    WaveHeader* header;
    WaveChunkHeader* chunk;
    WaveFmtBody* body;
    
    fseek(fp, 0, SEEK_SET);        //写到wav文件的开始处
    
    len = sizeof(WaveHeader)+sizeof(WaveFmtBody)+sizeof(WaveChunkHeader)*2;
    char* buf = (char*)malloc(len);
    header = (WaveHeader*)buf;
    header->magic = WAV_RIFF;
    header->length = data_len + sizeof(WaveFmtBody)+sizeof(WaveChunkHeader)*2 + 4;
    header->type = WAV_WAVE;
   
    chunk = buf+sizeof(WaveHeader);
    chunk->type = WAV_FMT;
    chunk->length = 16;

body = buf+sizeof(WaveHeader)+sizeof(WaveChunkHeader);
    body->format = (u_short)0x0001;      //编码方式为pcm
    body->channels = (u_short)0x02;      //声道数为2
    body->sample_fq = 44100;             //采样频率为44.1k 
    body->byte_p_sec = 176400;           //每秒所需字节数 44100*2*2=采样频率*声道*采样位数 
    body->byte_p_spl = (u_short)0x4;     //对齐无意义
    body->bit_p_spl = (u_short)16;       //采样位数16bit=2Byte

chunk = buf+sizeof(WaveHeader)+sizeof(WaveChunkHeader)+sizeof(WaveFmtBody);
    chunk->type = WAV_DATA;
    chunk->length = data_len;
    
    fwrite(buf, 1, len, fp);
    free(buf);
    return 0;
}

typedef struct {
    int videoindex;
    int sndindex;
    AVFormatContext* pFormatCtx;
    AVCodecContext* sndCodecCtx;
    AVCodec* sndCodec;
    SwrContext *swr_ctx;
    DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
}AudioState;

int init_ffmpeg(AudioState* is, char* filepath)
{
    int i=0;
    int ret;
    is->sndindex = -1;
    if(NULL == filepath)
    {
        dbmsg("input file is NULL");
        return -1;
    }
    avcodec_register_all();
    avfilter_register_all();
    av_register_all();

is->pFormatCtx = avformat_alloc_context();

if(avformat_open_input(&is->pFormatCtx, filepath, NULL, NULL)!=0)
        return -1;

if(avformat_find_stream_info(is->pFormatCtx, NULL)<0)
        return -1;
    av_dump_format(is->pFormatCtx,0, 0, 0);
    is->videoindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_VIDEO, is->videoindex, -1, NULL, 0); 
    is->sndindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_AUDIO,is->sndindex, is->videoindex, NULL, 0);
    dbmsg("videoindex=%d, sndindex=%d", is->videoindex, is->sndindex);
    if(is->sndindex != -1)
    {
        is->sndCodecCtx = is->pFormatCtx->streams[is->sndindex]->codec;
        is->sndCodec = avcodec_find_decoder(is->sndCodecCtx->codec_id);
        if(is->sndCodec == NULL)
        {
            dbmsg("Codec not found");
            return -1;
        }
        if(avcodec_open2(is->sndCodecCtx, is->sndCodec, NULL) < 0)
            return -1;
    }
    return 0;
}

int main(int argc, char **argv)
{
    int ret;
    FILE* fp; 
    int file_data_size = 0;                //这儿注意一个问题: 变量用时一定要初始化,否则会出现异常
    int len1,len2, data_size, got_frame;
    AVPacket *packet = av_mallocz(sizeof(AVPacket));
    AVFrame *frame = av_frame_alloc();
    AudioState* is = (AudioState*) av_mallocz(sizeof(AudioState));
    uint8_t *out[] = { is->audio_buf };
    fp = fopen("./test.wav", "wb+");
    len1 = sizeof(WaveHeader)+sizeof(WaveFmtBody)+sizeof(WaveChunkHeader)*2;
    fseek(fp,len1, SEEK_SET);      //在写之前先预留出wav的header,即44个字节
    dbmsg("len1=%d",len1);
     
    //第1步初始化ffmpeg,并用ffmpeg解码,最后转为pcm格式
    if( (ret=init_ffmpeg(is, argv[1])) != 0)            //1.1 初始化ffmpeg
    {
        dbmsg("init_ffmpeg error");
        return -1;
    }
    while( (av_read_frame(is->pFormatCtx, packet)>=0) )    //1.2 循环读取mp3文件中的数据帧
    { 
        if(packet->stream_index != is->sndindex)
            continue;
        if((ret=avcodec_decode_audio4(is->sndCodecCtx, frame, &got_frame, packet)) < 0) //1.3 解码数据帧
        {
            dbmsg("file eof");
            break;
        }

if(got_frame <= 0) /* No data yet, get more frames */
            continue;
        data_size = av_samples_get_buffer_size(NULL, is->sndCodecCtx->channels, frame->nb_samples, is->sndCodecCtx->sample_fmt, 1);
        //1.4下面将ffmpeg解码后的数据帧转为我们需要的数据(关于"需要的数据"下面有解释)
        if(NULL==is->swr_ctx)
        {
            if(is->swr_ctx != NULL)
                swr_free(&is->swr_ctx);
            dbmsg("frame: channnels=%d,format=%d, sample_rate=%d", frame->channels, frame->format, frame->sample_rate);
            is->swr_ctx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100, av_get_default_channel_layout(frame->channels), frame->format, frame->sample_rate, 0, NULL);
            if(is->swr_ctx == NULL)
            {
                dbmsg("swr_ctx == NULL");
            }
            swr_init(is->swr_ctx);
        }
        len2 = swr_convert(is->swr_ctx, out, 44100,(const uint8_t **)frame->extended_data, frame->nb_samples);
        file_data_size += len2;
        //1.5 数据格式转换完成后就写到文件中 
        fwrite((short *)is->audio_buf, sizeof(short), (size_t) len2* 2, fp);
    }
    file_data_size *= 4;
    dbmsg("file_data_size=%d", file_data_size);
    //第2步添加上wav的头
    ret = insert_wave_header(fp, file_data_size);
    av_free_packet(packet);
    av_free(frame);
    avcodec_close(is->sndCodecCtx);
    avformat_close_input(&is->pFormatCtx);
    fclose(fp);
    return 0;
}
2.运行结果
cong@msi:/work/ffmpeg/test/alsa/testalsa/5mp3towav$ make run
export LD_LIBRARY_PATH=/work/ffmpeg/out/lib/ \
    && ./mp3towav /work/ffmpeg/test/resource//test.mp3
mp3towav.c:main[150]: len1=44
[mp3 @ 0x14d3620] Skipping 0 bytes of junk at 197687.
libavutil/crc.c:av_crc_init[313]: 
[mp3 @ 0x14d3620] Estimating duration from bitrate, this may be inaccurate
Input #0, mp3, from '(null)':
  Metadata:
    artist : 佚名
    title : 法国国歌 马赛曲
    TYER : 2013-10-26
  Duration: 00:03:28.20, start: 0.000000, bitrate: 199 kb/s
    Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 192 kb/s
    Stream #0:1: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 600x600 [SAR 1:1 DAR 1:1], 90k tbr, 90k tbn, 90k tbc
    Metadata:
      title : e
      comment : Cover (front)
mp3towav.c:init_ffmpeg[120]: videoindex=-1381258232, sndindex=0
mp3towav.c:main[173]: frame: channnels=2,format=6, sample_rate=44100
mp3towav.c:main[186]: file_data_size=36725760
ls查看
cong@msi:/work/ffmpeg/test/alsa/testalsa/5mp3towav$ ls -l
total 36064
-rw-rw-r-- 1 cong cong 885 Sep 11 11:25 Makefile
-rwxrwxr-x 1 cong cong 64126 Sep 11 11:44 mp3towav
-rw-rw-r-- 1 cong cong 6183 Sep 11 11:24 mp3towav.c
-rw-rw-r-- 1 cong cong 115344 Sep 11 11:44 mp3towav.o
-rw-rw-r-- 1 cong cong 36725804 Sep 11 11:44 test.wav
-rw-rw-r-- 1 cong cong 333 Sep 9 11:31 utils.h
3. 说明
mp3towav.c:main[173]: AV_CH_LAYOUT_STEREO=3, AV_SAMPLE_FMT_S16=1, freq=44100
mp3towav.c:main[174]: frame: channnels=2, default_layout=3, format=6, sample_rate=44100
ffmpeg中:include/libavutil/samplefmt.h
enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1, 
    AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16, ///< signed 16 bits    --> 1 这个是pcm的数据格式
    AV_SAMPLE_FMT_S32, ///< signed 32 bits
    AV_SAMPLE_FMT_FLT, ///< float
    AV_SAMPLE_FMT_DBL, ///< double

AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar  -->6 这个是ffmepg解码之后的数据格式
    AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP, ///< float, planar
    AV_SAMPLE_FMT_DBLP, ///< double, planar

AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
interleaved -->理解为交叉存取  --> AV_SAMPLE_FMT_S16是两个声道的声音是交叉存储的
plannar--> 理解为平面存取       --> AV_SAMPLE_FMT_S16P是先存1个声道的数据再存另一个声道的数据

AV_SAMPLE_FMT_S16P is planar signed 16 bit audio, i.e. 2 bytes for each sample which is same for AV_SAMPLE_FMT_S16.

The only difference is in AV_SAMPLE_FMT_S16 samples of each channel are interleaved i.e. if you have two channel audio then the samples buffer will look like

c1 c1 c2 c2 c1 c1 c2 c2...                        -->AV_SAMPLE_FMT_S16的数据组织方式

where c1 is a sample for channel1 and c2 is sample for channel2.

while for one frame of planar audio you will have something like

c1 c1 c1 c1 .... c2 c2 c2 c2 ..                -->AV_SAMPLE_FMT_S16P的数据组织方式

now how is it stored in AVFrame:

for planar audio:

data[i] will contain the data of channel i (assuming channel 0 is first channel).

however if you have more channels then 8 then data for rest of the channels can be found in extended_data attribute of AVFrame.

for non-planar audio

data[0] will contain the data for all channels in an interleaved manner.

参考文章:
What is the difference between AV_SAMPLE_FMT_S16P and AV_SAMPLE_FMT_S16?
http://stackoverflow.com/questions/18888986/what-is-the-difference-between-av-sample-fmt-s16p-and-av-sample-fmt-s16
4. 代码打包 
5mp3towav.rar(下载后改名为5mp3towav.tar.gz)
————————————————
版权声明:本文为CSDN博主「wangcong02345」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wangcong02345/article/details/52399214

用ffmpeg将mp3转为wav相关推荐

  1. 使用FFmpeg转换mp3或wav文件为pcm格式文件

    使用FFmpeg转换mp3或wav文件为pcm格式文件 由于项目开发中需要验证pcm格式音频的播放,可以使用FFmpeg进行转换 安装时这里推荐一个便捷方式,sudo apt install smpl ...

  2. JAVA将MP3转为WAV(实现百度语音转译)

    近期实现的功能,不多说直接上代码(记得一些必要参数要配成自己的哈): 注意:1.本文由于存在语音文件的转换(百度api只支持pcm wav等有限类型,所以其他格式的音频需要自己转换),采用了ffmpe ...

  3. 批量将MP3或者m4a转为wav格式

    1 准备条件 需要安装ffmpeg,安装教程:[https://blog.csdn.net/liupeng19970119/article/details/110433807] 2 python代码 ...

  4. ffmpeg将ogg和wav格式转化为mp3

    ffmpeg将ogg和wav格式转化为mp3 因为钉钉和微信的iOS和android小程序版本音视频录制之后的格式与app录制不相同,因此我们需要使用ffmpeg将android录制的ogg格式和iO ...

  5. ffmpeg mp4 mp3 wav flac webm aac ac3 ogg格式转换

    转载自:ffmpeg mp4 mp3 wav flac webm aac ac3 ogg格式转换 - liuyihua1992 - 博客园 fmpeg是Linux中转换音频视频文件的常用工具. mp4 ...

  6. 基于FFMpeg实现音频mp3/aac/wav解码

    编译环境:Ubuntu16.04 64位 交叉编译工具:arm-himix200-linux-gcc 文章目录 1. ffmpeg源码下载 2. 交叉编译 3. 静态库链接 4. 头文件包含 5. 解 ...

  7. ffmpeg 将音频转为mp3问题解决

    安装完成ffmpeg后,就可以使用ffmpeg进行音频文件格式转换.比如 ./ffmpeg -i /media/1.mp3 /media/1.wav, 通过该命令行可以将/media文件夹下1.mp3 ...

  8. django中实现mp3转wav(使用ffmpeg)

    在django中使用ffmpeg实现mp3格式的音频 转换成 wav格式.作适当改造,也可以在非django项目中使用,本文仅提供实现方案,作为参考. 使用场景: 在微信小程序中录音,调用讯飞的相关音 ...

  9. ffmpeg window下批量转换MP3为wav

    转载链接:https://blog.csdn.net/fuchuchen/article/details/55214216 ffmpeg 在window下将MP3转换为wav文件 1)ffmpeg   ...

  10. 利用FFmpeg将立体声转为单声道wav

    os.system("sox {} -r 16k {}".format(path, new_path)) ffmpeg -y -i 345.wav -ac 1 345_dan.wa ...

最新文章

  1. vmware克隆centos修改linux mac地址
  2. 11--Rails数据交互3
  3. 本周个人总结(软件的初步开发)
  4. 在BAdI definition PRODUCT_R3_ADAPTER的implementation里获得download type
  5. aspx repeater 用法_ASP.NET-----Repeater数据控件的用法总结
  6. 自定义SharePoint 2013 元数据选择控件
  7. 集成测试用例_如何评估测试用例的有效性?
  8. 运输层课后第33题解析
  9. mysql创建数据库命令
  10. 【评测】常用免疫细胞培养基
  11. 应届生面试该注意的小技巧
  12. 关于STC单片机“假死”状态的判别和处理方法
  13. android 可以iphone,[实测]哪些Android手机充电器也可以给iPhone 12快充?
  14. PXE+Kickstart 无人值守安装系统
  15. 如何脱掉“梆梆加固”的保护壳
  16. 【2018年7月英语学习】--零散中星星点点
  17. 第一道bfs,撸了一晚上
  18. ftp工具绿色版,推荐5款好用的ftp工具绿色版,fyp客户端下载
  19. YUV图解 (YUV444, YUV422, YUV420, YV12, NV12, NV21)
  20. 分享|2023年全球市场准入认证咨讯

热门文章

  1. Unity 透视相机世界和屏幕坐标系转换
  2. 数据分析师必备的python包
  3. javaktv点歌系统项目(java点歌系统)java点歌管理系统
  4. 一阶微分方程的物理意义_薛定谔方程的物理意义
  5. CAB 写inf文件
  6. mysql 建表 game_RPG游戏数据库设计
  7. 苹果cms vod.html,苹果cms
  8. 快商通智能客服云平台、金融反欺诈方案获中科院互联网周刊金i奖
  9. [正则表达式] 校验经度和纬度
  10. 微信该服务器已饱满,微信故障背后:用户91pron过亿后的小故障有大影响