Commit | Line | Data |
---|---|---|
132a5a4a RK |
1 | /** @file plugins/mad.c |
2 | * @brief MP3 Length calculation | |
3 | * | |
4 | * This file is a subset of the debian source tarball of | |
5 | * mpg321-0.2.10.3/mad.c - see http://mpg321.sourceforge.net/ | |
6 | */ | |
460b9539 | 7 | |
8 | /* | |
9 | mpg321 - a fully free clone of mpg123. | |
10 | Copyright (C) 2001 Joe Drew | |
11 | ||
12 | Originally based heavily upon: | |
13 | plaympeg - Sample MPEG player using the SMPEG library | |
14 | Copyright (C) 1999 Loki Entertainment Software | |
15 | ||
16 | Also uses some code from | |
17 | mad - MPEG audio decoder | |
18 | Copyright (C) 2000-2001 Robert Leslie | |
19 | ||
20 | Original playlist code contributed by Tobias Bengtsson <tobbe@tobbe.nu> | |
21 | ||
22 | This program is free software; you can redistribute it and/or modify | |
23 | it under the terms of the GNU General Public License as published by | |
24 | the Free Software Foundation; either version 2 of the License, or | |
25 | (at your option) any later version. | |
26 | ||
27 | This program is distributed in the hope that it will be useful, | |
28 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
30 | GNU General Public License for more details. | |
31 | ||
32 | You should have received a copy of the GNU General Public License | |
33 | along with this program; if not, write to the Free Software | |
34 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
35 | */ | |
36 | ||
37 | #include <sys/types.h> | |
38 | #include <string.h> | |
39 | ||
40 | #include <mad.h> | |
41 | ||
42 | #include "madshim.h" | |
43 | ||
44 | /* XING parsing is from the MAD winamp input plugin */ | |
45 | ||
46 | struct xing { | |
47 | int flags; | |
48 | unsigned long frames; | |
49 | unsigned long bytes; | |
50 | unsigned char toc[100]; | |
51 | long scale; | |
52 | }; | |
53 | ||
54 | enum { | |
55 | XING_FRAMES = 0x0001, | |
56 | XING_BYTES = 0x0002, | |
57 | XING_TOC = 0x0004, | |
58 | XING_SCALE = 0x0008 | |
59 | }; | |
60 | ||
61 | # define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g') | |
62 | ||
63 | static | |
64 | int parse_xing(struct xing *xing, struct mad_bitptr ptr, unsigned int bitlen) | |
65 | { | |
66 | if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC) | |
67 | goto fail; | |
68 | ||
69 | xing->flags = mad_bit_read(&ptr, 32); | |
70 | bitlen -= 64; | |
71 | ||
72 | if (xing->flags & XING_FRAMES) { | |
73 | if (bitlen < 32) | |
74 | goto fail; | |
75 | ||
76 | xing->frames = mad_bit_read(&ptr, 32); | |
77 | bitlen -= 32; | |
78 | } | |
79 | ||
80 | if (xing->flags & XING_BYTES) { | |
81 | if (bitlen < 32) | |
82 | goto fail; | |
83 | ||
84 | xing->bytes = mad_bit_read(&ptr, 32); | |
85 | bitlen -= 32; | |
86 | } | |
87 | ||
88 | if (xing->flags & XING_TOC) { | |
89 | int i; | |
90 | ||
91 | if (bitlen < 800) | |
92 | goto fail; | |
93 | ||
94 | for (i = 0; i < 100; ++i) | |
95 | xing->toc[i] = mad_bit_read(&ptr, 8); | |
96 | ||
97 | bitlen -= 800; | |
98 | } | |
99 | ||
100 | if (xing->flags & XING_SCALE) { | |
101 | if (bitlen < 32) | |
102 | goto fail; | |
103 | ||
104 | xing->scale = mad_bit_read(&ptr, 32); | |
105 | bitlen -= 32; | |
106 | } | |
107 | ||
108 | return 1; | |
109 | ||
110 | fail: | |
111 | xing->flags = 0; | |
112 | return 0; | |
113 | } | |
114 | ||
115 | /* Following two functions are adapted from mad_timer, from the | |
116 | libmad distribution */ | |
117 | void scan_mp3(void const *ptr, ssize_t len, buffer *buf) | |
118 | { | |
119 | struct mad_stream stream; | |
120 | struct mad_header header; | |
121 | struct xing xing; | |
122 | ||
123 | unsigned long bitrate = 0; | |
124 | int has_xing = 0; | |
125 | int is_vbr = 0; | |
126 | ||
127 | memset(&xing, 0, sizeof xing); | |
128 | ||
129 | mad_stream_init(&stream); | |
130 | mad_header_init(&header); | |
131 | ||
132 | mad_stream_buffer(&stream, ptr, len); | |
133 | ||
134 | buf->num_frames = 0; | |
135 | ||
136 | /* There are three ways of calculating the length of an mp3: | |
137 | 1) Constant bitrate: One frame can provide the information | |
138 | needed: # of frames and duration. Just see how long it | |
139 | is and do the division. | |
140 | 2) Variable bitrate: Xing tag. It provides the number of | |
141 | frames. Each frame has the same number of samples, so | |
142 | just use that. | |
143 | 3) All: Count up the frames and duration of each frames | |
144 | by decoding each one. We do this if we've no other | |
145 | choice, i.e. if it's a VBR file with no Xing tag. | |
146 | */ | |
147 | ||
148 | while (1) | |
149 | { | |
150 | if (mad_header_decode(&header, &stream) == -1) | |
151 | { | |
152 | if (MAD_RECOVERABLE(stream.error)) | |
153 | continue; | |
154 | else | |
155 | break; | |
156 | } | |
157 | ||
158 | /* Limit xing testing to the first frame header */ | |
159 | if (!buf->num_frames++) | |
160 | { | |
161 | if(parse_xing(&xing, stream.anc_ptr, stream.anc_bitlen)) | |
162 | { | |
163 | is_vbr = 1; | |
164 | ||
165 | if (xing.flags & XING_FRAMES) | |
166 | { | |
167 | /* We use the Xing tag only for frames. If it doesn't have that | |
168 | information, it's useless to us and we have to treat it as a | |
169 | normal VBR file */ | |
170 | has_xing = 1; | |
171 | buf->num_frames = xing.frames; | |
172 | break; | |
173 | } | |
174 | } | |
175 | } | |
176 | ||
177 | /* Test the first n frames to see if this is a VBR file */ | |
178 | if (!is_vbr && !(buf->num_frames > 20)) | |
179 | { | |
180 | if (bitrate && header.bitrate != bitrate) | |
181 | { | |
182 | is_vbr = 1; | |
183 | } | |
184 | ||
185 | else | |
186 | { | |
187 | bitrate = header.bitrate; | |
188 | } | |
189 | } | |
190 | ||
191 | /* We have to assume it's not a VBR file if it hasn't already been | |
192 | marked as one and we've checked n frames for different bitrates */ | |
193 | else if (!is_vbr) | |
194 | { | |
195 | break; | |
196 | } | |
197 | ||
198 | mad_timer_add(&buf->duration, header.duration); | |
199 | } | |
200 | ||
201 | if (!is_vbr) | |
202 | { | |
203 | double time = (len * 8.0) / (header.bitrate); /* time in seconds */ | |
204 | double timefrac = (double)time - ((long)(time)); | |
205 | long nsamples = 32 * MAD_NSBSAMPLES(&header); /* samples per frame */ | |
206 | ||
207 | /* samplerate is a constant */ | |
208 | buf->num_frames = (long) (time * header.samplerate / nsamples); | |
209 | ||
210 | mad_timer_set(&buf->duration, (long)time, (long)(timefrac*100), 100); | |
211 | } | |
212 | ||
213 | else if (has_xing) | |
214 | { | |
215 | /* modify header.duration since we don't need it anymore */ | |
216 | mad_timer_multiply(&header.duration, buf->num_frames); | |
217 | buf->duration = header.duration; | |
218 | } | |
219 | ||
220 | else | |
221 | { | |
222 | /* the durations have been added up, and the number of frames | |
223 | counted. We do nothing here. */ | |
224 | } | |
225 | ||
226 | mad_header_finish(&header); | |
227 | mad_stream_finish(&stream); | |
228 | } | |
229 | ||
230 | /* | |
231 | Local Variables: | |
232 | c-basic-offset:2 | |
233 | comment-column:40 | |
234 | End: | |
235 | */ |