Rev 799 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 799 | Rev 5485 | ||
---|---|---|---|
1 | #include "mpg123.h" |
1 | #include "mpg123.h" |
2 | #include "..\kolibri.h" |
2 | #include "..\kolibri.h" |
3 | 3 | ||
4 | #define MAXFRAMESIZE 3456 |
4 | #define MAXFRAMESIZE 3456 |
5 | 5 | ||
6 | static int fsizeold=0,ssize; |
6 | static int fsizeold=0,ssize; |
7 | static unsigned char bsspace[2][MAXFRAMESIZE+512]; /* MAXFRAMESIZE */ |
7 | static unsigned char bsspace[2][MAXFRAMESIZE+512]; /* MAXFRAMESIZE */ |
8 | static unsigned char *bsbuf=bsspace[1],*bsbufold; |
8 | static unsigned char *bsbuf=bsspace[1],*bsbufold; |
9 | static int bsnum=0; |
9 | static int bsnum=0; |
10 | 10 | ||
11 | static unsigned long oldhead = 0; |
11 | static unsigned long oldhead = 0; |
12 | unsigned long firsthead=0; |
12 | unsigned long firsthead=0; |
13 | 13 | ||
14 | struct bitstream_info bsi; |
14 | struct bitstream_info bsi; |
15 | 15 | ||
16 | int tabsel_123[2][3][16] = { |
16 | int tabsel_123[2][3][16] = { |
17 | { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, |
17 | { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, |
18 | {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, |
18 | {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, |
19 | {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }, |
19 | {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }, |
20 | 20 | ||
21 | { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, |
21 | { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, |
22 | {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, |
22 | {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, |
23 | {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} } |
23 | {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} } |
24 | }; |
24 | }; |
25 | 25 | ||
26 | int freqs[9] = { 44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000 }; |
26 | int freqs[9] = { 44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000 }; |
27 | 27 | ||
28 | int stream_head_read(struct reader *rd,unsigned long *newhead); |
28 | int stream_head_read(struct reader *rd,unsigned long *newhead); |
29 | int stream_read_raw(struct reader *rd,unsigned char *buf, int size); |
29 | int stream_read_raw(struct reader *rd,unsigned char *buf, int size); |
30 | 30 | ||
31 | void set_synth_functions(struct frame *fr) |
31 | void set_synth_functions(struct frame *fr) |
32 | { |
32 | { |
33 | #ifdef USE_3DNOW |
33 | #ifdef USE_3DNOW |
34 | static func_dct36 funcs_dct36[2] = {dct36 , dct36_3dnow}; |
34 | static func_dct36 funcs_dct36[2] = {dct36 , dct36_3dnow}; |
35 | #endif |
35 | #endif |
36 | 36 | ||
37 | fr->synth = synth_1to1; |
37 | fr->synth = synth_1to1; |
38 | fr->synth_mono = synth_1to1_mono2stereo;; |
38 | fr->synth_mono = synth_1to1_mono2stereo;; |
39 | 39 | ||
40 | /* TODO: make autodetection for _all_ x86 optimizations (maybe just for i586+ and keep separate 486 build?) */ |
40 | /* TODO: make autodetection for _all_ x86 optimizations (maybe just for i586+ and keep separate 486 build?) */ |
41 | #ifdef USE_3DNOW |
41 | #ifdef USE_3DNOW |
42 | /* check cpuflags bit 31 (3DNow!) and 23 (MMX) */ |
42 | /* check cpuflags bit 31 (3DNow!) and 23 (MMX) */ |
43 | if((param.stat_3dnow < 2) && |
43 | if((param.stat_3dnow < 2) && |
44 | ((param.stat_3dnow == 1) || |
44 | ((param.stat_3dnow == 1) || |
45 | (getcpuflags() & 0x80800000) == 0x80800000)) |
45 | (getcpuflags() & 0x80800000) == 0x80800000)) |
46 | { |
46 | { |
47 | fr->synth = funcs[2][ds]; /* 3DNow! optimized synth_1to1() */ |
47 | fr->synth = funcs[2][ds]; /* 3DNow! optimized synth_1to1() */ |
48 | fr->dct36 = funcs_dct36[1]; /* 3DNow! optimized dct36() */ |
48 | fr->dct36 = funcs_dct36[1]; /* 3DNow! optimized dct36() */ |
49 | } |
49 | } |
50 | else |
50 | else |
51 | { |
51 | { |
52 | fr->dct36 = funcs_dct36[0]; |
52 | fr->dct36 = funcs_dct36[0]; |
53 | } |
53 | } |
54 | #endif |
54 | #endif |
55 | } |
55 | } |
56 | 56 | ||
57 | int __stdcall create_reader(struct reader *rd,byte *buffer, int buffsize) |
57 | int __stdcall create_reader(struct reader *rd,byte *buffer, int buffsize) |
58 | { rd->head_read = stream_head_read; |
58 | { rd->head_read = stream_head_read; |
59 | rd->read_frame_body = stream_read_raw; |
59 | rd->read_frame_body = stream_read_raw; |
60 | 60 | ||
61 | rd->buffer = buffer; |
61 | rd->buffer = buffer; |
62 | rd->stream = buffer; |
62 | rd->stream = buffer; |
63 | rd->strpos = 0; |
63 | rd->strpos = 0; |
64 | 64 | ||
65 | rd->strremain = 0; |
65 | rd->strremain = 0; |
66 | rd->filepos = 0; |
66 | rd->filepos = 0; |
67 | return 1; |
67 | return 1; |
68 | }; |
68 | }; |
69 | 69 | ||
70 | int __stdcall init_reader(struct reader *rd, char *file) |
70 | int __stdcall init_reader(struct reader *rd, char *file) |
71 | { FILEINFO fileinfo; |
71 | { FILEINFO fileinfo; |
72 | int retval; |
72 | int retval; |
73 | int bytes; |
73 | int bytes; |
74 | 74 | ||
75 | rd->hFile = file; |
75 | rd->hFile = file; |
76 | get_fileinfo(file, &fileinfo); |
76 | get_fileinfo(file, &fileinfo); |
77 | 77 | ||
78 | rd->filelen = fileinfo.size; |
78 | rd->filelen = fileinfo.size; |
79 | rd->strpos = 0; |
79 | rd->strpos = 0; |
80 | retval=read_file (file,rd->buffer,0,0x10000,&bytes); |
80 | retval=read_file (file,rd->buffer,0,0x10000,&bytes); |
81 | 81 | ||
82 | if( (retval==0)||(retval==6)) |
82 | if( (retval==0)||(retval==6)) |
83 | { |
83 | { |
84 | rd->strremain=bytes; |
84 | rd->strremain=bytes; |
85 | rd->filepos=bytes; |
85 | rd->filepos=bytes; |
86 | rd->strpos = 0; |
86 | rd->strpos = 0; |
87 | return 1; |
87 | return 1; |
88 | }; |
88 | }; |
89 | return 0; |
89 | return 0; |
90 | }; |
90 | }; |
91 | 91 | ||
92 | static int fill_reader(struct reader *rd) |
92 | static int fill_reader(struct reader *rd) |
93 | { int retval; |
93 | { int retval; |
94 | int bytes; |
94 | int bytes; |
95 | 95 | ||
96 | if(rd->strremain > 0) |
96 | if(rd->strremain > 0) |
97 | mem_cpy(rd->buffer,rd->stream,rd->strremain); |
97 | mem_cpy(rd->buffer,rd->stream,rd->strremain); |
98 | 98 | ||
99 | rd->stream = rd->buffer; |
99 | rd->stream = rd->buffer; |
100 | bytes= 0; |
100 | bytes= 0; |
101 | retval=read_file (rd->hFile,rd->buffer+rd->strremain,rd->filepos, |
101 | retval=read_file (rd->hFile,rd->buffer+rd->strremain,rd->filepos, |
102 | 0x10000-rd->strremain,&bytes); |
102 | 0x10000-rd->strremain,&bytes); |
103 | if( (retval==0)||(retval==6)) |
103 | if( (retval==0)||(retval==6)) |
104 | { |
104 | { |
105 | rd->strremain+=bytes; |
105 | rd->strremain+=bytes; |
106 | rd->filepos+=bytes; |
106 | rd->filepos+=bytes; |
107 | rd->strpos = 0; |
107 | rd->strpos = 0; |
108 | return bytes; |
108 | return bytes; |
109 | }; |
109 | }; |
110 | return bytes; |
110 | return bytes; |
111 | }; |
111 | }; |
112 | 112 | ||
113 | int __stdcall set_reader(struct reader *rd, unsigned int filepos) |
113 | int __stdcall set_reader(struct reader *rd, unsigned int filepos) |
114 | { int retval; |
114 | { int retval; |
115 | unsigned int bytes; |
115 | unsigned int bytes; |
116 | retval=read_file (rd->hFile,rd->buffer,filepos,0x10000,&bytes); |
116 | retval=read_file (rd->hFile,rd->buffer,filepos,0x10000,&bytes); |
117 | if( (retval==0)||(retval==6)) |
117 | if( (retval==0)||(retval==6)) |
118 | { |
118 | { |
119 | rd->stream = rd->buffer; |
119 | rd->stream = rd->buffer; |
120 | rd->strremain=bytes; |
120 | rd->strremain=bytes; |
121 | rd->filepos=filepos+bytes; |
121 | rd->filepos=filepos+bytes; |
122 | rd->strpos = 0; |
122 | rd->strpos = 0; |
123 | 123 | ||
124 | fsizeold=0; |
124 | fsizeold=0; |
125 | firsthead=0; |
125 | firsthead=0; |
126 | bsbufold = 0; |
126 | bsbufold = 0; |
127 | bsbuf = bsspace[1]; |
127 | bsbuf = bsspace[1]; |
128 | bsnum = 0; |
128 | bsnum = 0; |
129 | ssize=0; |
129 | ssize=0; |
130 | oldhead=0; |
130 | oldhead=0; |
131 | memset(bsspace,0,sizeof(bsspace)); |
131 | memset(bsspace,0,sizeof(bsspace)); |
132 | return 1; |
132 | return 1; |
133 | }; |
133 | }; |
134 | return 0; |
134 | return 0; |
135 | }; |
135 | }; |
136 | 136 | ||
137 | static int stream_head_read(struct reader *rd,unsigned long *newhead) |
137 | static int stream_head_read(struct reader *rd,unsigned long *newhead) |
138 | { |
138 | { |
139 | if(rd->strremain < 4) |
139 | if(rd->strremain < 4) |
140 | if( !fill_reader(rd)) |
140 | if( !fill_reader(rd)) |
141 | return 0; |
141 | return 0; |
142 | *newhead = (rd->stream[0]<<24)|(rd->stream[1] << 16)| |
142 | *newhead = (rd->stream[0]<<24)|(rd->stream[1] << 16)| |
143 | (rd->stream[2] << 8)| rd->stream[3]; |
143 | (rd->stream[2] << 8)| rd->stream[3]; |
144 | rd->strpos+=4; |
144 | rd->strpos+=4; |
145 | rd->stream+=4; |
145 | rd->stream+=4; |
146 | rd->strremain-=4; |
146 | rd->strremain-=4; |
147 | return TRUE; |
147 | return TRUE; |
148 | }; |
148 | }; |
149 | 149 | ||
150 | int stream_read_raw(struct reader *rd,unsigned char *buf, int size) |
150 | int stream_read_raw(struct reader *rd,unsigned char *buf, int size) |
151 | { |
151 | { |
152 | 152 | ||
153 | if(rd->strremain < size) fill_reader(rd); |
153 | if(rd->strremain < size) fill_reader(rd); |
154 | 154 | ||
155 | if(size > rd->strremain) size=rd->strremain; |
155 | if(size > rd->strremain) size=rd->strremain; |
156 | 156 | ||
157 | if(size>0) |
157 | if(size>0) |
158 | { |
158 | { |
159 | mem_cpy(buf,rd->stream,size); |
159 | mem_cpy(buf,rd->stream,size); |
160 | rd->strpos+=size; |
160 | rd->strpos+=size; |
161 | rd->stream+=size; |
161 | rd->stream+=size; |
162 | rd->strremain-=size; |
162 | rd->strremain-=size; |
163 | return size; |
163 | return size; |
164 | }; |
164 | }; |
165 | return 0; |
165 | return 0; |
166 | }; |
166 | }; |
167 | 167 | ||
168 | void set_pointer(long backstep) |
168 | void set_pointer(long backstep) |
169 | { |
169 | { |
170 | bsi.wordpointer = bsbuf + ssize - backstep; |
170 | bsi.wordpointer = bsbuf + ssize - backstep; |
171 | if (backstep) |
171 | if (backstep) |
172 | mem_cpy(bsi.wordpointer,bsbufold+fsizeold-backstep,backstep); |
172 | mem_cpy(bsi.wordpointer,bsbufold+fsizeold-backstep,backstep); |
173 | bsi.bitindex = 0; |
173 | bsi.bitindex = 0; |
174 | } |
174 | } |
175 | 175 | ||
176 | int head_check(unsigned long head) |
176 | int head_check(unsigned long head) |
177 | { if |
177 | { if |
178 | ( |
178 | ( |
179 | /* first 11 bits are set to 1 for frame sync */ |
179 | /* first 11 bits are set to 1 for frame sync */ |
180 | ((head & 0xffe00000) != 0xffe00000) |
180 | ((head & 0xffe00000) != 0xffe00000) |
181 | || |
181 | || |
182 | /* layer: 01,10,11 is 1,2,3; 00 is reserved */ |
182 | /* layer: 01,10,11 is 1,2,3; 00 is reserved */ |
183 | (!((head>>17)&3)) |
183 | (!((head>>17)&3)) |
184 | || |
184 | || |
185 | /* 1111 means bad bitrate */ |
185 | /* 1111 means bad bitrate */ |
186 | (((head>>12)&0xf) == 0xf) |
186 | (((head>>12)&0xf) == 0xf) |
187 | || |
187 | || |
188 | /* 0000 means free format... */ |
188 | /* 0000 means free format... */ |
189 | (((head>>12)&0xf) == 0x0) |
189 | (((head>>12)&0xf) == 0x0) |
190 | || |
190 | || |
191 | /* sampling freq: 11 is reserved */ |
191 | /* sampling freq: 11 is reserved */ |
192 | (((head>>10)&0x3) == 0x3 ) |
192 | (((head>>10)&0x3) == 0x3 ) |
193 | /* here used to be a mpeg 2.5 check... re-enabled 2.5 decoding due to lack of evidence that it is really not good */ |
193 | /* here used to be a mpeg 2.5 check... re-enabled 2.5 decoding due to lack of evidence that it is really not good */ |
194 | ) |
194 | ) |
195 | { |
195 | { |
196 | return FALSE; |
196 | return FALSE; |
197 | } |
197 | } |
198 | /* if no check failed, the header is valid (hopefully)*/ |
198 | /* if no check failed, the header is valid (hopefully)*/ |
199 | else |
199 | else |
200 | { |
200 | { |
201 | return TRUE; |
201 | return TRUE; |
202 | } |
202 | } |
203 | } |
203 | } |
204 | 204 | ||
205 | int __stdcall decode_header(struct frame *fr,unsigned long newhead) |
205 | int __stdcall decode_header(struct frame *fr,unsigned long newhead) |
206 | { |
206 | { |
207 | if(!head_check(newhead)) |
207 | if(!head_check(newhead)) |
208 | return 0; |
208 | return 0; |
209 | if( newhead & (1<<20) ) |
209 | if( newhead & (1<<20) ) |
210 | { fr->lsf = (newhead & (1<<19)) ? 0x0 : 0x1; |
210 | { fr->lsf = (newhead & (1<<19)) ? 0x0 : 0x1; |
211 | fr->mpeg25 = 0; |
211 | fr->mpeg25 = 0; |
212 | } |
212 | } |
213 | else |
213 | else |
214 | { fr->lsf = 1; |
214 | { fr->lsf = 1; |
215 | fr->mpeg25 = 1; |
215 | fr->mpeg25 = 1; |
216 | }; |
216 | }; |
217 | 217 | ||
218 | fr->lay = 4-((newhead>>17)&3); |
218 | fr->lay = 4-((newhead>>17)&3); |
219 | if(fr->mpeg25) |
219 | if(fr->mpeg25) |
220 | fr->sampling_frequency = 6 + ((newhead>>10)&0x3); |
220 | fr->sampling_frequency = 6 + ((newhead>>10)&0x3); |
221 | else |
221 | else |
222 | fr->sampling_frequency = ((newhead>>10)&0x3) + (fr->lsf*3); |
222 | fr->sampling_frequency = ((newhead>>10)&0x3) + (fr->lsf*3); |
223 | fr->error_protection = ((newhead>>16)&0x1)^0x1; |
223 | fr->error_protection = ((newhead>>16)&0x1)^0x1; |
224 | 224 | ||
225 | fr->bitrate_index = ((newhead>>12)&0xf); |
225 | fr->bitrate_index = ((newhead>>12)&0xf); |
226 | fr->padding = ((newhead>>9)&0x1); |
226 | fr->padding = ((newhead>>9)&0x1); |
227 | fr->extension = ((newhead>>8)&0x1); |
227 | fr->extension = ((newhead>>8)&0x1); |
228 | fr->mode = ((newhead>>6)&0x3); |
228 | fr->mode = ((newhead>>6)&0x3); |
229 | fr->mode_ext = ((newhead>>4)&0x3); |
229 | fr->mode_ext = ((newhead>>4)&0x3); |
230 | fr->copyright = ((newhead>>3)&0x1); |
230 | fr->copyright = ((newhead>>3)&0x1); |
231 | fr->original = ((newhead>>2)&0x1); |
231 | fr->original = ((newhead>>2)&0x1); |
232 | fr->emphasis = newhead & 0x3; |
232 | fr->emphasis = newhead & 0x3; |
233 | 233 | ||
234 | fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2; |
234 | fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2; |
235 | 235 | ||
236 | oldhead = newhead; |
236 | oldhead = newhead; |
237 | 237 | ||
238 | if(!fr->bitrate_index) |
238 | if(!fr->bitrate_index) |
239 | return (0); |
239 | return (0); |
240 | 240 | ||
241 | switch(fr->lay) |
241 | switch(fr->lay) |
242 | { case 1: |
242 | { case 1: |
243 | fr->do_layer = do_layer1; |
243 | fr->do_layer = do_layer1; |
244 | #ifdef VARMODESUPPORT |
244 | #ifdef VARMODESUPPORT |
245 | if (varmode) { |
245 | if (varmode) { |
246 | error("Sorry, layer-1 not supported in varmode."); |
246 | error("Sorry, layer-1 not supported in varmode."); |
247 | return (0); |
247 | return (0); |
248 | } |
248 | } |
249 | #endif |
249 | #endif |
250 | fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000; |
250 | fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000; |
251 | fr->framesize /= freqs[fr->sampling_frequency]; |
251 | fr->framesize /= freqs[fr->sampling_frequency]; |
252 | fr->framesize = ((fr->framesize+fr->padding)<<2)-4; |
252 | fr->framesize = ((fr->framesize+fr->padding)<<2)-4; |
253 | break; |
253 | break; |
254 | case 2: |
254 | case 2: |
255 | fr->do_layer = do_layer2; |
255 | fr->do_layer = do_layer2; |
256 | #ifdef VARMODESUPPORT |
256 | #ifdef VARMODESUPPORT |
257 | if (varmode) { |
257 | if (varmode) { |
258 | error("Sorry, layer-2 not supported in varmode."); |
258 | error("Sorry, layer-2 not supported in varmode."); |
259 | return (0); |
259 | return (0); |
260 | } |
260 | } |
261 | #endif |
261 | #endif |
262 | fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000; |
262 | fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000; |
263 | fr->framesize /= freqs[fr->sampling_frequency]; |
263 | fr->framesize /= freqs[fr->sampling_frequency]; |
264 | fr->framesize += fr->padding - 4; |
264 | fr->framesize += fr->padding - 4; |
265 | break; |
265 | break; |
266 | case 3: |
266 | case 3: |
267 | fr->do_layer = do_layer3; |
267 | fr->do_layer = do_layer3; |
268 | if(fr->lsf) |
268 | if(fr->lsf) |
269 | ssize = (fr->stereo == 1) ? 9 : 17; |
269 | ssize = (fr->stereo == 1) ? 9 : 17; |
270 | else |
270 | else |
271 | ssize = (fr->stereo == 1) ? 17 : 32; |
271 | ssize = (fr->stereo == 1) ? 17 : 32; |
272 | if(fr->error_protection) |
272 | if(fr->error_protection) |
273 | ssize += 2; |
273 | ssize += 2; |
274 | fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000; |
274 | fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000; |
275 | fr->framesize /= freqs[fr->sampling_frequency]<<(fr->lsf); |
275 | fr->framesize /= freqs[fr->sampling_frequency]<<(fr->lsf); |
276 | fr->framesize = fr->framesize + fr->padding - 4; |
276 | fr->framesize = fr->framesize + fr->padding - 4; |
277 | break; |
277 | break; |
278 | default: |
278 | default: |
279 | return (0); |
279 | return (0); |
280 | } |
280 | } |
281 | if (fr->framesize > MAXFRAMESIZE) |
281 | if (fr->framesize > MAXFRAMESIZE) |
282 | return (0); |
282 | return (0); |
283 | return 1; |
283 | return 1; |
284 | } |
284 | } |
285 | 285 | ||
286 | 286 | ||
287 | int read_frame(struct reader *rd, struct frame *fr) |
287 | int read_frame(struct reader *rd, struct frame *fr) |
288 | { unsigned long newhead; |
288 | { unsigned long newhead; |
289 | static unsigned char ssave[34]; |
289 | static unsigned char ssave[34]; |
290 | //off_t framepos; |
290 | //off_t framepos; |
291 | fsizeold=fr->framesize; /* for Layer3 */ |
291 | fsizeold=fr->framesize; /* for Layer3 */ |
292 | 292 | ||
293 | read_again: |
293 | read_again: |
294 | 294 | ||
295 | if(!rd->head_read(rd,&newhead)) |
295 | if(!rd->head_read(rd,&newhead)) |
296 | return FALSE; |
296 | return FALSE; |
297 | 297 | ||
298 | if(!decode_header(fr,newhead)) |
298 | if(!decode_header(fr,newhead)) |
299 | { |
299 | { |
300 | if((newhead & 0xffffff00) == 0x49443300) |
300 | if((newhead & 0xffffff00) == 0x49443300) |
301 | { |
301 | { |
302 | int id3length = 0; |
302 | int id3length = 0; |
303 | id3length = parse_new_id3(rd, newhead); |
303 | id3length = parse_new_id3(rd, newhead); |
304 | goto read_again; |
304 | goto read_again; |
305 | }; |
305 | }; |
306 | rd->strpos-=3; |
306 | rd->strpos-=3; |
307 | rd->stream-=3; |
307 | rd->stream-=3; |
308 | rd->strremain+=3; |
308 | rd->strremain+=3; |
309 | goto read_again; |
309 | goto read_again; |
310 | }; |
310 | }; |
311 | 311 | ||
312 | #if 0 |
312 | #if 0 |
313 | if(1 || oldhead != newhead || !oldhead) |
313 | if(1 || oldhead != newhead || !oldhead) |
314 | { |
314 | { |
315 | 315 | ||
316 | init_resync: |
316 | init_resync: |
317 | 317 | ||
318 | #ifdef SKIP_JUNK |
318 | #ifdef SKIP_JUNK |
319 | /* watch out for junk/tags on beginning of stream by invalid header */ |
319 | /* watch out for junk/tags on beginning of stream by invalid header */ |
320 | if(!firsthead && !head_check(newhead) && !free_format_header(newhead)) { |
320 | if(!firsthead && !head_check(newhead) && !free_format_header(newhead)) { |
321 | int i; |
321 | int i; |
322 | 322 | ||
323 | /* check for id3v2; first three bytes (of 4) are "ID3" */ |
323 | /* check for id3v2; first three bytes (of 4) are "ID3" */ |
324 | if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) |
324 | if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) |
325 | { |
325 | { |
326 | int id3length = 0; |
326 | int id3length = 0; |
327 | id3length = parse_new_id3(newhead, rd); |
327 | id3length = parse_new_id3(newhead, rd); |
328 | goto read_again; |
328 | goto read_again; |
329 | } |
329 | } |
330 | else if(param.verbose > 1) fprintf(stderr,"Note: Junk at the beginning (0x%08lx)\n",newhead); |
330 | else if(param.verbose > 1) fprintf(stderr,"Note: Junk at the beginning (0x%08lx)\n",newhead); |
331 | 331 | ||
332 | /* I even saw RIFF headers at the beginning of MPEG streams ;( */ |
332 | /* I even saw RIFF headers at the beginning of MPEG streams ;( */ |
333 | if(newhead == ('R'<<24)+('I'<<16)+('F'<<8)+'F') { |
333 | if(newhead == ('R'<<24)+('I'<<16)+('F'<<8)+'F') { |
334 | if(param.verbose > 1) fprintf(stderr, "Note: Looks like a RIFF header.\n"); |
334 | if(param.verbose > 1) fprintf(stderr, "Note: Looks like a RIFF header.\n"); |
335 | if(!rd->head_read(rd,&newhead)) |
335 | if(!rd->head_read(rd,&newhead)) |
336 | return 0; |
336 | return 0; |
337 | while(newhead != ('d'<<24)+('a'<<16)+('t'<<8)+'a') { |
337 | while(newhead != ('d'<<24)+('a'<<16)+('t'<<8)+'a') { |
338 | if(!rd->head_shift(rd,&newhead)) |
338 | if(!rd->head_shift(rd,&newhead)) |
339 | return 0; |
339 | return 0; |
340 | } |
340 | } |
341 | if(!rd->head_read(rd,&newhead)) |
341 | if(!rd->head_read(rd,&newhead)) |
342 | return 0; |
342 | return 0; |
343 | if(param.verbose > 1) fprintf(stderr,"Note: Skipped RIFF header!\n"); |
343 | if(param.verbose > 1) fprintf(stderr,"Note: Skipped RIFF header!\n"); |
344 | goto read_again; |
344 | goto read_again; |
345 | } |
345 | } |
346 | /* unhandled junk... just continue search for a header */ |
346 | /* unhandled junk... just continue search for a header */ |
347 | /* step in byte steps through next 64K */ |
347 | /* step in byte steps through next 64K */ |
348 | for(i=0;i<65536;i++) { |
348 | for(i=0;i<65536;i++) { |
349 | if(!rd->head_shift(rd,&newhead)) |
349 | if(!rd->head_shift(rd,&newhead)) |
350 | return 0; |
350 | return 0; |
351 | /* if(head_check(newhead)) */ |
351 | /* if(head_check(newhead)) */ |
352 | if(head_check(newhead) && decode_header(fr, newhead)) |
352 | if(head_check(newhead) && decode_header(fr, newhead)) |
353 | break; |
353 | break; |
354 | } |
354 | } |
355 | if(i == 65536) { |
355 | if(i == 65536) { |
356 | if(!param.quiet) error("Giving up searching valid MPEG header after 64K of junk."); |
356 | if(!param.quiet) error("Giving up searching valid MPEG header after 64K of junk."); |
357 | return 0; |
357 | return 0; |
358 | } |
358 | } |
359 | /* |
359 | /* |
360 | * should we additionaly check, whether a new frame starts at |
360 | * should we additionaly check, whether a new frame starts at |
361 | * the next expected position? (some kind of read ahead) |
361 | * the next expected position? (some kind of read ahead) |
362 | * We could implement this easily, at least for files. |
362 | * We could implement this easily, at least for files. |
363 | */ |
363 | */ |
364 | } |
364 | } |
365 | #endif |
365 | #endif |
366 | 366 | ||
367 | /* first attempt of read ahead check to find the real first header; cannot believe what junk is out there! */ |
367 | /* first attempt of read ahead check to find the real first header; cannot believe what junk is out there! */ |
368 | /* for now, a spurious first free format header screws up here; need free format support for detecting false free format headers... */ |
368 | /* for now, a spurious first free format header screws up here; need free format support for detecting false free format headers... */ |
369 | if(!firsthead && rd->flags & READER_SEEKABLE && head_check(newhead) && decode_header(fr, newhead)) |
369 | if(!firsthead && rd->flags & READER_SEEKABLE && head_check(newhead) && decode_header(fr, newhead)) |
370 | { |
370 | { |
371 | unsigned long nexthead = 0; |
371 | unsigned long nexthead = 0; |
372 | int hd = 0; |
372 | int hd = 0; |
373 | off_t start = rd->tell(rd); |
373 | off_t start = rd->tell(rd); |
374 | debug1("doing ahead check with BPF %d", fr->framesize+4); |
374 | debug1("doing ahead check with BPF %d", fr->framesize+4); |
375 | /* step framesize bytes forward and read next possible header*/ |
375 | /* step framesize bytes forward and read next possible header*/ |
376 | if(rd->back_bytes(rd, -fr->framesize)) |
376 | if(rd->back_bytes(rd, -fr->framesize)) |
377 | { |
377 | { |
378 | error("cannot seek!"); |
378 | error("cannot seek!"); |
379 | return 0; |
379 | return 0; |
380 | } |
380 | } |
381 | hd = rd->head_read(rd,&nexthead); |
381 | hd = rd->head_read(rd,&nexthead); |
382 | if(rd->back_bytes(rd, rd->tell(rd)-start)) |
382 | if(rd->back_bytes(rd, rd->tell(rd)-start)) |
383 | { |
383 | { |
384 | error("cannot seek!"); |
384 | error("cannot seek!"); |
385 | return 0; |
385 | return 0; |
386 | } |
386 | } |
387 | if(!hd) |
387 | if(!hd) |
388 | { |
388 | { |
389 | warning("cannot read next header, a one-frame stream? Duh..."); |
389 | warning("cannot read next header, a one-frame stream? Duh..."); |
390 | } |
390 | } |
391 | else |
391 | else |
392 | { |
392 | { |
393 | debug2("does next header 0x%08lx match first 0x%08lx?", nexthead, newhead); |
393 | debug2("does next header 0x%08lx match first 0x%08lx?", nexthead, newhead); |
394 | /* not allowing free format yet */ |
394 | /* not allowing free format yet */ |
395 | if(!head_check(nexthead) || (nexthead & HDRCMPMASK) != (newhead & HDRCMPMASK)) |
395 | if(!head_check(nexthead) || (nexthead & HDRCMPMASK) != (newhead & HDRCMPMASK)) |
396 | { |
396 | { |
397 | debug("No, the header was not valid, start from beginning..."); |
397 | debug("No, the header was not valid, start from beginning..."); |
398 | /* try next byte for valid header */ |
398 | /* try next byte for valid header */ |
399 | if(rd->back_bytes(rd, 3)) |
399 | if(rd->back_bytes(rd, 3)) |
400 | { |
400 | { |
401 | error("cannot seek!"); |
401 | error("cannot seek!"); |
402 | return 0; |
402 | return 0; |
403 | } |
403 | } |
404 | goto read_again; |
404 | goto read_again; |
405 | } |
405 | } |
406 | } |
406 | } |
407 | } |
407 | } |
408 | 408 | ||
409 | /* why has this head check been avoided here before? */ |
409 | /* why has this head check been avoided here before? */ |
410 | if(!head_check(newhead)) |
410 | if(!head_check(newhead)) |
411 | { |
411 | { |
412 | if(!firsthead && free_format_header(newhead)) |
412 | if(!firsthead && free_format_header(newhead)) |
413 | { |
413 | { |
414 | error1("Header 0x%08lx seems to indicate a free format stream; I do not handle that yet", newhead); |
414 | error1("Header 0x%08lx seems to indicate a free format stream; I do not handle that yet", newhead); |
415 | goto read_again; |
415 | goto read_again; |
416 | return 0; |
416 | return 0; |
417 | } |
417 | } |
418 | /* and those ugly ID3 tags */ |
418 | /* and those ugly ID3 tags */ |
419 | if((newhead & 0xffffff00) == ('T'<<24)+('A'<<16)+('G'<<8)) { |
419 | if((newhead & 0xffffff00) == ('T'<<24)+('A'<<16)+('G'<<8)) { |
420 | rd->skip_bytes(rd,124); |
420 | rd->skip_bytes(rd,124); |
421 | if (param.verbose > 1) fprintf(stderr,"Note: Skipped ID3 Tag!\n"); |
421 | if (param.verbose > 1) fprintf(stderr,"Note: Skipped ID3 Tag!\n"); |
422 | goto read_again; |
422 | goto read_again; |
423 | } |
423 | } |
424 | /* duplicated code from above! */ |
424 | /* duplicated code from above! */ |
425 | /* check for id3v2; first three bytes (of 4) are "ID3" */ |
425 | /* check for id3v2; first three bytes (of 4) are "ID3" */ |
426 | if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) |
426 | if((newhead & (unsigned long) 0xffffff00) == (unsigned long) 0x49443300) |
427 | { |
427 | { |
428 | int id3length = 0; |
428 | int id3length = 0; |
429 | id3length = parse_new_id3(newhead, rd); |
429 | id3length = parse_new_id3(newhead, rd); |
430 | goto read_again; |
430 | goto read_again; |
431 | } |
431 | } |
432 | else if (give_note) |
432 | else if (give_note) |
433 | { |
433 | { |
434 | fprintf(stderr,"Note: Illegal Audio-MPEG-Header 0x%08lx at offset 0x%lx.\n", newhead,rd->tell(rd)-4); |
434 | fprintf(stderr,"Note: Illegal Audio-MPEG-Header 0x%08lx at offset 0x%lx.\n", newhead,rd->tell(rd)-4); |
435 | } |
435 | } |
436 | 436 | ||
437 | if(give_note && (newhead & 0xffffff00) == ('b'<<24)+('m'<<16)+('p'<<8)) fprintf(stderr,"Note: Could be a BMP album art.\n"); |
437 | if(give_note && (newhead & 0xffffff00) == ('b'<<24)+('m'<<16)+('p'<<8)) fprintf(stderr,"Note: Could be a BMP album art.\n"); |
438 | if (param.tryresync || do_recover) { |
438 | if (param.tryresync || do_recover) { |
439 | int try = 0; |
439 | int try = 0; |
440 | /* TODO: make this more robust, I'd like to cat two mp3 fragments together (in a dirty way) and still have mpg123 beign able to decode all it somehow. */ |
440 | /* TODO: make this more robust, I'd like to cat two mp3 fragments together (in a dirty way) and still have mpg123 beign able to decode all it somehow. */ |
441 | if(give_note) fprintf(stderr, "Note: Trying to resync...\n"); |
441 | if(give_note) fprintf(stderr, "Note: Trying to resync...\n"); |
442 | /* Read more bytes until we find something that looks |
442 | /* Read more bytes until we find something that looks |
443 | reasonably like a valid header. This is not a |
443 | reasonably like a valid header. This is not a |
444 | perfect strategy, but it should get us back on the |
444 | perfect strategy, but it should get us back on the |
445 | track within a short time (and hopefully without |
445 | track within a short time (and hopefully without |
446 | too much distortion in the audio output). */ |
446 | too much distortion in the audio output). */ |
447 | do { |
447 | do { |
448 | if(!rd->head_shift(rd,&newhead)) |
448 | if(!rd->head_shift(rd,&newhead)) |
449 | return 0; |
449 | return 0; |
450 | /* debug2("resync try %i, got newhead 0x%08lx", try, newhead); */ |
450 | /* debug2("resync try %i, got newhead 0x%08lx", try, newhead); */ |
451 | if (!oldhead) |
451 | if (!oldhead) |
452 | { |
452 | { |
453 | debug("going to init_resync..."); |
453 | debug("going to init_resync..."); |
454 | goto init_resync; /* "considered harmful", eh? */ |
454 | goto init_resync; /* "considered harmful", eh? */ |
455 | } |
455 | } |
456 | /* we should perhaps collect a list of valid headers that occured in file... there can be more */ |
456 | /* we should perhaps collect a list of valid headers that occured in file... there can be more */ |
457 | /* Michael's new resync routine seems to work better with the one frame readahead (and some input buffering?) */ |
457 | /* Michael's new resync routine seems to work better with the one frame readahead (and some input buffering?) */ |
458 | } while |
458 | } while |
459 | ( |
459 | ( |
460 | ++try < RESYNC_LIMIT |
460 | ++try < RESYNC_LIMIT |
461 | && (newhead & HDRCMPMASK) != (oldhead & HDRCMPMASK) |
461 | && (newhead & HDRCMPMASK) != (oldhead & HDRCMPMASK) |
462 | && (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) |
462 | && (newhead & HDRCMPMASK) != (firsthead & HDRCMPMASK) |
463 | ); |
463 | ); |
464 | /* too many false positives |
464 | /* too many false positives |
465 | }while (!(head_check(newhead) && decode_header(fr, newhead))); */ |
465 | }while (!(head_check(newhead) && decode_header(fr, newhead))); */ |
466 | if(try == RESYNC_LIMIT) |
466 | if(try == RESYNC_LIMIT) |
467 | { |
467 | { |
468 | error("giving up resync - your stream is not nice... perhaps an improved routine could catch up"); |
468 | error("giving up resync - your stream is not nice... perhaps an improved routine could catch up"); |
469 | return 0; |
469 | return 0; |
470 | } |
470 | } |
471 | 471 | ||
472 | if (give_note) |
472 | if (give_note) |
473 | fprintf (stderr, "Note: Skipped %d bytes in input.\n", try); |
473 | fprintf (stderr, "Note: Skipped %d bytes in input.\n", try); |
474 | } |
474 | } |
475 | else |
475 | else |
476 | { |
476 | { |
477 | error("not attempting to resync..."); |
477 | error("not attempting to resync..."); |
478 | return (0); |
478 | return (0); |
479 | } |
479 | } |
480 | } |
480 | } |
481 | 481 | ||
482 | if (!firsthead) { |
482 | if (!firsthead) { |
483 | if(!decode_header(fr,newhead)) |
483 | if(!decode_header(fr,newhead)) |
484 | { |
484 | { |
485 | error("decode header failed before first valid one, going to read again"); |
485 | error("decode header failed before first valid one, going to read again"); |
486 | goto read_again; |
486 | goto read_again; |
487 | } |
487 | } |
488 | } |
488 | } |
489 | else |
489 | else |
490 | if(!decode_header(fr,newhead)) |
490 | if(!decode_header(fr,newhead)) |
491 | { |
491 | { |
492 | error("decode header failed - goto resync"); |
492 | error("decode header failed - goto resync"); |
493 | /* return 0; */ |
493 | /* return 0; */ |
494 | goto init_resync; |
494 | goto init_resync; |
495 | } |
495 | } |
496 | } |
496 | } |
497 | else |
497 | else |
498 | fr->header_change = 0; |
498 | fr->header_change = 0; |
499 | #endif |
499 | #endif |
500 | 500 | ||
501 | bsbufold = bsbuf; |
501 | bsbufold = bsbuf; |
502 | bsbuf = bsspace[bsnum]+512; |
502 | bsbuf = bsspace[bsnum]+512; |
503 | bsnum = (bsnum + 1) & 1; |
503 | bsnum = (bsnum + 1) & 1; |
504 | /* if filepos is invalid, so is framepos */ |
504 | /* if filepos is invalid, so is framepos */ |
505 | //framepos = rd->filepos - 4; |
505 | //framepos = rd->filepos - 4; |
506 | /* read main data into memory */ |
506 | /* read main data into memory */ |
507 | /* 0 is error! */ |
507 | /* 0 is error! */ |
508 | 508 | ||
509 | if(rd->read_frame_body(rd,bsbuf,fr->framesize) < fr->framesize) |
509 | if(rd->read_frame_body(rd,bsbuf,fr->framesize) < fr->framesize) |
510 | return 0; |
510 | return 0; |
511 | 511 | ||
512 | #if 0 |
512 | #if 0 |
513 | if(!firsthead) |
513 | if(!firsthead) |
514 | { |
514 | { |
515 | /* following stuff is actually layer3 specific (in practice, not in theory) */ |
515 | /* following stuff is actually layer3 specific (in practice, not in theory) */ |
516 | if(fr->lay == 3) |
516 | if(fr->lay == 3) |
517 | { |
517 | { |
518 | /* |
518 | /* |
519 | going to look for Xing or Info at some position after the header |
519 | going to look for Xing or Info at some position after the header |
520 | MPEG 1 MPEG 2/2.5 (LSF) |
520 | MPEG 1 MPEG 2/2.5 (LSF) |
521 | Stereo, Joint Stereo, Dual Channel 32 17 |
521 | Stereo, Joint Stereo, Dual Channel 32 17 |
522 | Mono 17 9 |
522 | Mono 17 9 |
523 | 523 | ||
524 | Also, how to avoid false positives? I guess I should interpret more of the header to rule that out(?). |
524 | Also, how to avoid false positives? I guess I should interpret more of the header to rule that out(?). |
525 | I hope that ensuring all zeros until tag start is enough. |
525 | I hope that ensuring all zeros until tag start is enough. |
526 | */ |
526 | */ |
527 | size_t lame_offset = (fr->stereo == 2) ? (fr->lsf ? 17 : 32 ) : (fr->lsf ? 9 : 17); |
527 | size_t lame_offset = (fr->stereo == 2) ? (fr->lsf ? 17 : 32 ) : (fr->lsf ? 9 : 17); |
528 | if(fr->framesize >= 120+lame_offset) /* traditional Xing header is 120 bytes */ |
528 | if(fr->framesize >= 120+lame_offset) /* traditional Xing header is 120 bytes */ |
529 | { |
529 | { |
530 | size_t i; |
530 | size_t i; |
531 | int lame_type = 0; |
531 | int lame_type = 0; |
532 | /* only search for tag when all zero before it (apart from checksum) */ |
532 | /* only search for tag when all zero before it (apart from checksum) */ |
533 | for(i=2; i < lame_offset; ++i) if(bsbuf[i] != 0) break; |
533 | for(i=2; i < lame_offset; ++i) if(bsbuf[i] != 0) break; |
534 | if(i == lame_offset) |
534 | if(i == lame_offset) |
535 | { |
535 | { |
536 | if |
536 | if |
537 | ( |
537 | ( |
538 | (bsbuf[lame_offset] == 'I') |
538 | (bsbuf[lame_offset] == 'I') |
539 | && (bsbuf[lame_offset+1] == 'n') |
539 | && (bsbuf[lame_offset+1] == 'n') |
540 | && (bsbuf[lame_offset+2] == 'f') |
540 | && (bsbuf[lame_offset+2] == 'f') |
541 | && (bsbuf[lame_offset+3] == 'o') |
541 | && (bsbuf[lame_offset+3] == 'o') |
542 | ) |
542 | ) |
543 | { |
543 | { |
544 | lame_type = 1; /* We still have to see what there is */ |
544 | lame_type = 1; /* We still have to see what there is */ |
545 | } |
545 | } |
546 | else if |
546 | else if |
547 | ( |
547 | ( |
548 | (bsbuf[lame_offset] == 'X') |
548 | (bsbuf[lame_offset] == 'X') |
549 | && (bsbuf[lame_offset+1] == 'i') |
549 | && (bsbuf[lame_offset+1] == 'i') |
550 | && (bsbuf[lame_offset+2] == 'n') |
550 | && (bsbuf[lame_offset+2] == 'n') |
551 | && (bsbuf[lame_offset+3] == 'g') |
551 | && (bsbuf[lame_offset+3] == 'g') |
552 | ) |
552 | ) |
553 | { |
553 | { |
554 | lame_type = 2; |
554 | lame_type = 2; |
555 | vbr = VBR; /* Xing header means always VBR */ |
555 | vbr = VBR; /* Xing header means always VBR */ |
556 | } |
556 | } |
557 | if(lame_type) |
557 | if(lame_type) |
558 | { |
558 | { |
559 | unsigned long xing_flags; |
559 | unsigned long xing_flags; |
560 | 560 | ||
561 | /* we have one of these headers... */ |
561 | /* we have one of these headers... */ |
562 | if(param.verbose > 1) fprintf(stderr, "Note: Xing/Lame/Info header detected\n"); |
562 | if(param.verbose > 1) fprintf(stderr, "Note: Xing/Lame/Info header detected\n"); |
563 | /* now interpret the Xing part, I have 120 bytes total for sure */ |
563 | /* now interpret the Xing part, I have 120 bytes total for sure */ |
564 | /* there are 4 bytes for flags, but only the last byte contains known ones */ |
564 | /* there are 4 bytes for flags, but only the last byte contains known ones */ |
565 | lame_offset += 4; /* now first byte after Xing/Name */ |
565 | lame_offset += 4; /* now first byte after Xing/Name */ |
566 | /* 4 bytes dword for flags */ |
566 | /* 4 bytes dword for flags */ |
567 | #define make_long(a, o) ((((unsigned long) a[o]) << 24) | (((unsigned long) a[o+1]) << 16) | (((unsigned long) a[o+2]) << 8) | ((unsigned long) a[o+3])) |
567 | #define make_long(a, o) ((((unsigned long) a[o]) << 24) | (((unsigned long) a[o+1]) << 16) | (((unsigned long) a[o+2]) << 8) | ((unsigned long) a[o+3])) |
568 | /* 16 bit */ |
568 | /* 16 bit */ |
569 | #define make_short(a,o) ((((unsigned short) a[o]) << 8) | ((unsigned short) a[o+1])) |
569 | #define make_short(a,o) ((((unsigned short) a[o]) << 8) | ((unsigned short) a[o+1])) |
570 | xing_flags = make_long(bsbuf, lame_offset); |
570 | xing_flags = make_long(bsbuf, lame_offset); |
571 | lame_offset += 4; |
571 | lame_offset += 4; |
572 | debug1("Xing: flags 0x%08lx", xing_flags); |
572 | debug1("Xing: flags 0x%08lx", xing_flags); |
573 | if(xing_flags & 1) /* frames */ |
573 | if(xing_flags & 1) /* frames */ |
574 | { |
574 | { |
575 | /* |
575 | /* |
576 | In theory, one should use that value for skipping... |
576 | In theory, one should use that value for skipping... |
577 | When I know the exact number of samples I could simply count in audio_flush, |
577 | When I know the exact number of samples I could simply count in audio_flush, |
578 | but that's problematic with seeking and such. |
578 | but that's problematic with seeking and such. |
579 | I still miss the real solution for detecting the end. |
579 | I still miss the real solution for detecting the end. |
580 | */ |
580 | */ |
581 | track_frames = make_long(bsbuf, lame_offset); |
581 | track_frames = make_long(bsbuf, lame_offset); |
582 | if(track_frames > TRACK_MAX_FRAMES) track_frames = 0; /* endless stream? */ |
582 | if(track_frames > TRACK_MAX_FRAMES) track_frames = 0; /* endless stream? */ |
583 | #ifdef GAPLESS |
583 | #ifdef GAPLESS |
584 | /* if no further info there, remove/add at least the decoder delay */ |
584 | /* if no further info there, remove/add at least the decoder delay */ |
585 | if(param.gapless) |
585 | if(param.gapless) |
586 | { |
586 | { |
587 | unsigned long length = track_frames * spf(fr); |
587 | unsigned long length = track_frames * spf(fr); |
588 | if(length > 1) |
588 | if(length > 1) |
589 | layer3_gapless_init(DECODER_DELAY+GAP_SHIFT, length+DECODER_DELAY+GAP_SHIFT); |
589 | layer3_gapless_init(DECODER_DELAY+GAP_SHIFT, length+DECODER_DELAY+GAP_SHIFT); |
590 | } |
590 | } |
591 | #endif |
591 | #endif |
592 | debug1("Xing: %lu frames", track_frames); |
592 | debug1("Xing: %lu frames", track_frames); |
593 | lame_offset += 4; |
593 | lame_offset += 4; |
594 | } |
594 | } |
595 | if(xing_flags & 0x2) /* bytes */ |
595 | if(xing_flags & 0x2) /* bytes */ |
596 | { |
596 | { |
597 | #ifdef DEBUG |
597 | #ifdef DEBUG |
598 | unsigned long xing_bytes = make_long(bsbuf, lame_offset); |
598 | unsigned long xing_bytes = make_long(bsbuf, lame_offset); |
599 | debug1("Xing: %lu bytes", xing_bytes); |
599 | debug1("Xing: %lu bytes", xing_bytes); |
600 | #endif |
600 | #endif |
601 | lame_offset += 4; |
601 | lame_offset += 4; |
602 | } |
602 | } |
603 | if(xing_flags & 0x4) /* TOC */ |
603 | if(xing_flags & 0x4) /* TOC */ |
604 | { |
604 | { |
605 | lame_offset += 100; /* just skip */ |
605 | lame_offset += 100; /* just skip */ |
606 | } |
606 | } |
607 | if(xing_flags & 0x8) /* VBR quality */ |
607 | if(xing_flags & 0x8) /* VBR quality */ |
608 | { |
608 | { |
609 | #ifdef DEBUG |
609 | #ifdef DEBUG |
610 | unsigned long xing_quality = make_long(bsbuf, lame_offset); |
610 | unsigned long xing_quality = make_long(bsbuf, lame_offset); |
611 | debug1("Xing: quality = %lu", xing_quality); |
611 | debug1("Xing: quality = %lu", xing_quality); |
612 | #endif |
612 | #endif |
613 | lame_offset += 4; |
613 | lame_offset += 4; |
614 | } |
614 | } |
615 | /* I guess that either 0 or LAME extra data follows */ |
615 | /* I guess that either 0 or LAME extra data follows */ |
616 | /* there may this crc16 be floating around... (?) */ |
616 | /* there may this crc16 be floating around... (?) */ |
617 | if(bsbuf[lame_offset] != 0) |
617 | if(bsbuf[lame_offset] != 0) |
618 | { |
618 | { |
619 | unsigned char lame_vbr; |
619 | unsigned char lame_vbr; |
620 | float replay_gain[2] = {0,0}; |
620 | float replay_gain[2] = {0,0}; |
621 | float peak = 0; |
621 | float peak = 0; |
622 | float gain_offset = 0; /* going to be +6 for old lame that used 83dB */ |
622 | float gain_offset = 0; /* going to be +6 for old lame that used 83dB */ |
623 | char nb[10]; |
623 | char nb[10]; |
624 | memcpy(nb, bsbuf+lame_offset, 9); |
624 | memcpy(nb, bsbuf+lame_offset, 9); |
625 | nb[9] = 0; |
625 | nb[9] = 0; |
626 | debug1("Info: Encoder: %s", nb); |
626 | debug1("Info: Encoder: %s", nb); |
627 | if(!strncmp("LAME", nb, 4)) |
627 | if(!strncmp("LAME", nb, 4)) |
628 | { |
628 | { |
629 | gain_offset = 6; |
629 | gain_offset = 6; |
630 | debug("TODO: finish lame detetcion..."); |
630 | debug("TODO: finish lame detetcion..."); |
631 | } |
631 | } |
632 | lame_offset += 9; |
632 | lame_offset += 9; |
633 | /* the 4 big bits are tag revision, the small bits vbr method */ |
633 | /* the 4 big bits are tag revision, the small bits vbr method */ |
634 | lame_vbr = bsbuf[lame_offset] & 15; |
634 | lame_vbr = bsbuf[lame_offset] & 15; |
635 | debug1("Info: rev %u", bsbuf[lame_offset] >> 4); |
635 | debug1("Info: rev %u", bsbuf[lame_offset] >> 4); |
636 | debug1("Info: vbr mode %u", lame_vbr); |
636 | debug1("Info: vbr mode %u", lame_vbr); |
637 | lame_offset += 1; |
637 | lame_offset += 1; |
638 | switch(lame_vbr) |
638 | switch(lame_vbr) |
639 | { |
639 | { |
640 | /* from rev1 proposal... not sure if all good in practice */ |
640 | /* from rev1 proposal... not sure if all good in practice */ |
641 | case 1: |
641 | case 1: |
642 | case 8: vbr = CBR; break; |
642 | case 8: vbr = CBR; break; |
643 | case 2: |
643 | case 2: |
644 | case 9: vbr = ABR; break; |
644 | case 9: vbr = ABR; break; |
645 | default: vbr = VBR; /* 00==unknown is taken as VBR */ |
645 | default: vbr = VBR; /* 00==unknown is taken as VBR */ |
646 | } |
646 | } |
647 | /* skipping: lowpass filter value */ |
647 | /* skipping: lowpass filter value */ |
648 | lame_offset += 1; |
648 | lame_offset += 1; |
649 | /* replaygain */ |
649 | /* replaygain */ |
650 | /* 32bit float: peak amplitude -- why did I parse it as int before??*/ |
650 | /* 32bit float: peak amplitude -- why did I parse it as int before??*/ |
651 | /* Ah, yes, lame seems to store it as int since some day in 2003; I've only seen zeros anyway until now, bah! */ |
651 | /* Ah, yes, lame seems to store it as int since some day in 2003; I've only seen zeros anyway until now, bah! */ |
652 | if |
652 | if |
653 | ( |
653 | ( |
654 | (bsbuf[lame_offset] != 0) |
654 | (bsbuf[lame_offset] != 0) |
655 | || (bsbuf[lame_offset+1] != 0) |
655 | || (bsbuf[lame_offset+1] != 0) |
656 | || (bsbuf[lame_offset+2] != 0) |
656 | || (bsbuf[lame_offset+2] != 0) |
657 | || (bsbuf[lame_offset+3] != 0) |
657 | || (bsbuf[lame_offset+3] != 0) |
658 | ) |
658 | ) |
659 | { |
659 | { |
660 | debug("Wow! Is there _really_ a non-zero peak value? Now is it stored as float or int - how should I know?"); |
660 | debug("Wow! Is there _really_ a non-zero peak value? Now is it stored as float or int - how should I know?"); |
661 | peak = *(float*) (bsbuf+lame_offset); |
661 | peak = *(float*) (bsbuf+lame_offset); |
662 | } |
662 | } |
663 | debug1("Info: peak = %f (I won't use this)", peak); |
663 | debug1("Info: peak = %f (I won't use this)", peak); |
664 | peak = 0; /* until better times arrived */ |
664 | peak = 0; /* until better times arrived */ |
665 | lame_offset += 4; |
665 | lame_offset += 4; |
666 | /* |
666 | /* |
667 | ReplayGain values - lame only writes radio mode gain... |
667 | ReplayGain values - lame only writes radio mode gain... |
668 | 16bit gain, 3 bits name, 3 bits originator, sign (1=-, 0=+), dB value*10 in 9 bits (fixed point) |
668 | 16bit gain, 3 bits name, 3 bits originator, sign (1=-, 0=+), dB value*10 in 9 bits (fixed point) |
669 | ignore the setting if name or originator == 000! |
669 | ignore the setting if name or originator == 000! |
670 | radio 0 0 1 0 1 1 1 0 0 1 1 1 1 1 0 1 |
670 | radio 0 0 1 0 1 1 1 0 0 1 1 1 1 1 0 1 |
671 | audiophile 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 |
671 | audiophile 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 |
672 | */ |
672 | */ |
673 | 673 | ||
674 | for(i =0; i < 2; ++i) |
674 | for(i =0; i < 2; ++i) |
675 | { |
675 | { |
676 | unsigned char origin = (bsbuf[lame_offset] >> 2) & 0x7; /* the 3 bits after that... */ |
676 | unsigned char origin = (bsbuf[lame_offset] >> 2) & 0x7; /* the 3 bits after that... */ |
677 | if(origin != 0) |
677 | if(origin != 0) |
678 | { |
678 | { |
679 | unsigned char gt = bsbuf[lame_offset] >> 5; /* only first 3 bits */ |
679 | unsigned char gt = bsbuf[lame_offset] >> 5; /* only first 3 bits */ |
680 | if(gt == 1) gt = 0; /* radio */ |
680 | if(gt == 1) gt = 0; /* radio */ |
681 | else if(gt == 2) gt = 1; /* audiophile */ |
681 | else if(gt == 2) gt = 1; /* audiophile */ |
682 | else continue; |
682 | else continue; |
683 | /* get the 9 bits into a number, divide by 10, multiply sign... happy bit banging */ |
683 | /* get the 9 bits into a number, divide by 10, multiply sign... happy bit banging */ |
684 | replay_gain[0] = ((bsbuf[lame_offset] & 0x2) ? -0.1 : 0.1) * (make_short(bsbuf, lame_offset) & 0x1f); |
684 | replay_gain[0] = ((bsbuf[lame_offset] & 0x2) ? -0.1 : 0.1) * (make_short(bsbuf, lame_offset) & 0x1f); |
685 | } |
685 | } |
686 | lame_offset += 2; |
686 | lame_offset += 2; |
687 | } |
687 | } |
688 | debug1("Info: Radio Gain = %03.1fdB", replay_gain[0]); |
688 | debug1("Info: Radio Gain = %03.1fdB", replay_gain[0]); |
689 | debug1("Info: Audiophile Gain = %03.1fdB", replay_gain[1]); |
689 | debug1("Info: Audiophile Gain = %03.1fdB", replay_gain[1]); |
690 | for(i=0; i < 2; ++i) |
690 | for(i=0; i < 2; ++i) |
691 | { |
691 | { |
692 | if(rva_level[i] <= 0) |
692 | if(rva_level[i] <= 0) |
693 | { |
693 | { |
694 | rva_peak[i] = 0; /* at some time the parsed peak should be used */ |
694 | rva_peak[i] = 0; /* at some time the parsed peak should be used */ |
695 | rva_gain[i] = replay_gain[i]; |
695 | rva_gain[i] = replay_gain[i]; |
696 | rva_level[i] = 0; |
696 | rva_level[i] = 0; |
697 | } |
697 | } |
698 | } |
698 | } |
699 | lame_offset += 1; /* skipping encoding flags byte */ |
699 | lame_offset += 1; /* skipping encoding flags byte */ |
700 | if(vbr == ABR) |
700 | if(vbr == ABR) |
701 | { |
701 | { |
702 | abr_rate = bsbuf[lame_offset]; |
702 | abr_rate = bsbuf[lame_offset]; |
703 | debug1("Info: ABR rate = %u", abr_rate); |
703 | debug1("Info: ABR rate = %u", abr_rate); |
704 | } |
704 | } |
705 | lame_offset += 1; |
705 | lame_offset += 1; |
706 | /* encoder delay and padding, two 12 bit values... lame does write them from int ...*/ |
706 | /* encoder delay and padding, two 12 bit values... lame does write them from int ...*/ |
707 | #ifdef GAPLESS |
707 | #ifdef GAPLESS |
708 | if(param.gapless) |
708 | if(param.gapless) |
709 | { |
709 | { |
710 | /* |
710 | /* |
711 | Temporary hack that doesn't work with seeking and also is not waterproof but works most of the time; |
711 | Temporary hack that doesn't work with seeking and also is not waterproof but works most of the time; |
712 | in future the lame delay/padding and frame number info should be passed to layer3.c and the junk samples avoided at the source. |
712 | in future the lame delay/padding and frame number info should be passed to layer3.c and the junk samples avoided at the source. |
713 | */ |
713 | */ |
714 | unsigned long length = track_frames * spf(fr); |
714 | unsigned long length = track_frames * spf(fr); |
715 | unsigned long skipbegin = DECODER_DELAY + ((((int) bsbuf[lame_offset]) << 4) | (((int) bsbuf[lame_offset+1]) >> 4)); |
715 | unsigned long skipbegin = DECODER_DELAY + ((((int) bsbuf[lame_offset]) << 4) | (((int) bsbuf[lame_offset+1]) >> 4)); |
716 | unsigned long skipend = -DECODER_DELAY + (((((int) bsbuf[lame_offset+1]) << 8) | (((int) bsbuf[lame_offset+2]))) & 0xfff); |
716 | unsigned long skipend = -DECODER_DELAY + (((((int) bsbuf[lame_offset+1]) << 8) | (((int) bsbuf[lame_offset+2]))) & 0xfff); |
717 | debug3("preparing gapless mode for layer3: length %lu, skipbegin %lu, skipend %lu", length, skipbegin, skipend); |
717 | debug3("preparing gapless mode for layer3: length %lu, skipbegin %lu, skipend %lu", length, skipbegin, skipend); |
718 | if(length > 1) |
718 | if(length > 1) |
719 | layer3_gapless_init(skipbegin+GAP_SHIFT, (skipend < length) ? length-skipend+GAP_SHIFT : length+GAP_SHIFT); |
719 | layer3_gapless_init(skipbegin+GAP_SHIFT, (skipend < length) ? length-skipend+GAP_SHIFT : length+GAP_SHIFT); |
720 | } |
720 | } |
721 | #endif |
721 | #endif |
722 | } |
722 | } |
723 | /* switch buffer back ... */ |
723 | /* switch buffer back ... */ |
724 | bsbuf = bsspace[bsnum]+512; |
724 | bsbuf = bsspace[bsnum]+512; |
725 | bsnum = (bsnum + 1) & 1; |
725 | bsnum = (bsnum + 1) & 1; |
726 | goto read_again; |
726 | goto read_again; |
727 | } |
727 | } |
728 | } |
728 | } |
729 | } |
729 | } |
730 | } /* end block for Xing/Lame/Info tag */ |
730 | } /* end block for Xing/Lame/Info tag */ |
731 | firsthead = newhead; /* _now_ it's time to store it... the first real header */ |
731 | firsthead = newhead; /* _now_ it's time to store it... the first real header */ |
732 | debug1("firsthead: %08lx", firsthead); |
732 | debug1("firsthead: %08lx", firsthead); |
733 | /* now adjust volume */ |
733 | /* now adjust volume */ |
734 | do_rva(); |
734 | do_rva(); |
735 | /* and print id3 info */ |
735 | /* and print id3 info */ |
736 | if(!param.quiet) print_id3_tag(rd->flags & READER_ID3TAG ? rd->id3buf : NULL); |
736 | if(!param.quiet) print_id3_tag(rd->flags & READER_ID3TAG ? rd->id3buf : NULL); |
737 | } |
737 | } |
738 | #endif |
738 | #endif |
739 | 739 | ||
740 | bsi.bitindex = 0; |
740 | bsi.bitindex = 0; |
741 | bsi.wordpointer = (unsigned char *) bsbuf; |
741 | bsi.wordpointer = (unsigned char *) bsbuf; |
742 | set_synth_functions(fr); |
742 | set_synth_functions(fr); |
743 | if (fr->error_protection) |
743 | if (fr->error_protection) |
744 | getbits(16); |
744 | getbits(16); |
745 | return 1; |
745 | return 1; |
746 | } |
746 | } |
747 | 747 | ||
748 | 748 | ||
749 | #if 0 |
749 | #if 0 |
750 | 750 | ||
751 | static int stream_back_bytes(struct reader *rds, off_t bytes) |
751 | static int stream_back_bytes(struct reader *rds, off_t bytes) |
752 | { |
752 | { |
753 | if(stream_lseek(rds,-bytes,SEEK_CUR) < 0) |
753 | if(stream_lseek(rds,-bytes,SEEK_CUR) < 0) |
754 | return -1; |
754 | return -1; |
755 | /* you sure you want the buffer to resync here? */ |
755 | /* you sure you want the buffer to resync here? */ |
756 | if(param.usebuffer) |
756 | if(param.usebuffer) |
757 | buffer_resync(); |
757 | buffer_resync(); |
758 | return 0; |
758 | return 0; |
759 | } |
759 | } |
760 | 760 | ||
761 | 761 | ||
762 | /* this function strangely is define to seek num frames _back_ (and is called with -offset - duh!) */ |
762 | /* this function strangely is define to seek num frames _back_ (and is called with -offset - duh!) */ |
763 | /* also... let that int be a long in future! */ |
763 | /* also... let that int be a long in future! */ |
764 | static int stream_back_frame(struct reader *rds,struct frame *fr,long num) |
764 | static int stream_back_frame(struct reader *rds,struct frame *fr,long num) |
765 | { |
765 | { |
766 | if(rds->flags & READER_SEEKABLE) |
766 | if(rds->flags & READER_SEEKABLE) |
767 | { |
767 | { |
768 | unsigned long newframe, preframe; |
768 | unsigned long newframe, preframe; |
769 | if(num > 0) /* back! */ |
769 | if(num > 0) /* back! */ |
770 | { |
770 | { |
771 | if(num > fr->num) newframe = 0; |
771 | if(num > fr->num) newframe = 0; |
772 | else newframe = fr->num-num; |
772 | else newframe = fr->num-num; |
773 | } |
773 | } |
774 | else newframe = fr->num-num; |
774 | else newframe = fr->num-num; |
775 | 775 | ||
776 | /* two leading frames? hm, doesn't seem to be really needed... */ |
776 | /* two leading frames? hm, doesn't seem to be really needed... */ |
777 | /*if(newframe > 1) newframe -= 2; |
777 | /*if(newframe > 1) newframe -= 2; |
778 | else newframe = 0;*/ |
778 | else newframe = 0;*/ |
779 | 779 | ||
780 | /* now seek to nearest leading index position and read from there until newframe is reached */ |
780 | /* now seek to nearest leading index position and read from there until newframe is reached */ |
781 | if(stream_lseek(rds,frame_index_find(newframe, &preframe),SEEK_SET) < 0) |
781 | if(stream_lseek(rds,frame_index_find(newframe, &preframe),SEEK_SET) < 0) |
782 | return -1; |
782 | return -1; |
783 | 783 | ||
784 | debug2("going to %lu; just got %lu", newframe, preframe); |
784 | debug2("going to %lu; just got %lu", newframe, preframe); |
785 | 785 | ||
786 | fr->num = preframe; |
786 | fr->num = preframe; |
787 | 787 | ||
788 | while(fr->num < newframe) |
788 | while(fr->num < newframe) |
789 | { |
789 | { |
790 | /* try to be non-fatal now... frameNum only gets advanced on success anyway */ |
790 | /* try to be non-fatal now... frameNum only gets advanced on success anyway */ |
791 | if(!read_frame(fr)) break; |
791 | if(!read_frame(fr)) break; |
792 | } |
792 | } |
793 | 793 | ||
794 | /* this is not needed at last? */ |
794 | /* this is not needed at last? */ |
795 | /*read_frame(fr); |
795 | /*read_frame(fr); |
796 | read_frame(fr);*/ |
796 | read_frame(fr);*/ |
797 | 797 | ||
798 | if(fr->lay == 3) { |
798 | if(fr->lay == 3) { |
799 | set_pointer(512); |
799 | set_pointer(512); |
800 | } |
800 | } |
801 | 801 | ||
802 | debug1("arrived at %lu", fr->num); |
802 | debug1("arrived at %lu", fr->num); |
803 | 803 | ||
804 | if(param.usebuffer) |
804 | if(param.usebuffer) |
805 | buffer_resync(); |
805 | buffer_resync(); |
806 | 806 | ||
807 | return 0; |
807 | return 0; |
808 | 808 | ||
809 | } |
809 | } |
810 | else return -1; /* invalid, no seek happened */ |
810 | else return -1; /* invalid, no seek happened */ |
811 | } |
811 | } |
812 | 812 | ||
813 | static int stream_head_read(struct reader *rds,unsigned long *newhead) |
813 | static int stream_head_read(struct reader *rds,unsigned long *newhead) |
814 | { |
814 | { |
815 | unsigned char hbuf[4]; |
815 | unsigned char hbuf[4]; |
816 | 816 | ||
817 | if(fullread(rds,hbuf,4) != 4) |
817 | if(fullread(rds,hbuf,4) != 4) |
818 | return FALSE; |
818 | return FALSE; |
819 | 819 | ||
820 | *newhead = ((unsigned long) hbuf[0] << 24) | |
820 | *newhead = ((unsigned long) hbuf[0] << 24) | |
821 | ((unsigned long) hbuf[1] << 16) | |
821 | ((unsigned long) hbuf[1] << 16) | |
822 | ((unsigned long) hbuf[2] << 8) | |
822 | ((unsigned long) hbuf[2] << 8) | |
823 | (unsigned long) hbuf[3]; |
823 | (unsigned long) hbuf[3]; |
824 | 824 | ||
825 | return TRUE; |
825 | return TRUE; |
826 | } |
826 | } |
827 | 827 | ||
828 | static int stream_head_shift(struct reader *rds,unsigned long *head) |
828 | static int stream_head_shift(struct reader *rds,unsigned long *head) |
829 | { |
829 | { |
830 | unsigned char hbuf; |
830 | unsigned char hbuf; |
831 | 831 | ||
832 | if(fullread(rds,&hbuf,1) != 1) |
832 | if(fullread(rds,&hbuf,1) != 1) |
833 | return 0; |
833 | return 0; |
834 | *head <<= 8; |
834 | *head <<= 8; |
835 | *head |= hbuf; |
835 | *head |= hbuf; |
836 | *head &= 0xffffffff; |
836 | *head &= 0xffffffff; |
837 | return 1; |
837 | return 1; |
838 | } |
838 | } |
839 | 839 | ||
840 | static off_t stream_skip_bytes(struct reader *rds,off_t len) |
840 | static off_t stream_skip_bytes(struct reader *rds,off_t len) |
841 | { |
841 | { |
842 | if (rds->filelen >= 0) { |
842 | if (rds->filelen >= 0) { |
843 | off_t ret = stream_lseek(rds, len, SEEK_CUR); |
843 | off_t ret = stream_lseek(rds, len, SEEK_CUR); |
844 | if (param.usebuffer) |
844 | if (param.usebuffer) |
845 | buffer_resync(); |
845 | buffer_resync(); |
846 | return ret; |
846 | return ret; |
847 | } else if (len >= 0) { |
847 | } else if (len >= 0) { |
848 | unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */ |
848 | unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */ |
849 | off_t ret; |
849 | off_t ret; |
850 | while (len > 0) { |
850 | while (len > 0) { |
851 | off_t num = len < sizeof(buf) ? len : sizeof(buf); |
851 | off_t num = len < sizeof(buf) ? len : sizeof(buf); |
852 | ret = fullread(rds, buf, num); |
852 | ret = fullread(rds, buf, num); |
853 | if (ret < 0) |
853 | if (ret < 0) |
854 | return ret; |
854 | return ret; |
855 | len -= ret; |
855 | len -= ret; |
856 | } |
856 | } |
857 | return rds->filepos; |
857 | return rds->filepos; |
858 | } else |
858 | } else |
859 | return -1; |
859 | return -1; |
860 | } |
860 | } |
861 | 861 | ||
862 | static int stream_read_frame_body(struct reader *rds,unsigned char *buf, |
862 | static int stream_read_frame_body(struct reader *rds,unsigned char *buf, |
863 | int size) |
863 | int size) |
864 | { |
864 | { |
865 | long l; |
865 | long l; |
866 | 866 | ||
867 | if( (l=fullread(rds,buf,size)) != size) |
867 | if( (l=fullread(rds,buf,size)) != size) |
868 | { |
868 | { |
869 | if(l <= 0) |
869 | if(l <= 0) |
870 | return 0; |
870 | return 0; |
871 | memset(buf+l,0,size-l); |
871 | memset(buf+l,0,size-l); |
872 | } |
872 | } |
873 | 873 | ||
874 | return 1; |
874 | return 1; |
875 | } |
875 | } |
876 | 876 | ||
877 | static off_t stream_tell(struct reader *rds) |
877 | static off_t stream_tell(struct reader *rds) |
878 | { |
878 | { |
879 | return rds->filepos; |
879 | return rds->filepos; |
880 | } |
880 | } |
881 | 881 | ||
882 | static void stream_rewind(struct reader *rds) |
882 | static void stream_rewind(struct reader *rds) |
883 | { |
883 | { |
884 | stream_lseek(rds,0,SEEK_SET); |
884 | stream_lseek(rds,0,SEEK_SET); |
885 | if(param.usebuffer) |
885 | if(param.usebuffer) |
886 | buffer_resync(); |
886 | buffer_resync(); |
887 | } |
887 | } |
888 | 888 | ||
889 | static off_t get_fileinfo(struct reader *rds,char *buf) |
889 | static off_t get_fileinfo(struct reader *rds,char *buf) |
890 | { |
890 | { |
891 | off_t len; |
891 | off_t len; |
892 | 892 | ||
893 | if((len=lseek(rds->filept,0,SEEK_END)) < 0) { |
893 | if((len=lseek(rds->filept,0,SEEK_END)) < 0) { |
894 | return -1; |
894 | return -1; |
895 | } |
895 | } |
896 | if(lseek(rds->filept,-128,SEEK_END) < 0) |
896 | if(lseek(rds->filept,-128,SEEK_END) < 0) |
897 | return -1; |
897 | return -1; |
898 | if(fullread(rds,(unsigned char *)buf,128) != 128) { |
898 | if(fullread(rds,(unsigned char *)buf,128) != 128) { |
899 | return -1; |
899 | return -1; |
900 | } |
900 | } |
901 | if(!strncmp(buf,"TAG",3)) { |
901 | if(!strncmp(buf,"TAG",3)) { |
902 | len -= 128; |
902 | len -= 128; |
903 | } |
903 | } |
904 | if(lseek(rds->filept,0,SEEK_SET) < 0) |
904 | if(lseek(rds->filept,0,SEEK_SET) < 0) |
905 | return -1; |
905 | return -1; |
906 | if(len <= 0) |
906 | if(len <= 0) |
907 | return -1; |
907 | return -1; |
908 | return len; |
908 | return len; |
909 | } |
909 | } |
910 | 910 | ||
911 | #endif |
911 | #endif |
912 | 912 | ||
913 | #define syncsafe_to_long(buf,res) \ |
913 | #define syncsafe_to_long(buf,res) \ |
914 | ( \ |
914 | ( \ |
915 | (((buf)[0]|(buf)[1]|(buf)[2]|(buf)[3]) & 0x80) ? 0 : \ |
915 | (((buf)[0]|(buf)[1]|(buf)[2]|(buf)[3]) & 0x80) ? 0 : \ |
916 | (res = (((unsigned long) (buf)[0]) << 27) \ |
916 | (res = (((unsigned long) (buf)[0]) << 27) \ |
917 | | (((unsigned long) (buf)[1]) << 14) \ |
917 | | (((unsigned long) (buf)[1]) << 14) \ |
918 | | (((unsigned long) (buf)[2]) << 7) \ |
918 | | (((unsigned long) (buf)[2]) << 7) \ |
919 | | ((unsigned long) (buf)[3]) \ |
919 | | ((unsigned long) (buf)[3]) \ |
920 | ,1) \ |
920 | ,1) \ |
921 | ) |
921 | ) |
922 | 922 | ||
923 | int parse_new_id3(struct reader *rd, unsigned long header) |
923 | int parse_new_id3(struct reader *rd, unsigned long header) |
924 | { |
924 | { |
925 | #define UNSYNC_FLAG 128 |
925 | #define UNSYNC_FLAG 128 |
926 | #define EXTHEAD_FLAG 64 |
926 | #define EXTHEAD_FLAG 64 |
927 | #define EXP_FLAG 32 |
927 | #define EXP_FLAG 32 |
928 | #define FOOTER_FLAG 16 |
928 | #define FOOTER_FLAG 16 |
929 | #define UNKNOWN_FLAGS 15 /* 00001111*/ |
929 | #define UNKNOWN_FLAGS 15 /* 00001111*/ |
930 | unsigned char buf[6]; |
930 | unsigned char buf[6]; |
931 | unsigned long length=0; |
931 | unsigned long length=0; |
932 | unsigned char flags = 0; |
932 | unsigned char flags = 0; |
933 | int ret = 1; |
933 | int ret = 1; |
934 | unsigned char* tagdata = NULL; |
934 | unsigned char* tagdata = NULL; |
935 | unsigned char major = header & 0xff; |
935 | unsigned char major = header & 0xff; |
936 | 936 | ||
937 | if(major == 0xff) return -1; |
937 | if(major == 0xff) return -1; |
938 | 938 | ||
939 | if (rd->read_frame_body(rd,buf,6)<6) |
939 | if (rd->read_frame_body(rd,buf,6)<6) |
940 | return 0; |
940 | return 0; |
941 | if(buf[0] == 0xff) /* major version, will never be 0xff */ |
941 | if(buf[0] == 0xff) /* major version, will never be 0xff */ |
942 | return -1; |
942 | return -1; |
943 | 943 | ||
944 | /* second new byte are some nice flags, if these are invalid skip the whole thing */ |
944 | /* second new byte are some nice flags, if these are invalid skip the whole thing */ |
945 | flags = buf[1]; |
945 | flags = buf[1]; |
946 | /* use 4 bytes from buf to construct 28bit uint value and return 1; return 0 if bytes are not syncsafe */ |
946 | /* use 4 bytes from buf to construct 28bit uint value and return 1; return 0 if bytes are not syncsafe */ |
947 | 947 | ||
948 | if(!syncsafe_to_long(buf+2,length)) |
948 | if(!syncsafe_to_long(buf+2,length)) |
949 | return -1; |
949 | return -1; |
950 | 950 | ||
- | 951 | ||
- | 952 | if(rd->strremain < length) |
|
- | 953 | { |
|
- | 954 | rd->filepos += length - rd->strremain; |
|
- | 955 | rd->strremain = 0; |
|
- | 956 | } |
|
- | 957 | else |
|
951 | 958 | { |
|
952 | rd->strpos+=length; |
959 | rd->strpos+=length; |
953 | rd->stream+=length; |
960 | rd->stream+=length; |
954 | rd->strremain-=length; |
961 | rd->strremain-=length; |
- | 962 | } |
|
955 | 963 | ||
956 | #if 0 |
964 | #if 0 |
957 | /* skip if unknown version/scary flags, parse otherwise */ |
965 | /* skip if unknown version/scary flags, parse otherwise */ |
958 | if((flags & UNKNOWN_FLAGS) || (major > 4)) |
966 | if((flags & UNKNOWN_FLAGS) || (major > 4)) |
959 | { |
967 | { |
960 | /* going to skip because there are unknown flags set */ |
968 | /* going to skip because there are unknown flags set */ |
961 | if(!rds->skip_bytes(rds,length)) /* will not store data in backbuff! */ |
969 | if(!rds->skip_bytes(rds,length)) /* will not store data in backbuff! */ |
962 | 970 | ||
963 | rd->strpos+=length; |
971 | rd->strpos+=length; |
964 | rd->stream+=length; |
972 | rd->stream+=length; |
965 | rd->strremain-=length; |
973 | rd->strremain-=length; |
966 | ret = 0; |
974 | ret = 0; |
967 | }; |
975 | }; |
968 | #endif |
976 | #endif |
969 | return length; |
977 | return length; |
970 | };6) |
978 | };>6) |
971 | >><>><>><>=>>>>=>>>=><=>><>><>><>>>>>><>><>=>>>><>><>><>><>>>>8))><8))>16)+('p'<<8))><16)+('p'<<8))>24)+('m'<<16)+('p'<<8))><24)+('m'<<16)+('p'<<8))>8))><8))>16)+('G'<<8))><16)+('G'<<8))>24)+('A'<<16)+('G'<<8))><24)+('A'<<16)+('G'<<8))>65536;i++)>8)+'a')><8)+'a')>16)+('t'<<8)+'a')><16)+('t'<<8)+'a')>24)+('a'<<16)+('t'<<8)+'a')><24)+('a'<<16)+('t'<<8)+'a')>8)+'F')><8)+'F')>16)+('F'<<8)+'F')><16)+('F'<<8)+'F')>24)+('I'<<16)+('F'<<8)+'F')><24)+('I'<<16)+('F'<<8)+'F')>(fr-><(fr->2)-4; |
979 | >><>><>><>=>>>>=>>>=><=>><>><>><>>>>>><>><>=>>>><>><>><>><>>>>8))><8))>16)+('p'<<8))><16)+('p'<<8))>24)+('m'<<16)+('p'<<8))><24)+('m'<<16)+('p'<<8))>8))><8))>16)+('G'<<8))><16)+('G'<<8))>24)+('A'<<16)+('G'<<8))><24)+('A'<<16)+('G'<<8))>65536;i++)>8)+'a')><8)+'a')>16)+('t'<<8)+'a')><16)+('t'<<8)+'a')>24)+('a'<<16)+('t'<<8)+'a')><24)+('a'<<16)+('t'<<8)+'a')>8)+'F')><8)+'F')>16)+('F'<<8)+'F')><16)+('F'<<8)+'F')>24)+('I'<<16)+('F'<<8)+'F')><24)+('I'<<16)+('F'<<8)+'F')>(fr-><(fr->2)-4; |
972 | ><2)-4; |
980 | ><2)-4; |
973 | >19))><19))>20)><20)>>><>><>24)|(rd-><24)|(rd->>> |
981 | >19))><19))>20)><20)>>><>><>24)|(rd-><24)|(rd->>> |