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; 18 19 20 import com.coremedia.iso.BoxParser; 21 import com.coremedia.iso.ChannelHelper; 22 import com.coremedia.iso.IsoTypeWriter; 23 import com.googlecode.mp4parser.AbstractBox; 24 25 import java.io.IOException; 26 import java.nio.ByteBuffer; 27 import java.nio.channels.FileChannel; 28 import java.nio.channels.ReadableByteChannel; 29 import java.nio.channels.WritableByteChannel; 30 import java.util.LinkedList; 31 import java.util.List; 32 33 import static com.googlecode.mp4parser.util.CastUtils.l2i; 34 35 /** 36 * A free box. Just a placeholder to enable editing without rewriting the whole file. 37 */ 38 public class FreeBox implements Box { 39 public static final String TYPE = "free"; 40 ByteBuffer data; 41 List<Box> replacers = new LinkedList<Box>(); 42 private ContainerBox parent; 43 FreeBox()44 public FreeBox() { 45 } 46 FreeBox(int size)47 public FreeBox(int size) { 48 this.data = ByteBuffer.allocate(size); 49 } 50 51 getData()52 public ByteBuffer getData() { 53 return data; 54 } 55 setData(ByteBuffer data)56 public void setData(ByteBuffer data) { 57 this.data = data; 58 } 59 getBox(WritableByteChannel os)60 public void getBox(WritableByteChannel os) throws IOException { 61 for (Box replacer : replacers) { 62 replacer.getBox(os); 63 } 64 ByteBuffer header = ByteBuffer.allocate(8); 65 IsoTypeWriter.writeUInt32(header, 8 + data.limit()); 66 header.put(TYPE.getBytes()); 67 header.rewind(); 68 os.write(header); 69 data.rewind(); 70 os.write(data); 71 72 } 73 getParent()74 public ContainerBox getParent() { 75 return parent; 76 } 77 setParent(ContainerBox parent)78 public void setParent(ContainerBox parent) { 79 this.parent = parent; 80 } 81 getSize()82 public long getSize() { 83 long size = 8; 84 for (Box replacer : replacers) { 85 size += replacer.getSize(); 86 } 87 size += data.limit(); 88 return size; 89 } 90 getType()91 public String getType() { 92 return TYPE; 93 } 94 parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser)95 public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { 96 if (readableByteChannel instanceof FileChannel && contentSize > 1024 * 1024) { 97 // It's quite expensive to map a file into the memory. Just do it when the box is larger than a MB. 98 data = ((FileChannel) readableByteChannel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) readableByteChannel).position(), contentSize); 99 ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize); 100 } else { 101 assert contentSize < Integer.MAX_VALUE; 102 data = ChannelHelper.readFully(readableByteChannel, contentSize); 103 } 104 } 105 106 107 public void addAndReplace(Box box) { 108 data.position(l2i(box.getSize())); 109 data = data.slice(); 110 replacers.add(box); 111 } 112 113 114 }