Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2159619
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-09-11 11:46:06

一.
1. 利用fffmpeg将mp3转为pcm并在pcm数据加上wav头就是一个完整的wav文件
2. 代码
  1. #include "utils.h"
  2. #include <libavutil/avutil.h>
  3. #include <libavutil/attributes.h>
  4. #include <libavutil/opt.h>
  5. #include <libavutil/mathematics.h>
  6. #include <libavutil/imgutils.h>
  7. #include <libavutil/samplefmt.h>
  8. #include <libavutil/timestamp.h>
  9. #include <libavformat/avformat.h>
  10. #include <libavcodec/avcodec.h>
  11. #include <libswscale/swscale.h>
  12. #include <libavutil/mathematics.h>
  13. #include <libswresample/swresample.h>
  14. #include <libavutil/channel_layout.h>
  15. #include <libavutil/common.h>
  16. #include <libavformat/avio.h>
  17. #include <libavutil/file.h>
  18. #include <libswresample/swresample.h>

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

  26. typedef struct {
  27.     u_short format;       /* see WAV_FMT_* */
  28.     u_short channels;
  29.     u_int sample_fq;      /* frequence of sample */
  30.     u_int byte_p_sec;
  31.     u_short byte_p_spl;   /* samplesize; 1 or 2 bytes */
  32.     u_short bit_p_spl;    /* 8, 12 or 16 bit */
  33. } WaveFmtBody;

  34. typedef struct {
  35.     u_int type;        /* 'data' */
  36.     u_int length;      /* samplecount */
  37. } WaveChunkHeader;

  38. #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
  39. #define WAV_RIFF COMPOSE_ID('R','I','F','F')
  40. #define WAV_WAVE COMPOSE_ID('W','A','V','E')
  41. #define WAV_FMT COMPOSE_ID('f','m','t',' ')
  42. #define WAV_DATA COMPOSE_ID('d','a','t','a')
  43. int insert_wave_header(FILE* fp, long data_len)
  44. {
  45.     int len;
  46.     WaveHeader* header;
  47.     WaveChunkHeader* chunk;
  48.     WaveFmtBody* body;
  49.     
  50.     fseek(fp, 0, SEEK_SET);        //写到wav文件的开始处
  51.     
  52.     len = sizeof(WaveHeader)+sizeof(WaveFmtBody)+sizeof(WaveChunkHeader)*2;
  53.     char* buf = (char*)malloc(len);
  54.     header = (WaveHeader*)buf;
  55.     header->magic = WAV_RIFF;
  56.     header->length = data_len + sizeof(WaveFmtBody)+sizeof(WaveChunkHeader)*2 + 4;
  57.     header->type = WAV_WAVE;
  58.    
  59.     chunk = buf+sizeof(WaveHeader);
  60.     chunk->type = WAV_FMT;
  61.     chunk->length = 16;

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


  69.     chunk = buf+sizeof(WaveHeader)+sizeof(WaveChunkHeader)+sizeof(WaveFmtBody);
  70.     chunk->type = WAV_DATA;
  71.     chunk->length = data_len;
  72.    
  73.     fwrite(buf, 1, len, fp);
  74.     free(buf);
  75.     return 0;
  76. }

  77. typedef struct {
  78.     int videoindex;
  79.     int sndindex;
  80.     AVFormatContext* pFormatCtx;
  81.     AVCodecContext* sndCodecCtx;
  82.     AVCodec* sndCodec;
  83.     SwrContext *swr_ctx;
  84.     DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
  85. }AudioState;

  86. int init_ffmpeg(AudioState* is, char* filepath)
  87. {
  88.     int i=0;
  89.     int ret;
  90.     is->sndindex = -1;
  91.     if(NULL == filepath)
  92.     {
  93.         dbmsg("input file is NULL");
  94.         return -1;
  95.     }
  96.     avcodec_register_all();
  97.     avfilter_register_all();
  98.     av_register_all();

  99.     is->pFormatCtx = avformat_alloc_context();

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

  102.     if(avformat_find_stream_info(is->pFormatCtx, NULL)<0)
  103.         return -1;
  104.     av_dump_format(is->pFormatCtx,0, 0, 0);
  105.     is->videoindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_VIDEO, is->videoindex, -1, NULL, 0);
  106.     is->sndindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_AUDIO,is->sndindex, is->videoindex, NULL, 0);
  107.     dbmsg("videoindex=%d, sndindex=%d", is->videoindex, is->sndindex);
  108.     if(is->sndindex != -1)
  109.     {
  110.         is->sndCodecCtx = is->pFormatCtx->streams[is->sndindex]->codec;
  111.         is->sndCodec = avcodec_find_decoder(is->sndCodecCtx->codec_id);
  112.         if(is->sndCodec == NULL)
  113.         {
  114.             dbmsg("Codec not found");
  115.             return -1;
  116.         }
  117.         if(avcodec_open2(is->sndCodecCtx, is->sndCodec, NULL) < 0)
  118.             return -1;
  119.     }
  120.     return 0;
  121. }

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

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

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

  14.     AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
  15. };
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?

4. 代码打包
5mp3towav.rar(下载后改名为5mp3towav.tar.gz)

阅读(4462) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~