"Fossies" - the Fresh Open Source Software Archive 
Member "mp3info-0.8.5a/mp3tech.c" (6 Nov 2006, 10800 Bytes) of package /linux/misc/old/mp3info-0.8.5a.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "mp3tech.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 mp3tech.c - Functions for handling MP3 files and most MP3 data
3 structure manipulation.
4
5 Copyright (C) 2000-2006 Cedric Tefft <cedric@phreaker.net>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 ***************************************************************************
22
23 This file is based in part on:
24
25 * MP3Info 0.5 by Ricardo Cerqueira <rmc@rccn.net>
26 * MP3Stat 0.9 by Ed Sweetman <safemode@voicenet.com> and
27 Johannes Overmann <overmann@iname.com>
28
29 */
30
31 #include "mp3info.h"
32
33
34 int layer_tab[4]= {0, 3, 2, 1};
35
36 int frequencies[3][4] = {
37 {22050,24000,16000,50000}, /* MPEG 2.0 */
38 {44100,48000,32000,50000}, /* MPEG 1.0 */
39 {11025,12000,8000,50000} /* MPEG 2.5 */
40 };
41
42 int bitrate[2][3][15] = {
43 { /* MPEG 2.0 */
44 {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256}, /* layer 1 */
45 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}, /* layer 2 */
46 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160} /* layer 3 */
47
48 },
49
50 { /* MPEG 1.0 */
51 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448}, /* layer 1 */
52 {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384}, /* layer 2 */
53 {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320} /* layer 3 */
54 }
55 };
56
57 int frame_size_index[] = {24000, 72000, 72000};
58
59
60 char *mode_text[] = {
61 "stereo", "joint stereo", "dual channel", "mono"
62 };
63
64 char *emphasis_text[] = {
65 "none", "50/15 microsecs", "reserved", "CCITT J 17"
66 };
67
68
69 int get_mp3_info(mp3info *mp3,int scantype, int fullscan_vbr)
70 {
71 int had_error = 0;
72 int frame_type[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
73 float seconds=0,total_rate=0;
74 int frames=0,frame_types=0,frames_so_far=0;
75 int l,vbr_median=-1;
76 int bitrate,lastrate;
77 int counter=0;
78 mp3header header;
79 struct stat filestat;
80 off_t sample_pos,data_start=0;
81
82
83 stat(mp3->filename,&filestat);
84 mp3->datasize=filestat.st_size;
85 get_id3(mp3);
86
87 if(scantype == SCAN_QUICK) {
88 if(get_first_header(mp3,0L)) {
89 data_start=ftell(mp3->file);
90 lastrate=15-mp3->header.bitrate;
91 while((counter < NUM_SAMPLES) && lastrate) {
92 sample_pos=(counter*(mp3->datasize/NUM_SAMPLES+1))+data_start;
93 if(get_first_header(mp3,sample_pos)) {
94 bitrate=15-mp3->header.bitrate;
95 } else {
96 bitrate=-1;
97 }
98
99 if(bitrate != lastrate) {
100 mp3->vbr=1;
101 if(fullscan_vbr) {
102 counter=NUM_SAMPLES;
103 scantype=SCAN_FULL;
104 }
105 }
106 lastrate=bitrate;
107 counter++;
108
109 }
110 if(!(scantype == SCAN_FULL)) {
111 mp3->frames=(mp3->datasize-data_start)/(l=frame_length(&mp3->header));
112 mp3->seconds = (int)((float)(frame_length(&mp3->header)*mp3->frames)/
113 (float)(header_bitrate(&mp3->header)*125)+0.5);
114 mp3->vbr_average = (float)header_bitrate(&mp3->header);
115 }
116 }
117
118 }
119
120 if(scantype == SCAN_FULL) {
121 if(get_first_header(mp3,0L)) {
122 data_start=ftell(mp3->file);
123 while((bitrate=get_next_header(mp3))) {
124 frame_type[15-bitrate]++;
125 frames++;
126 }
127 memcpy(&header,&(mp3->header),sizeof(mp3header));
128 for(counter=0;counter<15;counter++) {
129 if(frame_type[counter]) {
130 frame_types++;
131 header.bitrate=counter;
132 frames_so_far += frame_type[counter];
133 seconds += (float)(frame_length(&header)*frame_type[counter])/
134 (float)(header_bitrate(&header)*125);
135 total_rate += (float)((header_bitrate(&header))*frame_type[counter]);
136 if((vbr_median == -1) && (frames_so_far >= frames/2))
137 vbr_median=counter;
138 }
139 }
140 mp3->seconds=(int)(seconds+0.5);
141 mp3->header.bitrate=vbr_median;
142 mp3->vbr_average=total_rate/(float)frames;
143 mp3->frames=frames;
144 if(frame_types > 1) {
145 mp3->vbr=1;
146 }
147 }
148 }
149 return had_error;
150 }
151
152
153 int get_first_header(mp3info *mp3, long startpos)
154 {
155 int k, l=0,c;
156 mp3header h, h2;
157 long valid_start=0;
158
159 fseek(mp3->file,startpos,SEEK_SET);
160 while (1) {
161 while((c=fgetc(mp3->file)) != 255 && (c != EOF));
162 if(c == 255) {
163 ungetc(c,mp3->file);
164 valid_start=ftell(mp3->file);
165 if((l=get_header(mp3->file,&h))) {
166 fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
167 for(k=1; (k < MIN_CONSEC_GOOD_FRAMES) && (mp3->datasize-ftell(mp3->file) >= FRAME_HEADER_SIZE); k++) {
168 if(!(l=get_header(mp3->file,&h2))) break;
169 if(!sameConstant(&h,&h2)) break;
170 fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
171 }
172 if(k == MIN_CONSEC_GOOD_FRAMES) {
173 fseek(mp3->file,valid_start,SEEK_SET);
174 memcpy(&(mp3->header),&h2,sizeof(mp3header));
175 mp3->header_isvalid=1;
176 return 1;
177 }
178 }
179 } else {
180 return 0;
181 }
182 }
183
184 return 0;
185 }
186
187 /* get_next_header() - read header at current position or look for
188 the next valid header if there isn't one at the current position
189 */
190 int get_next_header(mp3info *mp3)
191 {
192 int l=0,c,skip_bytes=0;
193 mp3header h;
194
195 while(1) {
196 while((c=fgetc(mp3->file)) != 255 && (ftell(mp3->file) < mp3->datasize)) skip_bytes++;
197 if(c == 255) {
198 ungetc(c,mp3->file);
199 if((l=get_header(mp3->file,&h))) {
200 if(skip_bytes) mp3->badframes++;
201 fseek(mp3->file,l-FRAME_HEADER_SIZE,SEEK_CUR);
202 return 15-h.bitrate;
203 } else {
204 skip_bytes += FRAME_HEADER_SIZE;
205 }
206 } else {
207 if(skip_bytes) mp3->badframes++;
208 return 0;
209 }
210 }
211 }
212
213
214 /* Get next MP3 frame header.
215 Return codes:
216 positive value = Frame Length of this header
217 0 = No, we did not retrieve a valid frame header
218 */
219
220 int get_header(FILE *file,mp3header *header)
221 {
222 unsigned char buffer[FRAME_HEADER_SIZE];
223 int fl;
224
225 if(fread(&buffer,FRAME_HEADER_SIZE,1,file)<1) {
226 header->sync=0;
227 return 0;
228 }
229 header->sync=(((int)buffer[0]<<4) | ((int)(buffer[1]&0xE0)>>4));
230 if(buffer[1] & 0x10) header->version=(buffer[1] >> 3) & 1;
231 else header->version=2;
232 header->layer=(buffer[1] >> 1) & 3;
233 header->bitrate=(buffer[2] >> 4) & 0x0F;
234 if((header->sync != 0xFFE) || (header->layer != 1) || (header->bitrate == 0xF)) {
235 header->sync=0;
236 return 0;
237 }
238 header->crc=buffer[1] & 1;
239 header->freq=(buffer[2] >> 2) & 0x3;
240 header->padding=(buffer[2] >>1) & 0x1;
241 header->extension=(buffer[2]) & 0x1;
242 header->mode=(buffer[3] >> 6) & 0x3;
243 header->mode_extension=(buffer[3] >> 4) & 0x3;
244 header->copyright=(buffer[3] >> 3) & 0x1;
245 header->original=(buffer[3] >> 2) & 0x1;
246 header->emphasis=(buffer[3]) & 0x3;
247
248 /* Final sanity checks: bitrate 1111b and frequency 11b are reserved (invalid) */
249 if (header->bitrate == 0x0F || header->freq == 0x3) {
250 return 0;
251 }
252
253 return ((fl=frame_length(header)) >= MIN_FRAME_SIZE ? fl : 0);
254 }
255
256 int frame_length(mp3header *header) {
257 return header->sync == 0xFFE ?
258 (frame_size_index[3-header->layer]*((header->version&1)+1)*
259 header_bitrate(header)/header_frequency(header))+
260 header->padding : 1;
261 }
262
263 int header_layer(mp3header *h) {return layer_tab[h->layer];}
264
265 int header_bitrate(mp3header *h) {
266 return bitrate[h->version & 1][3-h->layer][h->bitrate];
267 }
268
269 int header_frequency(mp3header *h) {
270 return frequencies[h->version][h->freq];
271 }
272
273 char *header_emphasis(mp3header *h) {
274 return emphasis_text[h->emphasis];
275 }
276
277 char *header_mode(mp3header *h) {
278 return mode_text[h->mode];
279 }
280
281 int sameConstant(mp3header *h1, mp3header *h2) {
282 if((*(uint*)h1) == (*(uint*)h2)) return 1;
283
284 if((h1->version == h2->version ) &&
285 (h1->layer == h2->layer ) &&
286 (h1->crc == h2->crc ) &&
287 (h1->freq == h2->freq ) &&
288 (h1->mode == h2->mode ) &&
289 (h1->copyright == h2->copyright ) &&
290 (h1->original == h2->original ) &&
291 (h1->emphasis == h2->emphasis ))
292 return 1;
293 else return 0;
294 }
295
296
297 int get_id3(mp3info *mp3) {
298 int retcode=0;
299 char fbuf[4];
300
301 if(mp3->datasize >= 128) {
302 if(fseek(mp3->file, -128, SEEK_END )) {
303 fprintf(stderr,"ERROR: Couldn't read last 128 bytes of %s!!\n",mp3->filename);
304 retcode |= 4;
305 } else {
306 fread(fbuf,1,3,mp3->file); fbuf[3] = '\0';
307 mp3->id3.genre[0]=255;
308
309
310 if (!strcmp((const char *)"TAG",(const char *)fbuf)) {
311
312
313 mp3->id3_isvalid=1;
314 mp3->datasize -= 128;
315 fseek(mp3->file, -125, SEEK_END);
316 fread(mp3->id3.title,1,30,mp3->file); mp3->id3.title[30] = '\0';
317 fread(mp3->id3.artist,1,30,mp3->file); mp3->id3.artist[30] = '\0';
318 fread(mp3->id3.album,1,30,mp3->file); mp3->id3.album[30] = '\0';
319 fread(mp3->id3.year,1,4,mp3->file); mp3->id3.year[4] = '\0';
320 fread(mp3->id3.comment,1,30,mp3->file); mp3->id3.comment[30] = '\0';
321 if(mp3->id3.comment[28] == '\0') {
322 mp3->id3.track[0] = mp3->id3.comment[29];
323 }
324 fread(mp3->id3.genre,1,1,mp3->file);
325 unpad(mp3->id3.title);
326 unpad(mp3->id3.artist);
327 unpad(mp3->id3.album);
328 unpad(mp3->id3.year);
329 unpad(mp3->id3.comment);
330 }
331 }
332 }
333 return retcode;
334
335 }
336
337 char *pad(char *string, int length) {
338 int l;
339
340 l=strlen(string);
341 while(l<length) {
342 string[l] = ' ';
343 l++;
344 }
345
346 string[l]='\0';
347 return string;
348 }
349
350 /* Remove trailing whitespace from the end of a string */
351
352 char *unpad(char *string) {
353 char *pos=string+strlen(string)-1;
354 while(isspace(pos[0])) (pos--)[0]=0;
355 return string;
356 }
357
358 /*
359 * Build an ID3 tag and write it to the file
360 * Returns positive int on success, 0 on failure
361 */
362
363 int write_tag(mp3info *mp3) {
364
365 char buf[129];
366
367 strcpy(buf,"TAG");
368 pad(mp3->id3.title,TEXT_FIELD_LEN);
369 strncat(buf,mp3->id3.title,TEXT_FIELD_LEN);
370 pad(mp3->id3.artist,TEXT_FIELD_LEN);
371 strncat(buf,mp3->id3.artist,TEXT_FIELD_LEN);
372 pad(mp3->id3.album,TEXT_FIELD_LEN);
373 strncat(buf,mp3->id3.album,TEXT_FIELD_LEN);
374 pad(mp3->id3.year,INT_FIELD_LEN);
375 strncat(buf,mp3->id3.year,INT_FIELD_LEN);
376 pad(mp3->id3.comment,TEXT_FIELD_LEN);
377 strncat(buf,mp3->id3.comment,TEXT_FIELD_LEN);
378 strncat(buf,(char *)&(mp3->id3.genre),1);
379 if (mp3->id3.track[0] != '\0') {
380 buf[125]='\0';
381 buf[126]=mp3->id3.track[0];
382 }
383 fseek(mp3->file,-128*mp3->id3_isvalid,SEEK_END);
384 return (int)fwrite(buf,1,128,mp3->file);
385 }