Merge branch 'master' into startpage
[swftools.git] / lib / mp3.c
1 /* mp3.c
2    Routines for handling .mp3 files
3
4    Part of the swftools package.
5    
6    Copyright (c) 2005 Joel Yliluoma <bisqwit@iki.fi>
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "mp3.h"
27
28 struct MP3Frame
29 {
30     unsigned bitrate;
31     unsigned samprate;
32     unsigned chanmode;
33     unsigned framesize;
34     unsigned char* data;
35     struct MP3Frame* next;
36 };
37
38 //                                    0          4           8               C
39 static const unsigned BR_mpeg1[16] = {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0};
40 static const unsigned BR_mpeg2[16] = {0,8, 16,24,32,40,48,56, 64, 80, 96,112,128,144,160,0};
41 static const unsigned BR_reserved[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
42 static const unsigned*const BR[4] = {BR_mpeg2, BR_reserved, BR_mpeg2, BR_mpeg1};
43
44 static const unsigned SR_mpeg1[4] = {44100,48000,32000,0};
45 static const unsigned SR_mpeg2[4] = {22050,24000,16000,0};
46 static const unsigned SR_mpeg25[4] = {11025,12000,8000,0};
47 static const unsigned SR_reserved[4] = {0,0,0,0};
48 static const unsigned*const SR[4] = {SR_mpeg25, SR_reserved, SR_mpeg2, SR_mpeg1};
49
50 int mp3_read(struct MP3*mp3, const char* filename)
51 {
52     struct MP3Frame* root = 0;
53     struct MP3Frame** cur = &root;
54     
55     unsigned totalsize      = 0;
56     unsigned first_samprate = 0;
57     unsigned nframes = 0;
58     int first_chanmode = -1;
59
60     FILE*fi = fopen(filename, "rb");
61     if(!fi) return 0;
62     
63     for(;;)
64     {
65         unsigned char FrameBuf[2048];
66         unsigned char* hdr = FrameBuf;
67         unsigned char* data = FrameBuf+4;
68         unsigned char* frdata;
69
70         unsigned char mpegver;
71         unsigned padding;
72         unsigned bitrate;
73         unsigned samprate;
74         unsigned framesize;
75         int chanmode;
76
77         if(fread(hdr,1,4,fi) < 4) break;
78
79         if(hdr[0] == 'I' && hdr[1] == 'D' && hdr[2] == '3')
80         {
81             /* Skip ID3 header */
82             unsigned id3_size = 0;
83             if(fread(FrameBuf, 1, 6, fi) < 6) break;
84  
85             id3_size = (FrameBuf[5])
86                      + (FrameBuf[4] << 7)
87                      + (FrameBuf[3] << 14)
88                      + (FrameBuf[2] << 21);
89             fprintf(stderr, "readMP3: skipping ID3 tag (10+%u bytes)\n", id3_size);
90             if(fseek(fi, id3_size, SEEK_CUR) < 0)
91             {
92                 /* Cannot seek? Try reading. */
93                 char* tmpbuf = (char*)malloc(id3_size);
94                 int nread=0;
95                 if(!tmpbuf)
96                 {
97                     fprintf(stderr, "readMP3: fseek and malloc both failed?\n");
98                     break;
99                 }
100                 nread = fread(tmpbuf, 1, id3_size, fi);
101                 free(tmpbuf);
102                 if(nread < id3_size) break;
103             }
104             continue;
105         }
106
107
108         if(hdr[0] != 0xFF
109         || (hdr[1] & 0xE0) != 0xE0)
110         {
111             fprintf(stderr, "readMP3: invalid header %02X %02X %02X %02X\n",
112                 hdr[0],hdr[1],hdr[2],hdr[3]);
113             break;
114         }
115         
116         mpegver = (hdr[1] >> 3) & 0x03;
117         
118         bitrate  = BR[mpegver][ (hdr[2] >> 4) & 0x0F ] * 1000;
119         samprate = SR[mpegver][ (hdr[2] >> 2) & 0x03 ];
120         chanmode = (hdr[3] >> 6) & 0x03;
121         
122         padding = (hdr[2] & 2) ? 1 : 0;
123         
124         if(!bitrate || !samprate)
125         {
126             /* Invalid frame */
127             /*break;*/
128         }
129         if(!first_samprate) first_samprate = samprate;
130         else if(first_samprate != samprate)
131         {
132             /* Sampling rate changed?!? */
133             fprintf(stderr, "readMP3: sampling rate changed?\n");
134             /*break;*/
135         }
136         if(first_chanmode<0) first_chanmode = chanmode;
137         else if(first_chanmode != chanmode)
138         {
139             /* Channel mode changed?!? */
140             fprintf(stderr, "readMP3: chanmode changed?\n");
141             /*break;*/
142         }
143         
144         framesize = ((mpegver == 3 ? 144 : 72) * bitrate) / samprate + padding;
145         
146 /*
147         fprintf(stderr, "%02X %02X %02X %02X - bitrate=%u,samprate=%u,chanmode=%u,padding=%u,framesize=%u\n",
148             hdr[0],hdr[1],hdr[2],hdr[3],bitrate,samprate,chanmode,padding,framesize);
149 */
150         if(framesize > sizeof(FrameBuf)) break;
151         if(fread(data, 1, framesize - 4, fi) < framesize-4)
152         {
153             fprintf(stderr, "readMP3: short read at frame %u\n", nframes);
154             break;
155         }
156         
157         if(!bitrate || !samprate) continue; 
158         
159         frdata = (unsigned char*)malloc(framesize);
160         if(!frdata)
161         {
162             fprintf(stderr, "readMP3: malloc failed\n");
163             break;
164         }
165         
166         *cur = (struct MP3Frame*)malloc(sizeof(*root));
167         if(!*cur)
168         {
169             fprintf(stderr, "readMP3: malloc failed\n");
170             free(frdata);
171             break;
172         }
173         
174         (*cur)->next = 0;
175         (*cur)->bitrate = bitrate;
176         (*cur)->samprate = samprate;
177         (*cur)->chanmode = chanmode;
178         (*cur)->framesize = framesize;
179         (*cur)->data = frdata;
180         
181         memcpy(frdata, FrameBuf, framesize);
182         cur = &(*cur)->next;
183         
184         totalsize += framesize;
185         ++nframes;
186     }
187     if(!root)
188     {
189         fprintf(stderr, "readMP3: not a MP3 file\n");
190         fclose(fi);
191         return 0;
192     }
193     
194     /*
195     fprintf(stderr, "readMP3: read %u frames (%u bytes)\n", nframes, totalsize);
196     */
197
198     mp3->SampRate = first_samprate;
199     mp3->Channels = first_chanmode == 3 ? 1 : 2;
200     mp3->NumFrames = nframes;
201     mp3->size = totalsize;
202     mp3->data = (unsigned char*)malloc(mp3->size);
203     if(mp3->data)
204     {
205         unsigned pos=0;
206         struct MP3Frame* it;
207         for(it=root; it; it=it->next)
208         {
209             memcpy(mp3->data + pos, it->data, it->framesize);
210             pos += it->framesize;
211         }
212     }
213     else
214     {
215         fprintf(stderr, "readMP3: malloc failed\n");
216     }
217     
218     while(root)
219     {
220         struct MP3Frame* next = root->next;
221         free(root->data);
222         free(root);
223         root = next;
224     }
225     
226     fclose(fi);
227     return mp3->data != NULL;
228 }
229
230 void mp3_clear(struct MP3*mp3)
231 {
232     free(mp3->data);
233     mp3->data = 0;
234 }
235
236