1 /* 2 * Copyright 2012 Sebastian Annies, Hamburg 3 * 4 * Licensed under the Apache License, Version 2.0 (the License); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an AS IS BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.coremedia.iso; 17 18 import com.coremedia.iso.boxes.Box; 19 import com.coremedia.iso.boxes.ContainerBox; 20 import com.coremedia.iso.boxes.UserBox; 21 22 import java.io.IOException; 23 import java.nio.ByteBuffer; 24 import java.nio.channels.FileChannel; 25 import java.nio.channels.ReadableByteChannel; 26 import java.util.logging.Logger; 27 28 import static com.googlecode.mp4parser.util.CastUtils.l2i; 29 30 /** 31 * This BoxParser handles the basic stuff like reading size and extracting box type. 32 */ 33 public abstract class AbstractBoxParser implements BoxParser { 34 35 private static Logger LOG = Logger.getLogger(AbstractBoxParser.class.getName()); 36 createBox(String type, byte[] userType, String parent)37 public abstract Box createBox(String type, byte[] userType, String parent); 38 39 /** 40 * Parses the next size and type, creates a box instance and parses the box's content. 41 * 42 * @param byteChannel the FileChannel pointing to the ISO file 43 * @param parent the current box's parent (null if no parent) 44 * @return the box just parsed 45 * @throws java.io.IOException if reading from <code>in</code> fails 46 */ parseBox(ReadableByteChannel byteChannel, ContainerBox parent)47 public Box parseBox(ReadableByteChannel byteChannel, ContainerBox parent) throws IOException { 48 49 50 ByteBuffer header = ChannelHelper.readFully(byteChannel, 8); 51 52 long size = IsoTypeReader.readUInt32(header); 53 // do plausibility check 54 if (size < 8 && size > 1) { 55 LOG.severe("Plausibility check failed: size < 8 (size = " + size + "). Stop parsing!"); 56 return null; 57 } 58 59 60 String type = IsoTypeReader.read4cc(header); 61 byte[] usertype = null; 62 long contentSize; 63 64 if (size == 1) { 65 ByteBuffer bb = ByteBuffer.allocate(8); 66 byteChannel.read(bb); 67 bb.rewind(); 68 size = IsoTypeReader.readUInt64(bb); 69 contentSize = size - 16; 70 } else if (size == 0) { 71 if (byteChannel instanceof FileChannel) { 72 size = ((FileChannel) byteChannel).size() - ((FileChannel) byteChannel).position() - 8; 73 } else { 74 throw new RuntimeException("Only FileChannel inputs may use size == 0 (box reaches to the end of file)"); 75 } 76 contentSize = size - 8; 77 } else { 78 contentSize = size - 8; 79 } 80 if (UserBox.TYPE.equals(type)) { 81 ByteBuffer bb = ByteBuffer.allocate(16); 82 byteChannel.read(bb); 83 bb.rewind(); 84 usertype = bb.array(); 85 contentSize -= 16; 86 } 87 Box box = createBox(type, usertype, parent.getType()); 88 box.setParent(parent); 89 LOG.finest("Parsing " + box.getType()); 90 // System.out.println("parsing " + Arrays.toString(box.getType()) + " " + box.getClass().getName() + " size=" + size); 91 92 93 if (l2i(size - contentSize) == 8) { 94 // default - no large box - no uuid 95 // do nothing header's already correct 96 header.rewind(); 97 } else if (l2i(size - contentSize) == 16) { 98 header = ByteBuffer.allocate(16); 99 IsoTypeWriter.writeUInt32(header, 1); 100 header.put(IsoFile.fourCCtoBytes(type)); 101 IsoTypeWriter.writeUInt64(header, size); 102 } else if (l2i(size - contentSize) == 24) { 103 header = ByteBuffer.allocate(24); 104 IsoTypeWriter.writeUInt32(header, size); 105 header.put(IsoFile.fourCCtoBytes(type)); 106 header.put(usertype); 107 } else if (l2i(size - contentSize) == 32) { 108 header = ByteBuffer.allocate(32); 109 IsoTypeWriter.writeUInt32(header, size); 110 header.put(IsoFile.fourCCtoBytes(type)); 111 IsoTypeWriter.writeUInt64(header, size); 112 header.put(usertype); 113 } else { 114 throw new RuntimeException("I didn't expect that"); 115 } 116 117 118 box.parse(byteChannel, header, contentSize, this); 119 // System.out.println("box = " + box); 120 121 122 assert size == box.getSize() : 123 "Reconstructed Size is not x to the number of parsed bytes! (" + 124 box.getType() + ")" 125 + " Actual Box size: " + size + " Calculated size: " + box.getSize(); 126 return box; 127 } 128 129 130 } 131