1 16 package org.apache.cocoon.generation; 17 18 import org.xml.sax.SAXException ; 19 20 import java.io.File ; 21 import java.io.IOException ; 22 import java.io.RandomAccessFile ; 23 24 39 public class MP3DirectoryGenerator extends DirectoryGenerator 40 { 41 private static final int VERSION_MPEG1 = 3; 43 private static final int MODE_DUAL_CHANNEL = 2; 45 private static final int MODE_JOINT_STEREO = 1; 46 private static final int MODE_SINGLE_CHANNEL = 3; 47 private static final int MODE_STEREO = 0; 48 private static final int VBR_FRAMES_FLAG = 1; 49 53 protected final static String MP3_FREQUENCY_ATTR_NAME = "frequency"; 55 protected final static String MP3_BITRATE_ATTR_NAME = "bitrate"; 56 protected final static String MP3_MODE_ATTR_NAME = "mode"; 57 protected final static String MP3_VBR_ATTR_NAME = "variable-rate"; 58 59 protected final static String MP3_TITLE_ATTR_NAME = "title"; 60 protected final static String MP3_ARTIST_ATTR_NAME = "artist"; 61 protected final static String MP3_ALBUM_ATTR_NAME = "album"; 62 protected final static String MP3_YEAR_ATTR_NAME = "year"; 63 protected final static String MP3_COMMENT_ATTR_NAME = "comment"; 64 protected final static String MP3_TRACK_ATTR_NAME = "track"; 65 protected final static String MP3_GENRE_ATTR_NAME = "genre"; 66 67 72 protected void setNodeAttributes(File path) throws SAXException { 73 super.setNodeAttributes(path); 74 if (path.isDirectory()) { 75 return; 76 } 77 78 RandomAccessFile in = null; 79 try { 80 in = new RandomAccessFile (path, "r"); 81 setID3HeaderAttributes(in); 82 setID3TagAttributes(in); 83 } catch (IOException e) { 84 getLogger().debug("Could not set attributes for " + path, e); 85 } finally { 86 if(in != null) try{ in.close(); }catch(IOException ignored){} 87 } 88 } 89 90 93 private void setID3TagAttributes(RandomAccessFile in) throws IOException { 94 String s; 95 96 if (in.length() < 128) return; 98 in.seek(in.length() - 128); 99 byte [] buf = new byte[128]; 100 if (in.read(buf,0, 128) != 128) return; 102 if(buf[0] != 'T' || buf[1] != 'A' || buf[2] != 'G') return; 104 105 s = getID3TagValue(buf, 3, 30); 106 if(s.length() > 0) 107 attributes.addAttribute("", MP3_TITLE_ATTR_NAME, MP3_TITLE_ATTR_NAME, "CDATA", s); 108 s = getID3TagValue(buf, 33,30); 109 if(s.length() > 0) 110 attributes.addAttribute("", MP3_ARTIST_ATTR_NAME, MP3_ARTIST_ATTR_NAME, "CDATA", s); 111 s = getID3TagValue(buf, 63,30); 112 if(s.length() > 0) 113 attributes.addAttribute("", MP3_ALBUM_ATTR_NAME, MP3_ALBUM_ATTR_NAME, "CDATA", s); 114 s = getID3TagValue(buf, 93, 4); 115 if(s.length() > 0) 116 attributes.addAttribute("", MP3_YEAR_ATTR_NAME, MP3_YEAR_ATTR_NAME, "CDATA", s); 117 s = getID3TagValue(buf, 97,29); 118 if(s.length() > 0) 119 attributes.addAttribute("", MP3_COMMENT_ATTR_NAME, MP3_COMMENT_ATTR_NAME, "CDATA", s); 120 if(buf[126] > 0) 121 attributes.addAttribute("", MP3_TRACK_ATTR_NAME, MP3_TRACK_ATTR_NAME, "CDATA", 122 Byte.toString(buf[126])); 123 if(buf[127] > 0) 124 attributes.addAttribute("", MP3_GENRE_ATTR_NAME, MP3_GENRE_ATTR_NAME, "CDATA", 125 Byte.toString(buf[127])); 126 } 127 128 private String getID3TagValue(byte[] buf, int offset, int length) { 129 String s = new String (buf, offset, length); 130 int index = s.indexOf(0x00); 131 if (index != -1) { 132 s = s.substring(0, index); 133 } 134 return s.trim(); 135 } 136 137 private void setID3HeaderAttributes(RandomAccessFile in) throws IOException { 138 byte[] buffer = new byte[4]; 139 140 if (in.read(buffer, 0, 3) != 3) { 142 return; 143 } 144 int header = ((buffer[0] << 16) & 0x00FF0000) | ((buffer[1] << 8) & 0x0000FF00) | ((buffer[2] << 0) & 0x000000FF); 145 do { 146 header <<= 8; 147 if (in.read(buffer, 3, 1) != 1) { 148 return; 149 } 150 header |= (buffer[3] & 0x000000FF); 151 } while (!isSyncMark(header)); 152 153 int version = (header >>> 19) & 3; 154 int layer = 4 - (header >>> 17) & 3; 155 int bitrate = (header >>> 12) & 0xF; 157 int frequency = (header >>> 10) & 3; 158 if (frequency == 3) { 160 return; 161 } 162 int mode = ((header >>> 6) & 3); 164 165 attributes.addAttribute("", MP3_FREQUENCY_ATTR_NAME, MP3_FREQUENCY_ATTR_NAME, "CDATA", 166 frequencyString(version, frequency)); 167 attributes.addAttribute("", MP3_MODE_ATTR_NAME, MP3_MODE_ATTR_NAME, "CDATA", 168 mode(mode)); 169 170 int frames = getVBRHeaderFrames(in, version, mode); 171 if (frames != -1) { 172 float medFrameSize = (float)in.length() / frames; 174 bitrate = (int)(medFrameSize * frequency(version, frequency) / 144000.0); 176 attributes.addAttribute("", MP3_BITRATE_ATTR_NAME, MP3_BITRATE_ATTR_NAME, "CDATA", 177 Integer.toString(bitrate)); 178 } else { 179 attributes.addAttribute("", MP3_BITRATE_ATTR_NAME, MP3_BITRATE_ATTR_NAME, "CDATA", 180 bitrate(version, layer, bitrate)); 181 } 182 } 183 184 private static boolean isSyncMark(int header) { 185 boolean sync = ((header & 0xFFF00000) == 0xFFF00000); 186 if (sync) sync = ((header >>> 10) & 3) != 3; 188 if (sync) sync = ((header >>> 17) & 3) != 0; 190 if (sync) sync = ((header >>> 19) & 3) != 1; 192 return sync; 193 } 194 195 private int getVBRHeaderFrames(RandomAccessFile in, int version, int mode) throws IOException { 196 byte[] buffer = new byte[12]; 197 198 int skip; 200 if (version == VERSION_MPEG1) { 201 if (mode == MODE_SINGLE_CHANNEL) skip = 17; 202 else skip = 32; 203 } else { if (mode == MODE_SINGLE_CHANNEL) skip = 9; 205 else skip = 17; 206 } 207 while (skip > 0) { 208 if (in.read() == -1) return -1; 209 skip --; 210 } 211 212 if (in.read(buffer, 0, 12) != 12) { 213 return -1; 214 } 215 if (buffer[0] != 'X' || buffer[1] != 'i' || buffer[2] != 'n' || buffer[3] != 'g'){ 216 return -1; 217 } 218 219 attributes.addAttribute("", MP3_VBR_ATTR_NAME, MP3_VBR_ATTR_NAME, "CDATA", 220 "yes"); 221 222 int flags = 223 ((buffer[4] & 0xFF) << 24) | 224 ((buffer[5] & 0xFF) << 16) | 225 ((buffer[6] & 0xFF) << 8) | 226 (buffer[7] & 0xFF); 227 228 if ((flags & VBR_FRAMES_FLAG) == VBR_FRAMES_FLAG){ 229 int frames = 230 ((buffer[ 8] & 0xFF) << 24) | 231 ((buffer[ 9] & 0xFF) << 16) | 232 ((buffer[10] & 0xFF) << 8) | 233 (buffer[11] & 0xFF); 234 return frames; 235 } else { 236 return -1; 237 } 238 } 239 240 private static final String bitrates[][][] = { 242 { 243 {"free format", "32", "48", "56", "64", "80", "96", "112", "128", "144", "160", "176", "192", "224", "256", "forbidden"}, 245 {"free format", "8", "16", "24", "32", "40", "48", "56", "64", "80", "96", "112", "128", "144", "160", "forbidden"}, 247 {"free format", "8", "16", "24", "32", "40", "48", "56", "64", "80", "96", "112", "128", "144", "160", "forbidden"} 249 }, 250 { 251 {"free format", "32", "64", "96", "128", "160", "192", "224", "256", "288", "320", "352", "384", "416", "448", "forbidden"}, 253 {"free format", "32", "48", "56", "64", "80", "96", "112", "128", "160", "192", "224", "256", "320", "384", "forbidden"}, 255 {"free format", "32", "40", "48", "56", "64", "80" , "96", "112", "128", "160", "192", "224", "256", "320", "forbidden"} 257 } 258 }; 259 260 private static String bitrate(int version, int layer, int bitrate_index) { 261 return bitrates[version & 1][layer - 1][bitrate_index]; 262 } 263 264 private static String mode(int mode) { 265 switch(mode) 266 { 267 case MODE_STEREO: 268 return "Stereo"; 269 case MODE_JOINT_STEREO: 270 return "Joint stereo"; 271 case MODE_DUAL_CHANNEL: 272 return "Dual channel"; 273 case MODE_SINGLE_CHANNEL: 274 return "Single channel"; 275 } 276 return null; 277 } 278 279 private static final int frequencies[][] = { 280 {32000, 16000, 8000}, { 0, 0, 0}, {22050, 24000, 16000}, {44100, 48000, 32000} }; 285 286 private static int frequency(int version, int frequency) { 287 return frequencies[version][frequency]; 288 } 289 290 private static String frequencyString(int version, int frequency) { 291 return String.valueOf((float)frequency(version, frequency)/1000); 292 } 293 } 294 | Popular Tags |