近期一直不间断学习音频处理,一直也没想着要去碰音频编解码相关。
主要是觉得没什么实际的作用和意义。
不管视频编解码,图像编解码,音频编解码,都有很多组织基金在推动。
当然,在一些特定的情景下,需要用起来编解码库,
而一般这些库都会有编译困难,使用困难等等困难综合症。
图像方面,已经有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
而音频这块,就有点差强人意了。
当然dr_libs 也已经做了不少工作了。
https://github.com/mackron/dr_libs
可惜的是,他做了wav的编解码库,mp3的解码库,就是没有mp3的编码库。
而一般mp3 的编码库,大众使用最多的是lame
在一阵寻寻觅觅之后,俺找到了一个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.\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] <infile> <outfile>\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 <bitrate> 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 else
184 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 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\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一下,你懂的。
项目地址:
https://github.com/cpuimage/tinymp3
前面有不少朋友问到音频重采样库的问题,抽空整理了下speex的resampler。
我想重采样这方面也是够用的了。
项目地址:
https://github.com/cpuimage/speex_resampler
以上,权当抛砖引玉。
另外感谢 热心网友打赏两瓶可乐。
独乐乐,不如众乐乐。
若有其他相关问题或者需求也可以邮件联系俺探讨。
邮箱地址是:
gaozhihan@vip.qq.com
来源:oschina
链接:https://my.oschina.net/u/4279418/blog/3505699