1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/* 2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Copyright 2012 Sebastian Annies, 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 Zhupackage com.coremedia.iso; 17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.Box; 19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.ContainerBox; 20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.UserBox; 21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.IOException; 23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer; 24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.FileChannel; 25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.ReadableByteChannel; 26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.logging.Logger; 27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport static com.googlecode.mp4parser.util.CastUtils.l2i; 29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/** 31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * This BoxParser handles the basic stuff like reading size and extracting box type. 32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic abstract class AbstractBoxParser implements BoxParser { 34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private static Logger LOG = Logger.getLogger(AbstractBoxParser.class.getName()); 36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public abstract Box createBox(String type, byte[] userType, String parent); 38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Parses the next size and type, creates a box instance and parses the box's content. 41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param byteChannel the FileChannel pointing to the ISO file 43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param parent the current box's parent (null if no parent) 44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return the box just parsed 45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @throws java.io.IOException if reading from <code>in</code> fails 46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public Box parseBox(ReadableByteChannel byteChannel, ContainerBox parent) throws IOException { 48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer header = ChannelHelper.readFully(byteChannel, 8); 51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long size = IsoTypeReader.readUInt32(header); 53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // do plausibility check 54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (size < 8 && size > 1) { 55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.severe("Plausibility check failed: size < 8 (size = " + size + "). Stop parsing!"); 56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return null; 57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu String type = IsoTypeReader.read4cc(header); 61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byte[] usertype = null; 62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long contentSize; 63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (size == 1) { 65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer bb = ByteBuffer.allocate(8); 66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byteChannel.read(bb); 67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.rewind(); 68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size = IsoTypeReader.readUInt64(bb); 69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu contentSize = size - 16; 70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else if (size == 0) { 71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (byteChannel instanceof FileChannel) { 72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size = ((FileChannel) byteChannel).size() - ((FileChannel) byteChannel).position() - 8; 73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu throw new RuntimeException("Only FileChannel inputs may use size == 0 (box reaches to the end of file)"); 75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu contentSize = size - 8; 77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu contentSize = size - 8; 79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (UserBox.TYPE.equals(type)) { 81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer bb = ByteBuffer.allocate(16); 82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byteChannel.read(bb); 83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.rewind(); 84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu usertype = bb.array(); 85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu contentSize -= 16; 86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Box box = createBox(type, usertype, parent.getType()); 88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu box.setParent(parent); 89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.finest("Parsing " + box.getType()); 90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // System.out.println("parsing " + Arrays.toString(box.getType()) + " " + box.getClass().getName() + " size=" + size); 91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (l2i(size - contentSize) == 8) { 94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // default - no large box - no uuid 95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // do nothing header's already correct 96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.rewind(); 97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else if (l2i(size - contentSize) == 16) { 98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header = ByteBuffer.allocate(16); 99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(header, 1); 100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.put(IsoFile.fourCCtoBytes(type)); 101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt64(header, size); 102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else if (l2i(size - contentSize) == 24) { 103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header = ByteBuffer.allocate(24); 104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(header, size); 105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.put(IsoFile.fourCCtoBytes(type)); 106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.put(usertype); 107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else if (l2i(size - contentSize) == 32) { 108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header = ByteBuffer.allocate(32); 109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(header, size); 110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.put(IsoFile.fourCCtoBytes(type)); 111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt64(header, size); 112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu header.put(usertype); 113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu throw new RuntimeException("I didn't expect that"); 115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu box.parse(byteChannel, header, contentSize, this); 119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // System.out.println("box = " + box); 120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert size == box.getSize() : 123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu "Reconstructed Size is not x to the number of parsed bytes! (" + 124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu box.getType() + ")" 125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu + " Actual Box size: " + size + " Calculated size: " + box.getSize(); 126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return box; 127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu} 131