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