博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MP3 编码解码 附完整c代码
阅读量:6305 次
发布时间:2019-06-22

本文共 8320 字,大约阅读时间需要 27 分钟。

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

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

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

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

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

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

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

视频这块有libav,ffmpeg

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

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

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

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

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

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

也是相当历史久远了。

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

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

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

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

贴上完整代码:

1 #include 
2 #include
3 #include
4 #include
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.\n", 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\n", s); 54 exit(1); 55 } 56 57 static void print_usage() { 58 printf("Audio Processing\n"); 59 printf("mp3 encoder && decoder\n"); 60 printf("blog: http://cpuimage.cnblogs.com/\n"); 61 printf("Usage: mp3 encoder && decoder [options]
\n\n"); 62 printf("Use \"-\" for standard input or output.\n\n"); 63 printf("Options:\n"); 64 printf(" -h this help message\n"); 65 printf(" -b
set the bitrate [8-320], default 64 kbit\n"); 66 printf(" -m force encoder to operate in mono\n"); 67 printf(" -c set copyright flag, default off\n"); 68 printf(" -j encode in joint stereo (stereo data only)\n"); 69 printf(" -d encode in dual-channel (stereo data only)\n"); 70 printf(" -q quiet mode\n"); 71 printf(" -v verbose mode\n"); 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] != '\000' && 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\n",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\n",137 demp_names[config->mpeg.emph],138 ((config->mpeg.original) ? "Original" : ""),139 ((config->mpeg.copyright) ? "(C)" : ""));140 printf("Encoding \"%s\" to \"%s\"\n", 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\n");160 printf("mp3 encoder && decoder\n");161 printf("blog:http://cpuimage.cnblogs.com/\n");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 else184 outfile = fopen(outfname, "wb");185 if (!outfile) {186 fprintf(stderr, "Could not create \"%s\".\n", 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 else194 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\n");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\n");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\n ", (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一下,你懂的。

项目地址:

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

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

项目地址:

以上,权当抛砖引玉。

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

独乐乐,不如众乐乐。

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

邮箱地址是: 

gaozhihan@vip.qq.com

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

你可能感兴趣的文章
基于epoll封装的事件回调miniserver
查看>>
天猫高管全面解读大快消2018新零售打法
查看>>
idea springboot热部署无效问题
查看>>
第八章 进程间通信
查看>>
HttpSession接口中的方法(Jsp中的session类的用法)
查看>>
「镁客早报」AI可预测心脏病人死亡时间;机器人开始在美国送外卖
查看>>
MoQ(基于.net3.5,c#3.0的mock框架)简单介绍
查看>>
物联网全面升级,十年内推动工业进入智能化新阶段
查看>>
spring-通过ListFactory注入List
查看>>
一种基于SDR实现的被动GSM嗅探
查看>>
阿里云ECS每天一件事D1:配置SSH
查看>>
SQL Server 性能调优(性能基线)
查看>>
uva 10801 - Lift Hopping(最短路Dijkstra)
查看>>
[Java Web]servlet/filter/listener/interceptor区别与联系
查看>>
POJ 2312Battle City(BFS-priority_queue 或者是建图spfa)
查看>>
从零开始学MVC3——创建项目
查看>>
CentOS 7 巨大变动之 firewalld 取代 iptables
查看>>
延时任务和定时任务
查看>>
linux下的权限问题
查看>>
教你如何使用Flutter和原生App混合开发
查看>>