1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
/**********************************************************************
PROGRAM NAME: mp3_check
VERSION: 1.97
AUTHOR: Eric Bullen <ericb@thedeepsky.com>
PURPOSE: Identify in explicit detail mp3s that do not correctly
follow the mp3 format. Also look for invalid frame
headers, missing frames, etc. This can be especially
important when building an archive, and you want
quality mp3s.
USAGE: mp3s are accepted either from stdin, or on the
command-line. Statistical data and summary information
is sent to stout, and any errors are sent to stderr.
More information is available by using the '-h' switch
on the commandline.
Common execution can be:
========================
cat some_song.mp3 | mp3_check -s - | mpg123
OR
mp3_check -a -v some_song.mp3
INTERESTING TEST
mp3_check -b100000 -vv /dev/urandom
REFERENCES: All original code. However the format of an mp3 file
was obtained from long-lost web sites and nntp articles.
RESTRICTIONS: This program has been released under the GNU GPL license.
REVISIONS: 27-Mar-00: Initial release v.1.0.
NOTES: One area that could use some improvement is in the
function:
check_header_value
The check_header_value could use some more error checking.
DOWNLOADING: The master ftp archive for new versions is:
ftp://ftp.thedeepsky.com/outgoing/
GOALS: Initially, making a higly accurate mp3 analysis tool is the
goal, however, building a solid framework for a command-line
mp3 player is a possibility. I wanted clean, readable code
so it is easily expandable to do a variety of things. With
readable code, more people can follow my logic, and find
improvements quicker and easier.
**********************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include "mp3_check.h"
// FUNCTION PROTOTYPES HAPPEN HERE
extern int parse_args(char **argv, meta_options *flag_options, command_flags *flags);
extern void print_usage(void);
extern void init_command_flags_struct(command_flags *flags);
extern void print_sys_usage(void);
int
main(argc, argv)
int argc;
char *argv[];
{
int ch;
int got_error = 0;
command_flags flags;
meta_options flag_options;
init_command_flags_struct(&flags);
while ((ch = getopt(argc, argv, "q:epv::ahs::ib::")) != -1)
switch (ch) {
case 'q':
// Determine a mininum number of
// contiguous frames that must be
// present for an error not to occur.
// Reason why is that mp3 headers are very
// easy to generate, and often this is
// the best way to see if it is actually
// an mp3 and not some random data.
// The 'q' is for se'q'uence.
// NOTE TO SELF: Why isn't the single ':' forcing
// an option to be there? Weird.
if (atoi(optarg) > 1) {
flag_options.min_frame_seq = atoi(optarg);
flags.qflag = TRUE;
} else {
(void)fprintf(stderr, "You must supply an integer greater than 1 to use the '-q' flag.");
return(FAIL - 1);
}
break;
case 'e':
// Record an invalid frame
// when an id3v2 tag is found.
flags.eflag = TRUE;
break;
case 'p':
// Single-line output only
// for easier parsing.
flags.pflag = TRUE;
break;
case 'v':
// Verbose
flags.vflag = TRUE;
// Be very verbose - every pice of cool
// info about each frame is shot to the screen
if (optarg && *optarg == 'v')
flags.vvflag = TRUE;
break;
case 'a':
// Check the whole mp3
flags.aflag = TRUE;
break;
case 's':
// Send mp3 to stdout
flags.sflag = TRUE;
// Be betty quiet. I do not want any
// output unless it is an error.
if (optarg && *optarg == 's')
flags.ssflag = TRUE;
if (optarg && *optarg == 'f') {
flags.fflag = TRUE;
//flags.sflag = FALSE;
}
break;
case 'i':
// Check for that pesky id3 tag. It is going
// to run a LOT slower with this on.
flags.iflag = TRUE;
break;
case 'b':
// Only scan the first # of bytes, then quit.
if (optarg)
flag_options.byte_limit = atoi(optarg);
flags.bflag = TRUE;
break;
case 'h':
// What? You need the help message?
print_usage();
break;
default:
print_usage();
break;
}
argv += optind;
//
// If there's no data after the flags, return an error.
//
if (*argv == NULL) {
print_usage();
}
//
// Required fields go here. Everything
// else not listed here are optional.
//
// The below 'if' statement seems a little silly,
// but it works. I will clean it up a little later.
//
if (!(flags.vflag || flags.aflag || flags.bflag))
flags.aflag = TRUE;
if (!flags.aflag)
flags.bflag = TRUE;
// parse_args is where the program begins.
// everything else stems from it.
if (!parse_args(argv, &flag_options, &flags))
got_error++;
if (!flags.sflag)
print_sys_usage();
//
// At least in bash, I have to return a '0' to indicate
// a success, while in C, a success is typically a '1'.
//
if (got_error > 0)
return(FAIL - 1);
else
return(PASS - 1);
} // MAIN
|