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