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

    转:https://www.cnblogs.com/cpuimage/p/9427457.html

    WAV转MP3场景,已经验证,其他场景待验证

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

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

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

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

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

    图像方面,已经有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

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

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

    贴上完整代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include "timing.h"
    #include "shine_mp3.h"
    
    #define DR_WAV_IMPLEMENTATION
    
    #include "dr_wav.h"
    
    #define DR_MP3_IMPLEMENTATION
    
    #include "dr_mp3.h"
    
    void error(char *s);
    
    
    int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint32_t *channels, uint64_t *totalSampleCount) {
        int16_t *buffer = drwav_open_and_read_file_s16(filename, channels, sampleRate, totalSampleCount);
        if (buffer == NULL) {
            drmp3_config pConfig;
            float *mp3_buffer = drmp3_open_and_decode_file_f32(filename, &pConfig, totalSampleCount);
            if (mp3_buffer != NULL) {
                buffer = (int16_t *) calloc(*totalSampleCount, sizeof(int16_t));
                *channels = pConfig.outputChannels;
                *sampleRate = pConfig.outputSampleRate;
                if (buffer != NULL)
                    drwav_f32_to_s16(buffer, mp3_buffer, *totalSampleCount);
                free(mp3_buffer);
            } else {
                printf("read file [%s] error.
    ", filename);
            }
        }
        return buffer;
    }
    
    
    /* Some global vars. */
    char *infname, *outfname;
    FILE *outfile;
    int quiet = 0;
    int stereo = STEREO;
    int force_mono = 0;
    
    /* Write out the MP3 file */
    int write_mp3(long bytes, void *buffer, void *config) {
        return fwrite(buffer, sizeof(unsigned char), bytes, outfile) / sizeof(unsigned char);
    }
    
    /* Output error message and exit */
    void error(char *s) {
        fprintf(stderr, "Error: %s
    ", s);
        exit(1);
    }
    
    static void print_usage() {
        printf("Audio Processing
    ");
        printf("mp3 encoder && decoder
    ");
        printf("blog: http://cpuimage.cnblogs.com/
    ");
        printf("Usage: mp3 encoder && decoder [options] <infile> <outfile>
    
    ");
        printf("Use "-" for standard input or output.
    
    ");
        printf("Options:
    ");
        printf(" -h            this help message
    ");
        printf(" -b <bitrate>  set the bitrate [8-320], default 64 kbit
    ");
        printf(" -m            force encoder to operate in mono
    ");
        printf(" -c            set copyright flag, default off
    ");
        printf(" -j            encode in joint stereo (stereo data only)
    ");
        printf(" -d            encode in dual-channel (stereo data only)
    ");
        printf(" -q            quiet mode
    ");
        printf(" -v            verbose mode
    ");
    }
    
    /* Use these default settings, can be overridden */
    static void set_defaults(shine_config_t *config) {
        shine_set_config_mpeg_defaults(&config->mpeg);
    }
    
    /* Parse command line arguments */
    static int parse_command(int argc, char **argv, shine_config_t *config) {
        int i = 0;
    
        if (argc < 3) return 0;
    
        while (argv[++i][0] == '-' && argv[i][1] != '00' && argv[i][1] != ' ')
            switch (argv[i][1]) {
                case 'b':
                    config->mpeg.bitr = atoi(argv[++i]);
                    break;
    
                case 'm':
                    force_mono = 1;
                    break;
    
                case 'j':
                    stereo = JOINT_STEREO;
                    break;
    
                case 'd':
                    stereo = DUAL_CHANNEL;
                    break;
    
                case 'c':
                    config->mpeg.copyright = 1;
                    break;
    
                case 'q':
                    quiet = 1;
                    break;
    
                case 'v':
                    quiet = 0;
                    break;
    
                case 'h':
                default :
                    return 0;
            }
    
        if (argc - i != 2) return 0;
        infname = argv[i++];
        outfname = argv[i];
        return 1;
    }
    
    /* Print some info about what we're going to encode */
    static void check_config(shine_config_t *config) {
        static char *version_names[4] = {"2.5", "reserved", "II", "I"};
        static char *mode_names[4] = {"stereo", "joint-stereo", "dual-channel", "mono"};
        static char *demp_names[4] = {"none", "50/15us", "", "CITT"};
    
        printf("MPEG-%s layer III, %s  Psychoacoustic Model: Shine
    ",
               version_names[shine_check_config(config->wave.samplerate, config->mpeg.bitr)],
               mode_names[config->mpeg.mode]);
        printf("Bitrate: %d kbps  ", config->mpeg.bitr);
        printf("De-emphasis: %s   %s %s
    ",
               demp_names[config->mpeg.emph],
               ((config->mpeg.original) ? "Original" : ""),
               ((config->mpeg.copyright) ? "(C)" : ""));
        printf("Encoding "%s" to "%s"
    ", infname, outfname);
    }
    
    int main(int argc, char **argv) {
        shine_config_t config;
        shine_t s;
        int written;
        unsigned char *data;
        /* Set the default MPEG encoding paramters - basically init the struct */
        set_defaults(&config);
    
        if (!parse_command(argc, argv, &config)) {
            print_usage();
            exit(1);
        }
    
        quiet = quiet || !strcmp(outfname, "-");
    
        if (!quiet) {
            printf("Audio Processing
    ");
            printf("mp3 encoder && decoder
    ");
            printf("blog:http://cpuimage.cnblogs.com/
    ");
        }
        uint32_t sampleRate = 0;
        uint64_t totalSampleCount = 0;
        uint32_t channels = 0;
        int16_t *data_in = wavRead_int16(infname, &sampleRate, &channels, &totalSampleCount);
        if (data_in == NULL)
            return -1;
        double startTime = now();
        config.wave.samplerate = sampleRate;
        config.wave.channels = channels;
    
        if (force_mono)
            config.wave.channels = 1;
    
        /* See if samplerate and bitrate are valid */
        if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0)
            error("Unsupported samplerate/bitrate configuration.");
    
        /* open the output file */
        if (!strcmp(outfname, "-"))
            outfile = stdout;
        else
            outfile = fopen(outfname, "wb");
        if (!outfile) {
            fprintf(stderr, "Could not create "%s".
    ", outfname);
            exit(1);
        }
    
        /* Set to stereo mode if wave data is stereo, mono otherwise. */
        if (config.wave.channels > 1)
            config.mpeg.mode = stereo;
        else
            config.mpeg.mode = MONO;
    
        /* Initiate encoder */
        s = shine_initialise(&config);
    
        // assert(s != NULL);
        /* Print some info about the file about to be created (optional) */
        if (!quiet) check_config(&config);
    
        int samples_per_pass = shine_samples_per_pass(s) * channels;
    
        /* All the magic happens here */
        size_t count = totalSampleCount / samples_per_pass;
        int16_t *buffer = data_in;
        for (int i = 0; i < count; i++) {
            data = shine_encode_buffer_interleaved(s, buffer, &written);
            if (write_mp3(written, data, &config) != written) {
                fprintf(stderr, "mp3 encoder && decoder: write error
    ");
                return 1;
            }
            buffer += samples_per_pass;
        }
        size_t last = totalSampleCount % samples_per_pass;
        if (last != 0) {
            int16_t *cache = (int16_t *) calloc(samples_per_pass, sizeof(int16_t));
            if (cache != NULL) {
                memcpy(cache, buffer, last * sizeof(int16_t));
                data = shine_encode_buffer_interleaved(s, cache, &written);
                free(cache);
                if (write_mp3(written, data, &config) != written) {
                    fprintf(stderr, "mp3 encoder && decoder: write error
    ");
                    return 1;
                }
            }
        }
        /* Flush and write remaining data. */
        data = shine_flush(s, &written);
        write_mp3(written, data, &config);
        /* Close encoder. */
        shine_close(s);
        /* Close the MP3 file */
        fclose(outfile);
        free(data_in);
        double time_interval = calcElapsed(startTime, now());
        if (!quiet)
            printf("time interval: %d ms
     ", (int) (time_interval * 1000));
    
        return 0;
    }
    

      

    注释:由于编译环境部不同,有基础枚举复制,可以需要强制转换

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

    也不多做解释,当然了,这份代码是学习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

  • 相关阅读:
    一次函数(好难的一次函数)
    脱水缩合(大搜索)
    背单词
    仙人掌(cactus)
    LYK 快跑!(LYK别打我-)(话说LYK是谁)
    巧克力棒
    选数字(贪心+枚举)
    看程序写结果(program)
    np问题
    IUYYLIUIU
  • 原文地址:https://www.cnblogs.com/cyblogs/p/10722306.html
Copyright © 2011-2022 走看看