1 /*
2 * madplay - MPEG audio decoder and player
3 * Copyright (C) 2000-2004 Robert Leslie
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * $Id: madtime.c,v 1.25 2004/01/23 09:41:32 rob Exp $
20 */
21
22 # ifdef HAVE_CONFIG_H
23 # include "config.h"
24 # endif
25
26 # include "global.h"
27
28 # if !defined(HAVE_MMAP)
29 # error "madtime currently requires mmap() support"
30 # endif
31
32 # include <stdio.h>
33 # include <stdlib.h>
34
35 # ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 # endif
38
39 # include <sys/stat.h>
40
41 # ifdef HAVE_FCNTL_H
42 # include <fcntl.h>
43 # endif
44
45 # include <unistd.h>
46 # include <string.h>
47 # include <sys/mman.h>
48 # include <locale.h>
49 # include <mad.h>
50
51 # include "getopt.h"
52 # include "gettext.h"
53
54 # if !defined(O_BINARY)
55 # define O_BINARY 0
56 # endif
57
58 static
scan(unsigned char const * ptr,unsigned long len,mad_timer_t * duration)59 signed int scan(unsigned char const *ptr, unsigned long len,
60 mad_timer_t *duration)
61 {
62 struct mad_stream stream;
63 struct mad_header header;
64 unsigned long bitrate, kbps, count;
65 int vbr;
66
67 mad_stream_init(&stream);
68 mad_header_init(&header);
69
70 mad_stream_buffer(&stream, ptr, len);
71
72 bitrate = kbps = count = vbr = 0;
73
74 while (1) {
75 if (mad_header_decode(&header, &stream) == -1) {
76 if (MAD_RECOVERABLE(stream.error))
77 continue;
78 else
79 break;
80 }
81
82 if (bitrate && header.bitrate != bitrate)
83 vbr = 1;
84
85 bitrate = header.bitrate;
86
87 kbps += bitrate / 1000;
88 ++count;
89
90 mad_timer_add(duration, header.duration);
91 }
92
93 mad_header_finish(&header);
94 mad_stream_finish(&stream);
95
96 if (count == 0)
97 count = 1;
98
99 return ((kbps * 2) / count + 1) / 2 * (vbr ? -1 : 1);
100 }
101
102 static
calc(char const * path,mad_timer_t * duration,signed int * kbps,unsigned long * kbytes)103 int calc(char const *path, mad_timer_t *duration,
104 signed int *kbps, unsigned long *kbytes)
105 {
106 int fd;
107 struct stat stat;
108 void *fdm;
109
110 fd = open(path, O_RDONLY | O_BINARY);
111 if (fd == -1) {
112 perror(path);
113 return -1;
114 }
115
116 if (fstat(fd, &stat) == -1) {
117 perror("fstat");
118 close(fd);
119 return -1;
120 }
121
122 if (!S_ISREG(stat.st_mode)) {
123 fprintf(stderr, _("%s: Not a regular file\n"), path);
124 close(fd);
125 return -1;
126 }
127
128 *kbytes = (stat.st_size + 512) / 1024;
129
130 fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
131 if (fdm == MAP_FAILED) {
132 perror("mmap");
133 close(fd);
134 return -1;
135 }
136
137 if (fdm) {
138 *kbps = scan(fdm, stat.st_size, duration);
139
140 if (munmap(fdm, stat.st_size) == -1) {
141 perror("munmap");
142 close(fd);
143 return -1;
144 }
145 }
146 else
147 *kbps = 0;
148
149 if (close(fd) == -1) {
150 perror("close");
151 return -1;
152 }
153
154 return 0;
155 }
156
157 static
show(mad_timer_t duration,signed int kbps,unsigned long kbytes,char const * label)158 void show(mad_timer_t duration, signed int kbps,
159 unsigned long kbytes, char const *label)
160 {
161 char duration_str[19];
162
163 mad_timer_string(duration, duration_str,
164 "%4lu:%02u:%02u.%1u", MAD_UNITS_HOURS,
165 MAD_UNITS_DECISECONDS, 0);
166
167 # if defined(HAVE_LOCALECONV)
168 {
169 char *point;
170
171 point = strchr(duration_str, '.');
172 if (point)
173 *point = *localeconv()->decimal_point;
174 }
175 # endif
176
177 printf(_("%8.1f MB %c%3u kbps %s %s\n"), kbytes / 1024.0,
178 kbps < 0 ? '~' : ' ', abs(kbps), duration_str, label);
179 }
180
181 static
usage(char const * argv0)182 void usage(char const *argv0)
183 {
184 fprintf(stderr, _("Usage: %s [-s] FILE [...]\n"), argv0);
185 }
186
187 /*
188 * NAME: main()
189 * DESCRIPTION: program entry point
190 */
main(int argc,char * argv[])191 int main(int argc, char *argv[])
192 {
193 mad_timer_t total;
194 unsigned long total_kbps, total_kbytes, count;
195 signed int bitrate;
196 int vbr, opt, i, sum_only = 0;
197
198 /* internationalization support */
199
200 # if defined(ENABLE_NLS)
201 setlocale(LC_ALL, "");
202 bindtextdomain(PACKAGE, LOCALEDIR);
203 textdomain(PACKAGE);
204 # endif
205
206 /* initialize and get options */
207
208 if (argc > 1) {
209 if (strcmp(argv[1], "--version") == 0) {
210 printf("%s - %s\n", mad_version, mad_copyright);
211 printf(_("Build options: %s\n"), mad_build);
212 return 0;
213 }
214 if (strcmp(argv[1], "--help") == 0) {
215 usage(argv[0]);
216 return 0;
217 }
218 }
219
220 while ((opt = getopt(argc, argv, "s")) != -1) {
221 switch (opt) {
222 case 's':
223 sum_only = 1;
224 break;
225
226 default:
227 usage(argv[0]);
228 return 1;
229 }
230 }
231
232 if (optind == argc) {
233 usage(argv[0]);
234 return 1;
235 }
236
237 /* main processing */
238
239 total = mad_timer_zero;
240
241 total_kbps = total_kbytes = count = bitrate = vbr = 0;
242
243 for (i = optind; i < argc; ++i) {
244 mad_timer_t duration = mad_timer_zero;
245 signed int kbps;
246 unsigned long kbytes;
247
248 if (calc(argv[i], &duration, &kbps, &kbytes) == -1)
249 continue;
250
251 if (!sum_only)
252 show(duration, kbps, kbytes, argv[i]);
253
254 mad_timer_add(&total, duration);
255
256 total_kbytes += kbytes;
257
258 if (kbps) {
259 total_kbps += abs(kbps);
260 ++count;
261 }
262
263 if (kbps < 0 || (bitrate && kbps != bitrate))
264 vbr = 1;
265
266 bitrate = kbps;
267 }
268
269 if (count == 0)
270 count = 1;
271
272 if (argc > 2 || sum_only) {
273 show(total, ((total_kbps * 2) / count + 1) / 2 * (vbr ? -1 : 1),
274 total_kbytes, _("TOTAL"));
275 }
276
277 return 0;
278 }
279