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 226 227 228 229 230 231 232 233 234
|
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Use Safefree for libid3tag free calls on Windows
#ifdef _MSC_VER
#define free(ptr) Safefree(ptr)
#endif
#define MP3_BLOCK_SIZE 4096
#define XING_FRAMES 0x01
#define XING_BYTES 0x02
#define XING_TOC 0x04
#define XING_QUALITY 0x08
#define CBR 1
#define ABR 2
#define VBR 3
#define ILLEGAL_MPEG_ID 1
#define MPEG1_ID 3
#define MPEG2_ID 2
#define MPEG25_ID 0
#define ILLEGAL_LAYER_ID 0
#define LAYER1_ID 3
#define LAYER2_ID 2
#define LAYER3_ID 1
#define ILLEGAL_SR 3
#define MODE_MONO 3
// Based on pcutmp3 FrameHeader
typedef struct mp3frame {
int header32;
int mpegID;
int layerID;
bool crc16_used;
int bitrate_index;
int samplingrate_index;
bool padding;
bool private_bit_set;
int mode;
int mode_extension;
bool copyrighted;
bool original;
int emphasis;
bool valid;
int samplerate;
int channels;
int bitrate_kbps;
int samples_per_frame;
int bytes_per_slot;
int frame_size;
} mp3frame;
// based on pcutmp3 XingInfoLameTagFrame
typedef struct xingframe {
int frame_size;
bool xing_tag;
bool info_tag;
int flags;
int xing_frames;
int xing_bytes;
bool has_toc;
uint8_t xing_toc[100];
int xing_quality;
bool lame_tag;
char lame_encoder_version[9];
uint8_t lame_tag_revision;
uint8_t lame_vbr_method;
int lame_lowpass;
float lame_replay_gain[2];
uint16_t lame_abr_rate;
int lame_encoder_delay;
int lame_encoder_padding;
uint8_t lame_noise_shaping;
uint8_t lame_stereo_mode;
uint8_t lame_unwise;
uint8_t lame_source_freq;
int lame_mp3gain;
float lame_mp3gain_db;
uint8_t lame_surround;
uint16_t lame_preset;
int lame_music_length;
bool vbri_tag;
uint16_t vbri_delay;
uint16_t vbri_quality;
uint32_t vbri_bytes;
uint32_t vbri_frames;
int lame_tag_ofs;
} xingframe;
typedef struct mp3info {
PerlIO *infile;
char *file;
Buffer *buf;
HV *info;
off_t file_size;
uint32_t id3_size;
off_t audio_offset;
off_t audio_size;
uint16_t bitrate;
uint32_t song_length_ms;
uint8_t vbr;
int music_frame_count;
int samples_per_frame;
mp3frame *first_frame;
xingframe *xing_frame;
} mp3info;
// LAME lookup tables
const char *stereo_modes[] = {
"Mono",
"Stereo",
"Dual",
"Joint",
"Force",
"Auto",
"Intensity",
"Undefined"
};
const char *source_freqs[] = {
"<= 32 kHz",
"44.1 kHz",
"48 kHz",
"> 48 kHz"
};
const char *surround[] = {
"None",
"DPL encoding",
"DPL2 encoding",
"Ambisonic encoding",
"Reserved"
};
const char *vbr_methods[] = {
"Unknown",
"Constant Bitrate",
"Average Bitrate",
"Variable Bitrate method1 (old/rh)",
"Variable Bitrate method2 (mtrh)",
"Variable Bitrate method3 (mt)",
"Variable Bitrate method4",
NULL,
"Constant Bitrate (2 pass)",
"Average Bitrate (2 pass)",
NULL,
NULL,
NULL,
NULL,
NULL,
"Reserved"
};
const char *presets_v[] = {
"V9",
"V8",
"V7",
"V6",
"V5",
"V4",
"V3",
"V2",
"V1",
"V0"
};
const char *presets_old[] = {
"r3mix",
"standard",
"extreme",
"insane",
"standard/fast",
"extreme/fast",
"medium",
"medium/fast"
};
static int bitrate_map[4][4][16] = {
{ { 0 }, //MPEG2.5
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }
},
{ { 0 } },
{ { 0 }, // MPEG2
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }
},
{ { 0 }, // MPEG1
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 },
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }
}
};
// sample_rate[samplingrate_index]
static int sample_rate_tbl[ ] = {
44100, 48000, 32000, 0,
};
int get_mp3tags(PerlIO *infile, char *file, HV *info, HV *tags);
int get_mp3fileinfo(PerlIO *infile, char *file, HV *info);
int mp3_find_frame(PerlIO *infile, char *file, int offset);
mp3info * _mp3_parse(PerlIO *infile, char *file, HV *info);
int _decode_mp3_frame(unsigned char *bptr, struct mp3frame *frame);
int _is_ape_header(char *bptr);
int _has_ape(PerlIO *infile, off_t file_size, HV *info);
void _mp3_skip(mp3info *mp3, uint32_t size);
|