diff options
author | Teng-Hui Zhu <ztenghui@google.com> | 2012-09-20 16:00:17 -0700 |
---|---|---|
committer | Teng-Hui Zhu <ztenghui@google.com> | 2012-09-20 16:25:28 -0700 |
commit | dd9eb897ee7c7b507cbdcf80263bb4b5de6966bf (patch) | |
tree | a0f3b67524d3e7beeca5e30878f349d58a65b705 /isoparser/src/main/java/com/coremedia/iso/.svn | |
parent | 8436c0da2d787a33439f14e9273ea647f346fa9b (diff) | |
download | mp4parser-dd9eb897ee7c7b507cbdcf80263bb4b5de6966bf.tar.gz |
Initial drop the compilable version of mp4parser, with least modification
bug:7093055
Change-Id: Id9b1b4ec91e26ae6e9fd75d86696aa30f30897b3
Diffstat (limited to 'isoparser/src/main/java/com/coremedia/iso/.svn')
14 files changed, 1654 insertions, 0 deletions
diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/.svn/all-wcprops new file mode 100644 index 0000000..9b50c5a --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/all-wcprops @@ -0,0 +1,77 @@ +K 25 +svn:wc:ra_dav:version-url +V 65 +/svn/!svn/ver/777/trunk/isoparser/src/main/java/com/coremedia/iso +END +IsoTypeReader.java +K 25 +svn:wc:ra_dav:version-url +V 84 +/svn/!svn/ver/659/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeReader.java +END +IsoTypeWriterVariable.java +K 25 +svn:wc:ra_dav:version-url +V 92 +/svn/!svn/ver/426/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriterVariable.java +END +Hex.java +K 25 +svn:wc:ra_dav:version-url +V 74 +/svn/!svn/ver/619/trunk/isoparser/src/main/java/com/coremedia/iso/Hex.java +END +IsoTypeReaderVariable.java +K 25 +svn:wc:ra_dav:version-url +V 92 +/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeReaderVariable.java +END +BoxParser.java +K 25 +svn:wc:ra_dav:version-url +V 80 +/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/BoxParser.java +END +Utf8.java +K 25 +svn:wc:ra_dav:version-url +V 75 +/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/Utf8.java +END +Ascii.java +K 25 +svn:wc:ra_dav:version-url +V 76 +/svn/!svn/ver/419/trunk/isoparser/src/main/java/com/coremedia/iso/Ascii.java +END +ChannelHelper.java +K 25 +svn:wc:ra_dav:version-url +V 84 +/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/ChannelHelper.java +END +IsoTypeWriter.java +K 25 +svn:wc:ra_dav:version-url +V 84 +/svn/!svn/ver/692/trunk/isoparser/src/main/java/com/coremedia/iso/IsoTypeWriter.java +END +AbstractBoxParser.java +K 25 +svn:wc:ra_dav:version-url +V 88 +/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/AbstractBoxParser.java +END +IsoFile.java +K 25 +svn:wc:ra_dav:version-url +V 78 +/svn/!svn/ver/742/trunk/isoparser/src/main/java/com/coremedia/iso/IsoFile.java +END +PropertyBoxParserImpl.java +K 25 +svn:wc:ra_dav:version-url +V 92 +/svn/!svn/ver/505/trunk/isoparser/src/main/java/com/coremedia/iso/PropertyBoxParserImpl.java +END diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/.svn/entries new file mode 100644 index 0000000..0114cad --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/entries @@ -0,0 +1,442 @@ +10 + +dir +778 +http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso +http://mp4parser.googlecode.com/svn + + + +2012-09-10T14:56:10.036617Z +777 +sebastian.annies@gmail.com + + + + + + + + + + + + + + +7decde4b-c250-0410-a0da-51896bc88be6 + +IsoTypeReader.java +file + + + + +2012-09-14T17:27:53.147256Z +1b3832056109e2538ddb064410e145a3 +2012-06-06T10:36:53.498661Z +659 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +4181 + +IsoTypeWriterVariable.java +file + + + + +2012-09-14T17:27:53.157256Z +dc08bcfd952e251e81f54d6876cf2822 +2012-03-12T12:55:40.927472Z +426 +hoemmagnus@gmail.com + + + + + + + + + + + + + + + + + + + + + +1471 + +boxes +dir + +Hex.java +file + + + + +2012-09-14T17:27:53.157256Z +834508c38dadb7747ba2a9e611a29f75 +2012-05-20T18:32:15.672660Z +619 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +2026 + +mdta +dir + +IsoTypeReaderVariable.java +file + + + + +2012-09-14T17:27:53.157256Z +a2e5fe2ff8d860e485a09fe069b23b67 +2012-03-11T20:58:41.111953Z +419 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1283 + +BoxParser.java +file + + + + +2012-09-14T17:27:53.157256Z +7ffb4de0f5409f6be08384c50ed1f239 +2012-03-11T20:58:41.111953Z +419 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1089 + +Utf8.java +file + + + + +2012-09-14T17:27:53.157256Z +7e580cd68183dc1f3927fb0866b2030b +2012-03-11T20:58:41.111953Z +419 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1712 + +Ascii.java +file + + + + +2012-09-14T17:27:53.157256Z +30e0990932cfaaf6df4603a5aabbd724 +2012-03-11T20:58:41.111953Z +419 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1274 + +ChannelHelper.java +file + + + + +2012-09-14T17:27:53.157256Z +363efdcb385f027569cf4748273c9533 +2012-04-21T21:18:31.685061Z +505 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +2750 + +IsoTypeWriter.java +file + + + + +2012-09-14T17:27:53.157256Z +746a167bf3de7edb454855bed18ec21b +2012-06-25T03:13:15.796438Z +692 +michael.stattmann@gmail.com + + + + + + + + + + + + + + + + + + + + + +2840 + +AbstractBoxParser.java +file + + + + +2012-09-14T17:27:53.157256Z +e5bf90052f2d10b984827de45560b8b8 +2012-04-21T21:18:31.685061Z +505 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +4828 + +IsoFile.java +file + + + + +2012-09-14T17:27:53.157256Z +fa74e86d8e2f3f19c2a91319ee286b38 +2012-08-12T09:16:02.229115Z +742 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +5567 + +PropertyBoxParserImpl.java +file + + + + +2012-09-14T17:27:53.157256Z +e93996880a8025f186a835bbff195141 +2012-04-21T21:18:31.685061Z +505 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +7247 + diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/AbstractBoxParser.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/AbstractBoxParser.java.svn-base new file mode 100644 index 0000000..6d92acd --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/AbstractBoxParser.java.svn-base @@ -0,0 +1,130 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; +import com.coremedia.iso.boxes.UserBox; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.util.logging.Logger; + +import static com.googlecode.mp4parser.util.CastUtils.l2i; + +/** + * This BoxParser handles the basic stuff like reading size and extracting box type. + */ +public abstract class AbstractBoxParser implements BoxParser { + + private static Logger LOG = Logger.getLogger(AbstractBoxParser.class.getName()); + + public abstract Box createBox(String type, byte[] userType, String parent); + + /** + * Parses the next size and type, creates a box instance and parses the box's content. + * + * @param byteChannel the FileChannel pointing to the ISO file + * @param parent the current box's parent (null if no parent) + * @return the box just parsed + * @throws java.io.IOException if reading from <code>in</code> fails + */ + public Box parseBox(ReadableByteChannel byteChannel, ContainerBox parent) throws IOException { + + + ByteBuffer header = ChannelHelper.readFully(byteChannel, 8); + + long size = IsoTypeReader.readUInt32(header); + // do plausibility check + if (size < 8 && size > 1) { + LOG.severe("Plausibility check failed: size < 8 (size = " + size + "). Stop parsing!"); + return null; + } + + + String type = IsoTypeReader.read4cc(header); + byte[] usertype = null; + long contentSize; + + if (size == 1) { + ByteBuffer bb = ByteBuffer.allocate(8); + byteChannel.read(bb); + bb.rewind(); + size = IsoTypeReader.readUInt64(bb); + contentSize = size - 16; + } else if (size == 0) { + if (byteChannel instanceof FileChannel) { + size = ((FileChannel) byteChannel).size() - ((FileChannel) byteChannel).position() - 8; + } else { + throw new RuntimeException("Only FileChannel inputs may use size == 0 (box reaches to the end of file)"); + } + contentSize = size - 8; + } else { + contentSize = size - 8; + } + if (UserBox.TYPE.equals(type)) { + ByteBuffer bb = ByteBuffer.allocate(16); + byteChannel.read(bb); + bb.rewind(); + usertype = bb.array(); + contentSize -= 16; + } + Box box = createBox(type, usertype, parent.getType()); + box.setParent(parent); + LOG.finest("Parsing " + box.getType()); + // System.out.println("parsing " + Arrays.toString(box.getType()) + " " + box.getClass().getName() + " size=" + size); + + + if (l2i(size - contentSize) == 8) { + // default - no large box - no uuid + // do nothing header's already correct + header.rewind(); + } else if (l2i(size - contentSize) == 16) { + header = ByteBuffer.allocate(16); + IsoTypeWriter.writeUInt32(header, 1); + header.put(IsoFile.fourCCtoBytes(type)); + IsoTypeWriter.writeUInt64(header, size); + } else if (l2i(size - contentSize) == 24) { + header = ByteBuffer.allocate(24); + IsoTypeWriter.writeUInt32(header, size); + header.put(IsoFile.fourCCtoBytes(type)); + header.put(usertype); + } else if (l2i(size - contentSize) == 32) { + header = ByteBuffer.allocate(32); + IsoTypeWriter.writeUInt32(header, size); + header.put(IsoFile.fourCCtoBytes(type)); + IsoTypeWriter.writeUInt64(header, size); + header.put(usertype); + } else { + throw new RuntimeException("I didn't expect that"); + } + + + box.parse(byteChannel, header, contentSize, this); + // System.out.println("box = " + box); + + + assert size == box.getSize() : + "Reconstructed Size is not x to the number of parsed bytes! (" + + box.getType() + ")" + + " Actual Box size: " + size + " Calculated size: " + box.getSize(); + return box; + } + + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Ascii.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Ascii.java.svn-base new file mode 100644 index 0000000..2a659d7 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Ascii.java.svn-base @@ -0,0 +1,47 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import java.io.UnsupportedEncodingException; + +/** + * Converts <code>byte[]</code> -> <code>String</code> and vice versa. + */ +public final class Ascii { + public static byte[] convert(String s) { + try { + if (s != null) { + return s.getBytes("us-ascii"); + } else { + return null; + } + } catch (UnsupportedEncodingException e) { + throw new Error(e); + } + } + + public static String convert(byte[] b) { + try { + if (b != null) { + return new String(b, "us-ascii"); + } else { + return null; + } + } catch (UnsupportedEncodingException e) { + throw new Error(e); + } + } +}
\ No newline at end of file diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/BoxParser.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/BoxParser.java.svn-base new file mode 100644 index 0000000..cbe9a6f --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/BoxParser.java.svn-base @@ -0,0 +1,31 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; + +import java.io.IOException; +import java.nio.channels.ReadableByteChannel; + +/** + * Basic interface to create boxes from a <code>IsoBufferWrapper</code> and its parent. + */ +public interface BoxParser { + Class<? extends Box> getClassForFourCc(String type, byte[] userType, String parent); + + Box parseBox(ReadableByteChannel in, ContainerBox parent) throws IOException; +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/ChannelHelper.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/ChannelHelper.java.svn-base new file mode 100644 index 0000000..2ec1d05 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/ChannelHelper.java.svn-base @@ -0,0 +1,90 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.WritableByteChannel; + +import static com.googlecode.mp4parser.util.CastUtils.l2i; + + +public class ChannelHelper { + public static ByteBuffer readFully(final ReadableByteChannel channel, long size) throws IOException { + + if (channel instanceof FileChannel && size > 1024 * 1024) { + ByteBuffer bb = ((FileChannel) channel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) channel).position(), size); + ((FileChannel) channel).position(((FileChannel) channel).position() + size); + return bb; + } else { + ByteBuffer buf = ByteBuffer.allocate(l2i(size)); + readFully(channel, buf, buf.limit()); + buf.rewind(); + assert buf.limit() == size; + + return buf; + } + + } + + + public static void readFully(final ReadableByteChannel channel, final ByteBuffer buf) + throws IOException { + readFully(channel, buf, buf.remaining()); + } + + public static int readFully(final ReadableByteChannel channel, final ByteBuffer buf, final int length) + throws IOException { + int n, count = 0; + while (-1 != (n = channel.read(buf))) { + count += n; + if (count == length) { + break; + } + } + if (n == -1) { + throw new EOFException("End of file. No more boxes."); + } + return count; + } + + + public static void writeFully(final WritableByteChannel channel, final ByteBuffer buf) + throws IOException { + do { + int written = channel.write(buf); + if (written < 0) { + throw new EOFException(); + } + } while (buf.hasRemaining()); + } + + + public static void close(SelectionKey key) { + try { + key.channel().close(); + } catch (IOException e) { + // nop + } + + } + + +}
\ No newline at end of file diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Hex.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Hex.java.svn-base new file mode 100644 index 0000000..b3d55ef --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Hex.java.svn-base @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +Extracted from commons-codec + */ +package com.coremedia.iso; + +import java.io.ByteArrayOutputStream; + +/** + * Converts hexadecimal Strings. + */ +public class Hex { + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + public static String encodeHex(byte[] data) { + return encodeHex(data, 0); + } + + public static String encodeHex(byte[] data, int group) { + int l = data.length; + char[] out = new char[(l << 1) + (group > 0 ? (l / group) : 0)]; + // two characters form the hex value. + for (int i = 0, j = 0; i < l; i++) { + if ((group > 0) && ((i % group) == 0) && j > 0) { + out[j++] = '-'; + } + + out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; + out[j++] = DIGITS[0x0F & data[i]]; + } + return new String(out); + } + + public static byte[] decodeHex(String hexString) { + ByteArrayOutputStream bas = new ByteArrayOutputStream(); + for (int i = 0; i < hexString.length(); i += 2) { + int b = Integer.parseInt(hexString.substring(i, i + 2), 16); + bas.write(b); + } + return bas.toByteArray(); + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoFile.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoFile.java.svn-base new file mode 100644 index 0000000..a6f4b2b --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoFile.java.svn-base @@ -0,0 +1,195 @@ +/* + * Copyright 2008 CoreMedia AG, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.coremedia.iso; + +import com.googlecode.mp4parser.AbstractContainerBox; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.MovieBox; +import com.googlecode.mp4parser.annotations.DoNotParseDetail; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +/** + * The most upper container for ISO Boxes. It is a container box that is a file. + * Uses IsoBufferWrapper to access the underlying file. + */ +@DoNotParseDetail +public class IsoFile extends AbstractContainerBox implements Closeable { + protected BoxParser boxParser = new PropertyBoxParserImpl(); + ReadableByteChannel byteChannel; + + public IsoFile() { + super(""); + } + + public IsoFile(File f) throws IOException { + super(""); + this.byteChannel = new FileInputStream(f).getChannel(); + boxParser = createBoxParser(); + parse(); + } + + public IsoFile(ReadableByteChannel byteChannel) throws IOException { + super(""); + this.byteChannel = byteChannel; + boxParser = createBoxParser(); + parse(); + } + + public IsoFile(ReadableByteChannel byteChannel, BoxParser boxParser) throws IOException { + super(""); + this.byteChannel = byteChannel; + this.boxParser = boxParser; + parse(); + + + } + + protected BoxParser createBoxParser() { + return new PropertyBoxParserImpl(); + } + + + @Override + public void _parseDetails(ByteBuffer content) { + // there are no details to parse we should be just file + } + + public void parse(ReadableByteChannel inFC, ByteBuffer header, long contentSize, AbstractBoxParser abstractBoxParser) throws IOException { + throw new IOException("This method is not meant to be called. Use #parse() directly."); + } + + private void parse() throws IOException { + + boolean done = false; + while (!done) { + try { + Box box = boxParser.parseBox(byteChannel, this); + if (box != null) { + // System.err.println(box.getType()); + boxes.add(box); + } else { + done = true; + } + } catch (EOFException e) { + done = true; + } + } + } + + @DoNotParseDetail + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("IsoFile["); + if (boxes == null) { + buffer.append("unparsed"); + } else { + for (int i = 0; i < boxes.size(); i++) { + if (i > 0) { + buffer.append(";"); + } + buffer.append(boxes.get(i).toString()); + } + } + buffer.append("]"); + return buffer.toString(); + } + + @DoNotParseDetail + public static byte[] fourCCtoBytes(String fourCC) { + byte[] result = new byte[4]; + if (fourCC != null) { + for (int i = 0; i < Math.min(4, fourCC.length()); i++) { + result[i] = (byte) fourCC.charAt(i); + } + } + return result; + } + + @DoNotParseDetail + public static String bytesToFourCC(byte[] type) { + byte[] result = new byte[]{0, 0, 0, 0}; + if (type != null) { + System.arraycopy(type, 0, result, 0, Math.min(type.length, 4)); + } + try { + return new String(result, "ISO-8859-1"); + } catch (UnsupportedEncodingException e) { + throw new Error("Required character encoding is missing", e); + } + } + + + @Override + public long getNumOfBytesToFirstChild() { + return 0; + } + + @Override + public long getSize() { + long size = 0; + for (Box box : boxes) { + size += box.getSize(); + } + return size; + } + + @Override + public IsoFile getIsoFile() { + return this; + } + + + /** + * Shortcut to get the MovieBox since it is often needed and present in + * nearly all ISO 14496 files (at least if they are derived from MP4 ). + * + * @return the MovieBox or <code>null</code> + */ + @DoNotParseDetail + public MovieBox getMovieBox() { + for (Box box : boxes) { + if (box instanceof MovieBox) { + return (MovieBox) box; + } + } + return null; + } + + public void getBox(WritableByteChannel os) throws IOException { + for (Box box : boxes) { + + if (os instanceof FileChannel) { + long startPos = ((FileChannel) os).position(); + box.getBox(os); + long size = ((FileChannel) os).position() - startPos; + assert size == box.getSize(); + } else { + box.getBox(os); + } + + } + } + + public void close() throws IOException { + this.byteChannel.close(); + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReader.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReader.java.svn-base new file mode 100644 index 0000000..6d9e86e --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReader.java.svn-base @@ -0,0 +1,147 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +public final class IsoTypeReader { + + + public static long readUInt32BE(ByteBuffer bb) { + long ch1 = readUInt8(bb); + long ch2 = readUInt8(bb); + long ch3 = readUInt8(bb); + long ch4 = readUInt8(bb); + return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); + + } + + + public static long readUInt32(ByteBuffer bb) { + long i = bb.getInt(); + if (i < 0) { + i += 1l<<32; + } + return i; + } + + public static int readUInt24(ByteBuffer bb) { + int result = 0; + result += readUInt16(bb) << 8; + result += byte2int(bb.get()); + return result; + } + + + public static int readUInt16(ByteBuffer bb) { + int result = 0; + result += byte2int(bb.get()) << 8; + result += byte2int(bb.get()); + return result; + } + + public static int readUInt16BE(ByteBuffer bb) { + int result = 0; + result += byte2int(bb.get()); + result += byte2int(bb.get()) << 8; + return result; + } + + public static int readUInt8(ByteBuffer bb) { + return byte2int(bb.get()); + } + + public static int byte2int(byte b) { + return b < 0 ? b + 256 : b; + } + + + /** + * Reads a zero terminated UTF-8 string. + * + * @param byteBuffer the data source + * @return the string readByte + * @throws Error in case of an error in the underlying stream + */ + public static String readString(ByteBuffer byteBuffer) { + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int read; + while ((read = byteBuffer.get()) != 0) { + out.write(read); + } + return Utf8.convert(out.toByteArray()); + } + + public static String readString(ByteBuffer byteBuffer, int length) { + byte[] buffer = new byte[length]; + byteBuffer.get(buffer); + return Utf8.convert(buffer); + + } + + public static long readUInt64(ByteBuffer byteBuffer) { + long result = 0; + // thanks to Erik Nicolas for finding a bug! Cast to long is definitivly needed + result += readUInt32(byteBuffer) << 32; + if (result < 0) { + throw new RuntimeException("I don't know how to deal with UInt64! long is not sufficient and I don't want to use BigInt"); + } + result += readUInt32(byteBuffer); + + return result; + } + + public static double readFixedPoint1616(ByteBuffer bb) { + byte[] bytes = new byte[4]; + bb.get(bytes); + + int result = 0; + result |= ((bytes[0] << 24) & 0xFF000000); + result |= ((bytes[1] << 16) & 0xFF0000); + result |= ((bytes[2] << 8) & 0xFF00); + result |= ((bytes[3]) & 0xFF); + return ((double) result) / 65536; + + } + + public static float readFixedPoint88(ByteBuffer bb) { + byte[] bytes = new byte[2]; + bb.get(bytes); + short result = 0; + result |= ((bytes[0] << 8) & 0xFF00); + result |= ((bytes[1]) & 0xFF); + return ((float) result) / 256; + } + + public static String readIso639(ByteBuffer bb) { + int bits = readUInt16(bb); + StringBuilder result = new StringBuilder(); + for (int i = 0; i < 3; i++) { + int c = (bits >> (2 - i) * 5) & 0x1f; + result.append((char) (c + 0x60)); + } + return result.toString(); + } + + public static String read4cc(ByteBuffer bb) { + byte[] b = new byte[4]; + bb.get(b); + return IsoFile.bytesToFourCC(b); + } + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReaderVariable.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReaderVariable.java.svn-base new file mode 100644 index 0000000..a2e4681 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeReaderVariable.java.svn-base @@ -0,0 +1,39 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import java.nio.ByteBuffer; + +public final class IsoTypeReaderVariable { + + public static long read(ByteBuffer bb, int bytes) { + switch (bytes) { + case 1: + return IsoTypeReader.readUInt8(bb); + case 2: + return IsoTypeReader.readUInt16(bb); + case 3: + return IsoTypeReader.readUInt24(bb); + case 4: + return IsoTypeReader.readUInt32(bb); + case 8: + return IsoTypeReader.readUInt64(bb); + default: + throw new RuntimeException("I don't know how to read " + bytes + " bytes"); + } + + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriter.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriter.java.svn-base new file mode 100644 index 0000000..6da6998 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriter.java.svn-base @@ -0,0 +1,95 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import java.nio.ByteBuffer; + +public final class IsoTypeWriter { + + public static void writeUInt64(ByteBuffer bb, long u) { + bb.putLong(u); + } + + public static void writeUInt32(ByteBuffer bb, long u) { + bb.putInt((int) u); + + } + + public static void writeUInt32BE(ByteBuffer bb, long u) { + assert u >= 0 && u <= 1L << 32 : "The given long is not in the range of uint32 (" + u + ")"; + writeUInt16BE(bb, (int) u & 0xFFFF); + writeUInt16BE(bb, (int) ((u >> 16) & 0xFFFF)); + + } + + + public static void writeUInt24(ByteBuffer bb, int i) { + i = i & 0xFFFFFF; + writeUInt16(bb, i >> 8); + writeUInt8(bb, i); + + } + + + public static void writeUInt16(ByteBuffer bb, int i) { + i = i & 0xFFFF; + writeUInt8(bb, i >> 8); + writeUInt8(bb, i & 0xFF); + } + + public static void writeUInt16BE(ByteBuffer bb, int i) { + i = i & 0xFFFF; + writeUInt8(bb, i & 0xFF); + writeUInt8(bb, i >> 8); + } + + public static void writeUInt8(ByteBuffer bb, int i) { + i = i & 0xFF; + bb.put((byte) i); + } + + + public static void writeFixedPont1616(ByteBuffer bb, double v) { + int result = (int) (v * 65536); + bb.put((byte) ((result & 0xFF000000) >> 24)); + bb.put((byte) ((result & 0x00FF0000) >> 16)); + bb.put((byte) ((result & 0x0000FF00) >> 8)); + bb.put((byte) ((result & 0x000000FF))); + } + + public static void writeFixedPont88(ByteBuffer bb, double v) { + short result = (short) (v * 256); + bb.put((byte) ((result & 0xFF00) >> 8)); + bb.put((byte) ((result & 0x00FF))); + } + + public static void writeIso639(ByteBuffer bb, String language) { + if (language.getBytes().length != 3) { + throw new IllegalArgumentException("\"" + language + "\" language string isn't exactly 3 characters long!"); + } + int bits = 0; + for (int i = 0; i < 3; i++) { + bits += (language.getBytes()[i] - 0x60) << (2 - i) * 5; + } + writeUInt16(bb, bits); + } + + public static void writeUtf8String(ByteBuffer bb, String string) { + + bb.put(Utf8.convert(string)); + writeUInt8(bb, 0); + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriterVariable.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriterVariable.java.svn-base new file mode 100644 index 0000000..3b3bdd4 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/IsoTypeWriterVariable.java.svn-base @@ -0,0 +1,45 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public final class IsoTypeWriterVariable { + + public static void write(long v, ByteBuffer bb, int bytes) { + switch (bytes) { + case 1: + IsoTypeWriter.writeUInt8(bb, (int) (v & 0xff)); + break; + case 2: + IsoTypeWriter.writeUInt16(bb, (int) (v & 0xffff)); + break; + case 3: + IsoTypeWriter.writeUInt24(bb, (int) (v & 0xffffff)); + break; + case 4: + IsoTypeWriter.writeUInt32(bb, v); + break; + case 8: + IsoTypeWriter.writeUInt64(bb, v); + break; + default: + throw new RuntimeException("I don't know how to read " + bytes + " bytes"); + } + + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/PropertyBoxParserImpl.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/PropertyBoxParserImpl.java.svn-base new file mode 100644 index 0000000..f1bcc01 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/PropertyBoxParserImpl.java.svn-base @@ -0,0 +1,199 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import com.googlecode.mp4parser.AbstractBox; +import com.coremedia.iso.boxes.Box; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A Property file based BoxFactory + */ +public class PropertyBoxParserImpl extends AbstractBoxParser { + Properties mapping; + + public PropertyBoxParserImpl(String... customProperties) { + InputStream is = new BufferedInputStream(getClass().getResourceAsStream("/isoparser-default.properties")); + try { + mapping = new Properties(); + try { + mapping.load(is); + Enumeration<URL> enumeration = Thread.currentThread().getContextClassLoader().getResources("isoparser-custom.properties"); + + while (enumeration.hasMoreElements()) { + URL url = enumeration.nextElement(); + InputStream customIS = new BufferedInputStream(url.openStream()); + try { + mapping.load(customIS); + } finally { + customIS.close(); + } + } + for (String customProperty : customProperties) { + mapping.load(new BufferedInputStream(getClass().getResourceAsStream(customProperty))); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + // ignore - I can't help + } + } + } + + public PropertyBoxParserImpl(Properties mapping) { + this.mapping = mapping; + } + + Pattern p = Pattern.compile("(.*)\\((.*?)\\)"); + + @SuppressWarnings("unchecked") + public Class<? extends Box> getClassForFourCc(String type, byte[] userType, String parent) { + FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke(); + try { + return (Class<? extends Box>) Class.forName(fourCcToBox.clazzName); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + @Override + public Box createBox(String type, byte[] userType, String parent) { + + FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke(); + String[] param = fourCcToBox.getParam(); + String clazzName = fourCcToBox.getClazzName(); + try { + if (param[0].trim().length() == 0) { + param = new String[]{}; + } + Class clazz = Class.forName(clazzName); + + Class[] constructorArgsClazz = new Class[param.length]; + Object[] constructorArgs = new Object[param.length]; + for (int i = 0; i < param.length; i++) { + + if ("userType".equals(param[i])) { + constructorArgs[i] = userType; + constructorArgsClazz[i] = byte[].class; + } else if ("type".equals(param[i])) { + constructorArgs[i] = type; + constructorArgsClazz[i] = String.class; + } else if ("parent".equals(param[i])) { + constructorArgs[i] = parent; + constructorArgsClazz[i] = String.class; + } else { + throw new InternalError("No such param: " + param[i]); + } + + + } + Constructor<AbstractBox> constructorObject; + try { + if (param.length > 0) { + constructorObject = clazz.getConstructor(constructorArgsClazz); + } else { + constructorObject = clazz.getConstructor(); + } + + return constructorObject.newInstance(constructorArgs); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private class FourCcToBox { + private String type; + private byte[] userType; + private String parent; + private String clazzName; + private String[] param; + + public FourCcToBox(String type, byte[] userType, String parent) { + this.type = type; + this.parent = parent; + this.userType = userType; + } + + public String getClazzName() { + return clazzName; + } + + public String[] getParam() { + return param; + } + + public FourCcToBox invoke() { + String constructor; + if (userType != null) { + if (!"uuid".equals((type))) { + throw new RuntimeException("we have a userType but no uuid box type. Something's wrong"); + } + constructor = mapping.getProperty((parent) + "-uuid[" + Hex.encodeHex(userType).toUpperCase() + "]"); + if (constructor == null) { + constructor = mapping.getProperty("uuid[" + Hex.encodeHex(userType).toUpperCase() + "]"); + } + if (constructor == null) { + constructor = mapping.getProperty("uuid"); + } + } else { + constructor = mapping.getProperty((parent) + "-" + (type)); + if (constructor == null) { + constructor = mapping.getProperty((type)); + } + } + if (constructor == null) { + constructor = mapping.getProperty("default"); + } + if (constructor == null) { + throw new RuntimeException("No box object found for " + type); + } + Matcher m = p.matcher(constructor); + boolean matches = m.matches(); + if (!matches) { + throw new RuntimeException("Cannot work with that constructor: " + constructor); + } + clazzName = m.group(1); + param = m.group(2).split(","); + return this; + } + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Utf8.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Utf8.java.svn-base new file mode 100644 index 0000000..a30497e --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/.svn/text-base/Utf8.java.svn-base @@ -0,0 +1,59 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.coremedia.iso; + +import java.io.UnsupportedEncodingException; + +/** + * Converts <code>byte[]</code> -> <code>String</code> and vice versa. + */ +public final class Utf8 { + public static byte[] convert(String s) { + try { + if (s != null) { + return s.getBytes("UTF-8"); + } else { + return null; + } + } catch (UnsupportedEncodingException e) { + throw new Error(e); + } + } + + public static String convert(byte[] b) { + try { + if (b != null) { + return new String(b, "UTF-8"); + } else { + return null; + } + } catch (UnsupportedEncodingException e) { + throw new Error(e); + } + } + + public static int utf8StringLengthInBytes(String utf8) { + try { + if (utf8 != null) { + return utf8.getBytes("UTF-8").length; + } else { + return 0; + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(); + } + } +} |