implemented a few more OutputDev functions
[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, 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         if(hdr[0] != 0xFF
79         || (hdr[1] & 0xE0) != 0xE0)
80         {
81             fprintf(stderr, "readMP3: invalid header %02X %02X %02X %02X\n",
82                 hdr[0],hdr[1],hdr[2],hdr[3]);
83             break;
84         }
85         
86         mpegver = (hdr[1] >> 3) & 0x03;
87         
88         bitrate  = BR[mpegver][ (hdr[2] >> 4) & 0x0F ] * 1000;
89         samprate = SR[mpegver][ (hdr[2] >> 2) & 0x03 ];
90         chanmode = (hdr[3] >> 6) & 0x03;
91         
92         padding = (hdr[2] & 2) ? 1 : 0;
93         
94         if(!bitrate || !samprate)
95         {
96             /* Invalid frame */
97             /*break;*/
98         }
99         if(!first_samprate) first_samprate = samprate;
100         else if(first_samprate != samprate)
101         {
102             /* Sampling rate changed?!? */
103             fprintf(stderr, "readMP3: sampling rate changed?\n");
104             /*break;*/
105         }
106         if(first_chanmode<0) first_chanmode = chanmode;
107         else if(first_chanmode != chanmode)
108         {
109             /* Channel mode changed?!? */
110             fprintf(stderr, "readMP3: chanmode changed?\n");
111             /*break;*/
112         }
113         
114         framesize = ((mpegver == 3 ? 144 : 72) * bitrate) / samprate + padding;
115         
116 /*
117         fprintf(stderr, "%02X %02X %02X %02X - bitrate=%u,samprate=%u,chanmode=%u,padding=%u,framesize=%u\n",
118             hdr[0],hdr[1],hdr[2],hdr[3],bitrate,samprate,chanmode,padding,framesize);
119 */
120         if(framesize > sizeof(FrameBuf)) break;
121         if(fread(data, 1, framesize - 4, fi) < framesize-4)
122         {
123             fprintf(stderr, "readMP3: short read at frame %u\n", nframes);
124             break;
125         }
126         
127         if(!bitrate || !samprate) continue; 
128         
129         frdata = (unsigned char*)malloc(framesize);
130         if(!frdata)
131         {
132             fprintf(stderr, "readMP3: malloc failed\n");
133             break;
134         }
135         
136         *cur = (struct MP3Frame*)malloc(sizeof(*root));
137         if(!*cur)
138         {
139             fprintf(stderr, "readMP3: malloc failed\n");
140             free(frdata);
141             break;
142         }
143         
144         (*cur)->next = 0;
145         (*cur)->bitrate = bitrate;
146         (*cur)->samprate = samprate;
147         (*cur)->chanmode = chanmode;
148         (*cur)->framesize = framesize;
149         (*cur)->data = frdata;
150         
151         memcpy(frdata, FrameBuf, framesize);
152         cur = &(*cur)->next;
153         
154         totalsize += framesize;
155         ++nframes;
156     }
157     if(!root)
158     {
159         fprintf(stderr, "readMP3: not a MP3 file\n");
160         fclose(fi);
161         return 0;
162     }
163     
164     /*
165     fprintf(stderr, "readMP3: read %u frames (%u bytes)\n", nframes, totalsize);
166     */
167
168     mp3->SampRate = first_samprate;
169     mp3->Channels = first_chanmode == 3 ? 1 : 2;
170     mp3->NumFrames = nframes;
171     mp3->size = totalsize;
172     mp3->data = (unsigned char*)malloc(mp3->size);
173     if(mp3->data)
174     {
175         unsigned pos=0;
176         struct MP3Frame* it;
177         for(it=root; it; it=it->next)
178         {
179             memcpy(mp3->data + pos, it->data, it->framesize);
180             pos += it->framesize;
181         }
182     }
183     else
184     {
185         fprintf(stderr, "readMP3: malloc failed\n");
186     }
187     
188     while(root)
189     {
190         struct MP3Frame* next = root->next;
191         free(root->data);
192         free(root);
193         root = next;
194     }
195     
196     fclose(fi);
197     return mp3->data != NULL;
198 }
199
200 void mp3_clear(struct MP3*mp3)
201 {
202     free(mp3->data);
203     mp3->data = 0;
204 }
205
206