zoukankan      html  css  js  c++  java
  • MP3 编码解码 附完整c代码

    近期一直不间断学习音频处理,一直也没想着要去碰音频编解码相关。

    主要是觉得没什么实际的作用和意义。

    不管视频编解码,图像编解码,音频编解码,都有很多组织基金在推动。

    当然,在一些特定的情景下,需要用起来编解码库,

    而一般这些库都会有编译困难,使用困难等等困难综合症。

    图像方面,已经有stb_image,spot,freeimage等编解码库系列,做得特别赞。

    https://github.com/nothings/stb/

    https://github.com/r-lyeh-archived/spot

    http://freeimage.sourceforge.net/index.html

    当然有一段时间,jpeg的编码库也是个头疼的事情,直到tinyjpg的出现。

    视频这块有libav,ffmpeg

    https://libav.org/

    https://ffmpeg.org/

    而音频这块,就有点差强人意了。

    当然dr_libs 也已经做了不少工作了。

    https://github.com/mackron/dr_libs

    可惜的是,他做了wav的编解码库,mp3的解码库,就是没有mp3的编码库。

    而一般mp3 的编码库,大众使用最多的是lame

    http://lame.sourceforge.net/

    在一阵寻寻觅觅之后,俺找到了一个mp3的编码库。

    其原官网已经成为历史资源了。

    https://web.archive.org/web/20060102002813/http://www.everett9981.freeserve.co.uk/pete.htm

    也是相当历史久远了。

    也有人对其进行了回炉重造。

    https://github.com/toots/shine

    俺一直惦念着,找个时间,进行代码整合,blabla

    秉承着简洁简单的态度,就这么新鲜出炉了。

    在写示例代码的时候,踩了几个小坑。

    贴上完整代码:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <time.h>
      5 #include "timing.h"
      6 #include "shine_mp3.h"
      7 
      8 #define DR_WAV_IMPLEMENTATION
      9 
     10 #include "dr_wav.h"
     11 
     12 #define DR_MP3_IMPLEMENTATION
     13 
     14 #include "dr_mp3.h"
     15 
     16 void error(char *s);
     17 
     18 
     19 int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint32_t *channels, uint64_t *totalSampleCount) {
     20     int16_t *buffer = drwav_open_and_read_file_s16(filename, channels, sampleRate, totalSampleCount);
     21     if (buffer == NULL) {
     22         drmp3_config pConfig;
     23         float *mp3_buffer = drmp3_open_and_decode_file_f32(filename, &pConfig, totalSampleCount);
     24         if (mp3_buffer != NULL) {
     25             buffer = (int16_t *) calloc(*totalSampleCount, sizeof(int16_t));
     26             *channels = pConfig.outputChannels;
     27             *sampleRate = pConfig.outputSampleRate;
     28             if (buffer != NULL)
     29                 drwav_f32_to_s16(buffer, mp3_buffer, *totalSampleCount);
     30             free(mp3_buffer);
     31         } else {
     32             printf("read file [%s] error.
    ", filename);
     33         }
     34     }
     35     return buffer;
     36 }
     37 
     38 
     39 /* Some global vars. */
     40 char *infname, *outfname;
     41 FILE *outfile;
     42 int quiet = 0;
     43 int stereo = STEREO;
     44 int force_mono = 0;
     45 
     46 /* Write out the MP3 file */
     47 int write_mp3(long bytes, void *buffer, void *config) {
     48     return fwrite(buffer, sizeof(unsigned char), bytes, outfile) / sizeof(unsigned char);
     49 }
     50 
     51 /* Output error message and exit */
     52 void error(char *s) {
     53     fprintf(stderr, "Error: %s
    ", s);
     54     exit(1);
     55 }
     56 
     57 static void print_usage() {
     58     printf("Audio Processing
    ");
     59     printf("mp3 encoder && decoder
    ");
     60     printf("blog: http://cpuimage.cnblogs.com/
    ");
     61     printf("Usage: mp3 encoder && decoder [options] <infile> <outfile>
    
    ");
     62     printf("Use "-" for standard input or output.
    
    ");
     63     printf("Options:
    ");
     64     printf(" -h            this help message
    ");
     65     printf(" -b <bitrate>  set the bitrate [8-320], default 64 kbit
    ");
     66     printf(" -m            force encoder to operate in mono
    ");
     67     printf(" -c            set copyright flag, default off
    ");
     68     printf(" -j            encode in joint stereo (stereo data only)
    ");
     69     printf(" -d            encode in dual-channel (stereo data only)
    ");
     70     printf(" -q            quiet mode
    ");
     71     printf(" -v            verbose mode
    ");
     72 }
     73 
     74 /* Use these default settings, can be overridden */
     75 static void set_defaults(shine_config_t *config) {
     76     shine_set_config_mpeg_defaults(&config->mpeg);
     77 }
     78 
     79 /* Parse command line arguments */
     80 static int parse_command(int argc, char **argv, shine_config_t *config) {
     81     int i = 0;
     82 
     83     if (argc < 3) return 0;
     84 
     85     while (argv[++i][0] == '-' && argv[i][1] != '00' && argv[i][1] != ' ')
     86         switch (argv[i][1]) {
     87             case 'b':
     88                 config->mpeg.bitr = atoi(argv[++i]);
     89                 break;
     90 
     91             case 'm':
     92                 force_mono = 1;
     93                 break;
     94 
     95             case 'j':
     96                 stereo = JOINT_STEREO;
     97                 break;
     98 
     99             case 'd':
    100                 stereo = DUAL_CHANNEL;
    101                 break;
    102 
    103             case 'c':
    104                 config->mpeg.copyright = 1;
    105                 break;
    106 
    107             case 'q':
    108                 quiet = 1;
    109                 break;
    110 
    111             case 'v':
    112                 quiet = 0;
    113                 break;
    114 
    115             case 'h':
    116             default :
    117                 return 0;
    118         }
    119 
    120     if (argc - i != 2) return 0;
    121     infname = argv[i++];
    122     outfname = argv[i];
    123     return 1;
    124 }
    125 
    126 /* Print some info about what we're going to encode */
    127 static void check_config(shine_config_t *config) {
    128     static char *version_names[4] = {"2.5", "reserved", "II", "I"};
    129     static char *mode_names[4] = {"stereo", "joint-stereo", "dual-channel", "mono"};
    130     static char *demp_names[4] = {"none", "50/15us", "", "CITT"};
    131 
    132     printf("MPEG-%s layer III, %s  Psychoacoustic Model: Shine
    ",
    133            version_names[shine_check_config(config->wave.samplerate, config->mpeg.bitr)],
    134            mode_names[config->mpeg.mode]);
    135     printf("Bitrate: %d kbps  ", config->mpeg.bitr);
    136     printf("De-emphasis: %s   %s %s
    ",
    137            demp_names[config->mpeg.emph],
    138            ((config->mpeg.original) ? "Original" : ""),
    139            ((config->mpeg.copyright) ? "(C)" : ""));
    140     printf("Encoding "%s" to "%s"
    ", infname, outfname);
    141 }
    142 
    143 int main(int argc, char **argv) {
    144     shine_config_t config;
    145     shine_t s;
    146     int written;
    147     unsigned char *data;
    148     /* Set the default MPEG encoding paramters - basically init the struct */
    149     set_defaults(&config);
    150 
    151     if (!parse_command(argc, argv, &config)) {
    152         print_usage();
    153         exit(1);
    154     }
    155 
    156     quiet = quiet || !strcmp(outfname, "-");
    157 
    158     if (!quiet) {
    159         printf("Audio Processing
    ");
    160         printf("mp3 encoder && decoder
    ");
    161         printf("blog:http://cpuimage.cnblogs.com/
    ");
    162     }
    163     uint32_t sampleRate = 0;
    164     uint64_t totalSampleCount = 0;
    165     uint32_t channels = 0;
    166     int16_t *data_in = wavRead_int16(infname, &sampleRate, &channels, &totalSampleCount);
    167     if (data_in == NULL)
    168         return -1;
    169     double startTime = now();
    170     config.wave.samplerate = sampleRate;
    171     config.wave.channels = channels;
    172 
    173     if (force_mono)
    174         config.wave.channels = 1;
    175 
    176     /* See if samplerate and bitrate are valid */
    177     if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0)
    178         error("Unsupported samplerate/bitrate configuration.");
    179 
    180     /* open the output file */
    181     if (!strcmp(outfname, "-"))
    182         outfile = stdout;
    183     else
    184         outfile = fopen(outfname, "wb");
    185     if (!outfile) {
    186         fprintf(stderr, "Could not create "%s".
    ", outfname);
    187         exit(1);
    188     }
    189 
    190     /* Set to stereo mode if wave data is stereo, mono otherwise. */
    191     if (config.wave.channels > 1)
    192         config.mpeg.mode = stereo;
    193     else
    194         config.mpeg.mode = MONO;
    195 
    196     /* Initiate encoder */
    197     s = shine_initialise(&config);
    198 
    199     // assert(s != NULL);
    200     /* Print some info about the file about to be created (optional) */
    201     if (!quiet) check_config(&config);
    202 
    203     int samples_per_pass = shine_samples_per_pass(s) * channels;
    204 
    205     /* All the magic happens here */
    206     size_t count = totalSampleCount / samples_per_pass;
    207     int16_t *buffer = data_in;
    208     for (int i = 0; i < count; i++) {
    209         data = shine_encode_buffer_interleaved(s, buffer, &written);
    210         if (write_mp3(written, data, &config) != written) {
    211             fprintf(stderr, "mp3 encoder && decoder: write error
    ");
    212             return 1;
    213         }
    214         buffer += samples_per_pass;
    215     }
    216     size_t last = totalSampleCount % samples_per_pass;
    217     if (last != 0) {
    218         int16_t *cache = (int16_t *) calloc(samples_per_pass, sizeof(int16_t));
    219         if (cache != NULL) {
    220             memcpy(cache, buffer, last * sizeof(int16_t));
    221             data = shine_encode_buffer_interleaved(s, cache, &written);
    222             free(cache);
    223             if (write_mp3(written, data, &config) != written) {
    224                 fprintf(stderr, "mp3 encoder && decoder: write error
    ");
    225                 return 1;
    226             }
    227         }
    228     }
    229     /* Flush and write remaining data. */
    230     data = shine_flush(s, &written);
    231     write_mp3(written, data, &config);
    232     /* Close encoder. */
    233     shine_close(s);
    234     /* Close the MP3 file */
    235     fclose(outfile);
    236     free(data_in);
    237     double time_interval = calcElapsed(startTime, now());
    238     if (!quiet)
    239         printf("time interval: %d ms
     ", (int) (time_interval * 1000));
    240 
    241     return 0;
    242 }

    熟悉我的风格的朋友们,估计一看就清楚了。

    也不多做解释,当然了,这份代码是学习mp3编解码的不二之选。

    使用示例:

    tinymp3 -b 64 input.mp3 ouput.mp3

    tinymp3 -b 64 input.wav ouput.mp3

    相关参数说明:

    Usage: tinymp3  [options] <infile> <outfile>

    Use "-" for standard input or output.

    Options:
    -h this help message
    -b <bitrate> set the bitrate [8-320], default 64 kbit
    -m force encoder to operate in mono
    -c set copyright flag, default off
    -j encode in joint stereo (stereo data only)
    -d encode in dual-channel (stereo data only)
    -q quiet mode

    不做解释,直接上取下项目,cmake一下,你懂的。

    项目地址:

    https://github.com/cpuimage/tinymp3

    前面有不少朋友问到音频重采样库的问题,抽空整理了下speex的resampler。

    我想重采样这方面也是够用的了。

    项目地址:

    https://github.com/cpuimage/speex_resampler

    以上,权当抛砖引玉。

    另外感谢 热心网友打赏两瓶可乐。

    独乐乐,不如众乐乐。

    若有其他相关问题或者需求也可以邮件联系俺探讨。

    邮箱地址是: 
    gaozhihan@vip.qq.com

  • 相关阅读:
    吴裕雄 python深度学习与实践(1)
    吴裕雄 python 机器学习-Logistic(1)
    吴裕雄 python 熵权法确定特征权重
    【Uva 1252】Twenty Questions
    【玲珑杯 round#18 B】图论你先敲完模板
    【Uva 10817】Headmaster's Headache
    【玲珑杯 round#18 A】计算几何你瞎暴力
    【Uva 12128】Perfect Service
    【UVa 12186】Another Crisis
    【Uva 10003】Cutting Sticks
  • 原文地址:https://www.cnblogs.com/cpuimage/p/9427457.html
Copyright © 2011-2022 走看看