1 /*
2 feedseek: test program for libmpg123, showing how to use fuzzy seeking in feeder mode
3 copyright 2008 by the mpg123 project - free software under the terms of the LGPL 2.1
4 see COPYING and AUTHORS files in distribution or http://mpg123.org
5 */
6
7 #include <mpg123.h>
8 #include <stdio.h>
9
10 #define INBUFF 16384 * 2 * 2
11 #define WAVE_FORMAT_PCM 0x0001
12 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
13
14 FILE *out;
15 size_t totaloffset, dataoffset;
16 long rate;
17 int channels, enc;
18 unsigned short bitspersample, wavformat;
19
20 // write wav header
initwav()21 void initwav()
22 {
23 unsigned int tmp32 = 0;
24 unsigned short tmp16 = 0;
25
26 fwrite("RIFF", 1, 4, out);
27 totaloffset = ftell(out);
28
29 fwrite(&tmp32, 1, 4, out); // total size
30 fwrite("WAVE", 1, 4, out);
31 fwrite("fmt ", 1, 4, out);
32 tmp32 = 16;
33 fwrite(&tmp32, 1, 4, out); // format length
34 tmp16 = wavformat;
35 fwrite(&tmp16, 1, 2, out); // format
36 tmp16 = channels;
37 fwrite(&tmp16, 1, 2, out); // channels
38 tmp32 = rate;
39 fwrite(&tmp32, 1, 4, out); // sample rate
40 tmp32 = rate * bitspersample/8 * channels;
41 fwrite(&tmp32, 1, 4, out); // bytes / second
42 tmp16 = bitspersample/8 * channels; // float 16 or signed int 16
43 fwrite(&tmp16, 1, 2, out); // block align
44 tmp16 = bitspersample;
45 fwrite(&tmp16, 1, 2, out); // bits per sample
46 fwrite("data ", 1, 4, out);
47 tmp32 = 0;
48 dataoffset = ftell(out);
49 fwrite(&tmp32, 1, 4, out); // data length
50 }
51
52 // rewrite wav header with final length infos
closewav()53 void closewav()
54 {
55 unsigned int tmp32 = 0;
56 unsigned short tmp16 = 0;
57
58 long total = ftell(out);
59 fseek(out, totaloffset, SEEK_SET);
60 tmp32 = total - (totaloffset + 4);
61 fwrite(&tmp32, 1, 4, out);
62 fseek(out, dataoffset, SEEK_SET);
63 tmp32 = total - (dataoffset + 4);
64
65 fwrite(&tmp32, 1, 4, out);
66 }
67
68 // determine correct wav format and bits per sample
69 // from mpg123 enc value
initwavformat()70 void initwavformat()
71 {
72 if(enc & MPG123_ENC_FLOAT_64)
73 {
74 bitspersample = 64;
75 wavformat = WAVE_FORMAT_IEEE_FLOAT;
76 }
77 else if(enc & MPG123_ENC_FLOAT_32)
78 {
79 bitspersample = 32;
80 wavformat = WAVE_FORMAT_IEEE_FLOAT;
81 }
82 else if(enc & MPG123_ENC_16)
83 {
84 bitspersample = 16;
85 wavformat = WAVE_FORMAT_PCM;
86 }
87 else
88 {
89 bitspersample = 8;
90 wavformat = WAVE_FORMAT_PCM;
91 }
92 }
93
main(int argc,char ** argv)94 int main(int argc, char **argv)
95 {
96 unsigned char buf[INBUFF];
97 unsigned char *audio;
98 FILE *in;
99 mpg123_handle *m;
100 int ret, state;
101 size_t inc, outc;
102 off_t len, num;
103 size_t bytes;
104 off_t inoffset;
105 inc = outc = 0;
106
107 if(argc < 3)
108 {
109 fprintf(stderr,"Please supply in and out filenames\n");
110 return -1;
111 }
112
113 mpg123_init();
114
115 m = mpg123_new(NULL, &ret);
116 if(m == NULL)
117 {
118 fprintf(stderr,"Unable to create mpg123 handle: %s\n", mpg123_plain_strerror(ret));
119 return -1;
120 }
121
122 mpg123_param(m, MPG123_VERBOSE, 2, 0);
123
124 ret = mpg123_param(m, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS, 0);
125 if(ret != MPG123_OK)
126 {
127 fprintf(stderr,"Unable to set library options: %s\n", mpg123_plain_strerror(ret));
128 return -1;
129 }
130
131 // Let the seek index auto-grow and contain an entry for every frame
132 ret = mpg123_param(m, MPG123_INDEX_SIZE, -1, 0);
133 if(ret != MPG123_OK)
134 {
135 fprintf(stderr,"Unable to set index size: %s\n", mpg123_plain_strerror(ret));
136 return -1;
137 }
138
139 ret = mpg123_format_none(m);
140 if(ret != MPG123_OK)
141 {
142 fprintf(stderr,"Unable to disable all output formats: %s\n", mpg123_plain_strerror(ret));
143 return -1;
144 }
145
146 // Use float output
147 ret = mpg123_format(m, 44100, MPG123_MONO | MPG123_STEREO, MPG123_ENC_FLOAT_32);
148 if(ret != MPG123_OK)
149 {
150 fprintf(stderr,"Unable to set float output formats: %s\n", mpg123_plain_strerror(ret));
151 return -1;
152 }
153
154 ret = mpg123_open_feed(m);
155 if(ret != MPG123_OK)
156 {
157 fprintf(stderr,"Unable open feed: %s\n", mpg123_plain_strerror(ret));
158 return -1;
159 }
160
161 in = fopen(argv[1], "rb");
162 if(in == NULL)
163 {
164 fprintf(stderr,"Unable to open input file %s\n", argv[1]);
165 return -1;
166 }
167
168 out = fopen(argv[2], "wb");
169 if(out == NULL)
170 {
171 fclose(in);
172 fprintf(stderr,"Unable to open output file %s\n", argv[2]);
173 return -1;
174 }
175
176 fprintf(stderr, "Seeking...\n");
177 /* That condition is tricky... parentheses are crucial... */
178 while((ret = mpg123_feedseek(m, 95000, SEEK_SET, &inoffset)) == MPG123_NEED_MORE)
179 {
180 len = fread(buf, sizeof(unsigned char), INBUFF, in);
181 if(len <= 0)
182 break;
183 inc += len;
184
185 state = mpg123_feed(m, buf, len);
186 if(state == MPG123_ERR)
187 {
188 fprintf(stderr, "Error: %s", mpg123_strerror(m));
189 return -1;
190 }
191 }
192 if(ret == MPG123_ERR)
193 {
194 fprintf(stderr, "Feedseek failed: %s\n", mpg123_strerror(m));
195 return -1;
196 }
197
198 fseek(in, inoffset, SEEK_SET);
199
200 fprintf(stderr, "Starting decode...\n");
201 while(1)
202 {
203 len = fread(buf, sizeof(unsigned char), INBUFF, in);
204 if(len <= 0)
205 break;
206 inc += len;
207 ret = mpg123_feed(m, buf, len);
208
209 while(ret != MPG123_ERR && ret != MPG123_NEED_MORE)
210 {
211 ret = mpg123_decode_frame(m, &num, &audio, &bytes);
212 if(ret == MPG123_NEW_FORMAT)
213 {
214 mpg123_getformat(m, &rate, &channels, &enc);
215 initwavformat();
216 initwav();
217 fprintf(stderr, "New format: %li Hz, %i channels, encoding value %i\n", rate, channels, enc);
218 }
219 fwrite(audio, sizeof(unsigned char), bytes, out);
220 outc += bytes;
221 }
222
223 if(ret == MPG123_ERR)
224 {
225 fprintf(stderr, "Error: %s", mpg123_strerror(m));
226 break;
227 }
228 }
229
230 fprintf(stderr, "Finished\n", (unsigned long)inc, (unsigned long)outc);
231
232 closewav();
233 fclose(out);
234 fclose(in);
235 mpg123_delete(m);
236 mpg123_exit();
237 return 0;
238 }
239