chiark / gitweb /
Missing gcry_md_close.
[disorder] / plugins / mad.c
CommitLineData
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
46struct xing {
47 int flags;
48 unsigned long frames;
49 unsigned long bytes;
50 unsigned char toc[100];
51 long scale;
52};
53
54enum {
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
63static
64int 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 */
117void 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/*
231Local Variables:
232c-basic-offset:2
233comment-column:40
234End:
235*/