1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/* 2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Copyright 2008 CoreMedia AG, Hamburg 3dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 4dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Licensed under the Apache License, Version 2.0 (the License); 5dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * you may not use this file except in compliance with the License. 6dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * You may obtain a copy of the License at 7dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 8dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * http://www.apache.org/licenses/LICENSE-2.0 9dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 10dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Unless required by applicable law or agreed to in writing, software 11dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * distributed under the License is distributed on an AS IS BASIS, 12dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * See the License for the specific language governing permissions and 14dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * limitations under the License. 15dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 16dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupackage com.coremedia.iso; 18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.AbstractContainerBox; 20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.Box; 21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.MovieBox; 22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.annotations.DoNotParseDetail; 23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.*; 25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer; 26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.FileChannel; 27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.ReadableByteChannel; 28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.WritableByteChannel; 29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/** 31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * The most upper container for ISO Boxes. It is a container box that is a file. 32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Uses IsoBufferWrapper to access the underlying file. 33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu@DoNotParseDetail 35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic class IsoFile extends AbstractContainerBox implements Closeable { 36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected BoxParser boxParser = new PropertyBoxParserImpl(); 37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ReadableByteChannel byteChannel; 38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public IsoFile() { 40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu super(""); 41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public IsoFile(File f) throws IOException { 44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu super(""); 45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.byteChannel = new FileInputStream(f).getChannel(); 46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu boxParser = createBoxParser(); 47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu parse(); 48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public IsoFile(ReadableByteChannel byteChannel) throws IOException { 51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu super(""); 52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.byteChannel = byteChannel; 53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu boxParser = createBoxParser(); 54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu parse(); 55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public IsoFile(ReadableByteChannel byteChannel, BoxParser boxParser) throws IOException { 58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu super(""); 59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.byteChannel = byteChannel; 60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.boxParser = boxParser; 61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu parse(); 62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected BoxParser createBoxParser() { 67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return new PropertyBoxParserImpl(); 68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @Override 72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void _parseDetails(ByteBuffer content) { 73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // there are no details to parse we should be just file 74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void parse(ReadableByteChannel inFC, ByteBuffer header, long contentSize, AbstractBoxParser abstractBoxParser) throws IOException { 77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu throw new IOException("This method is not meant to be called. Use #parse() directly."); 78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private void parse() throws IOException { 81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu boolean done = false; 83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu while (!done) { 84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu try { 85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Box box = boxParser.parseBox(byteChannel, this); 86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (box != null) { 87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // System.err.println(box.getType()); 88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu boxes.add(box); 89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu done = true; 91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } catch (EOFException e) { 93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu done = true; 94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public String toString() { 100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu StringBuilder buffer = new StringBuilder(); 101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu buffer.append("IsoFile["); 102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (boxes == null) { 103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu buffer.append("unparsed"); 104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < boxes.size(); i++) { 106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (i > 0) { 107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu buffer.append(";"); 108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu buffer.append(boxes.get(i).toString()); 110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu buffer.append("]"); 113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return buffer.toString(); 114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public static byte[] fourCCtoBytes(String fourCC) { 118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byte[] result = new byte[4]; 119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (fourCC != null) { 120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = 0; i < Math.min(4, fourCC.length()); i++) { 121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu result[i] = (byte) fourCC.charAt(i); 122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return result; 125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public static String bytesToFourCC(byte[] type) { 129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byte[] result = new byte[]{0, 0, 0, 0}; 130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (type != null) { 131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu System.arraycopy(type, 0, result, 0, Math.min(type.length, 4)); 132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu try { 134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return new String(result, "ISO-8859-1"); 135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } catch (UnsupportedEncodingException e) { 136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu throw new Error("Required character encoding is missing", e); 137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @Override 142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public long getNumOfBytesToFirstChild() { 143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return 0; 144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @Override 147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public long getSize() { 148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long size = 0; 149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Box box : boxes) { 150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size += box.getSize(); 151dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 152dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return size; 153dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 154dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 155dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @Override 156dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public IsoFile getIsoFile() { 157dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return this; 158dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 159dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 160dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 161dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 162dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Shortcut to get the MovieBox since it is often needed and present in 163dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * nearly all ISO 14496 files (at least if they are derived from MP4 ). 164dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 165dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return the MovieBox or <code>null</code> 166dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 167dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 168dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public MovieBox getMovieBox() { 169dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Box box : boxes) { 170dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (box instanceof MovieBox) { 171dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return (MovieBox) box; 172dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 173dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 174dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return null; 175dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 176dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 177dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void getBox(WritableByteChannel os) throws IOException { 178dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Box box : boxes) { 179dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 180dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (os instanceof FileChannel) { 181dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long startPos = ((FileChannel) os).position(); 182dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu box.getBox(os); 183dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long size = ((FileChannel) os).position() - startPos; 184dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert size == box.getSize(); 185dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 186dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu box.getBox(os); 187dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 188dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 189dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 190dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 191dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 192dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void close() throws IOException { 193dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.byteChannel.close(); 194dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 195dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu} 196