1 /* 2 * Copyright 2008 CoreMedia AG, 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 17 package com.coremedia.iso.boxes.sampleentry; 18 19 import com.coremedia.iso.BoxParser; 20 import com.coremedia.iso.IsoTypeReader; 21 import com.coremedia.iso.IsoTypeWriter; 22 import com.googlecode.mp4parser.AbstractBox; 23 import com.coremedia.iso.boxes.Box; 24 import com.coremedia.iso.boxes.ContainerBox; 25 import com.googlecode.mp4parser.util.ByteBufferByteChannel; 26 27 import java.io.ByteArrayOutputStream; 28 import java.io.IOException; 29 import java.nio.ByteBuffer; 30 import java.nio.channels.Channels; 31 import java.nio.channels.ReadableByteChannel; 32 import java.nio.channels.WritableByteChannel; 33 import java.util.ArrayList; 34 import java.util.LinkedList; 35 import java.util.List; 36 37 /** 38 * Abstract base class for all sample entries. 39 * 40 * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry 41 * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry 42 * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry 43 */ 44 public abstract class SampleEntry extends AbstractBox implements ContainerBox { 45 46 47 private int dataReferenceIndex = 1; 48 protected List<Box> boxes = new LinkedList<Box>(); 49 private BoxParser boxParser; 50 51 SampleEntry(String type)52 protected SampleEntry(String type) { 53 super(type); 54 } 55 setType(String type)56 public void setType(String type) { 57 this.type = type; 58 } 59 getDataReferenceIndex()60 public int getDataReferenceIndex() { 61 return dataReferenceIndex; 62 } 63 setDataReferenceIndex(int dataReferenceIndex)64 public void setDataReferenceIndex(int dataReferenceIndex) { 65 this.dataReferenceIndex = dataReferenceIndex; 66 } 67 setBoxes(List<Box> boxes)68 public void setBoxes(List<Box> boxes) { 69 this.boxes = new LinkedList<Box>(boxes); 70 } 71 addBox(Box b)72 public void addBox(Box b) { 73 b.setParent(this); 74 boxes.add(b); 75 } 76 removeBox(Box b)77 public boolean removeBox(Box b) { 78 b.setParent(this); 79 return boxes.remove(b); 80 } 81 getBoxes()82 public List<Box> getBoxes() { 83 return boxes; 84 } 85 86 @SuppressWarnings("unchecked") getBoxes(Class<T> clazz, boolean recursive)87 public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) { 88 List<T> boxesToBeReturned = new ArrayList<T>(2); 89 for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()? 90 if (clazz == boxe.getClass()) { 91 boxesToBeReturned.add((T) boxe); 92 } 93 94 if (recursive && boxe instanceof ContainerBox) { 95 boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive)); 96 } 97 } 98 // Optimize here! Spare object creation work on arrays directly! System.arrayCopy 99 return boxesToBeReturned; 100 //return (T[]) boxesToBeReturned.toArray(); 101 } 102 103 @SuppressWarnings("unchecked") getBoxes(Class<T> clazz)104 public <T extends Box> List<T> getBoxes(Class<T> clazz) { 105 return getBoxes(clazz, false); 106 } 107 108 @Override parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser)109 public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { 110 this.boxParser = boxParser; 111 super.parse(readableByteChannel, header, contentSize, boxParser); 112 113 } 114 115 _parseReservedAndDataReferenceIndex(ByteBuffer content)116 public void _parseReservedAndDataReferenceIndex(ByteBuffer content) { 117 content.get(new byte[6]); // ignore 6 reserved bytes; 118 dataReferenceIndex = IsoTypeReader.readUInt16(content); 119 } 120 _parseChildBoxes(ByteBuffer content)121 public void _parseChildBoxes(ByteBuffer content) { 122 while (content.remaining() > 8) { 123 try { 124 boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this)); 125 } catch (IOException e) { 126 throw new RuntimeException(e); 127 } 128 129 } 130 setDeadBytes(content.slice()); 131 } 132 _writeReservedAndDataReferenceIndex(ByteBuffer bb)133 public void _writeReservedAndDataReferenceIndex(ByteBuffer bb) { 134 bb.put(new byte[6]); 135 IsoTypeWriter.writeUInt16(bb, dataReferenceIndex); 136 } 137 _writeChildBoxes(ByteBuffer bb)138 public void _writeChildBoxes(ByteBuffer bb) { 139 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 140 WritableByteChannel wbc = Channels.newChannel(baos); 141 try { 142 for (Box box : boxes) { 143 box.getBox(wbc); 144 } 145 wbc.close(); 146 } catch (IOException e) { 147 throw new RuntimeException("Cannot happen. Everything should be in memory and therefore no exceptions."); 148 } 149 bb.put(baos.toByteArray()); 150 } 151 getNumOfBytesToFirstChild()152 public long getNumOfBytesToFirstChild() { 153 long sizeOfChildren = 0; 154 for (Box box : boxes) { 155 sizeOfChildren += box.getSize(); 156 } 157 return getSize() - sizeOfChildren; 158 } 159 160 } 161