diff options
Diffstat (limited to 'isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry')
18 files changed, 2793 insertions, 0 deletions
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/all-wcprops b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/all-wcprops new file mode 100644 index 0000000..8a5b647 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/all-wcprops @@ -0,0 +1,53 @@ +K 25 +svn:wc:ra_dav:version-url +V 83 +/svn/!svn/ver/757/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry +END +SubtitleSampleEntry.java +K 25 +svn:wc:ra_dav:version-url +V 108 +/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java +END +Ovc1VisualSampleEntryImpl.java +K 25 +svn:wc:ra_dav:version-url +V 114 +/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java +END +SampleEntry.java +K 25 +svn:wc:ra_dav:version-url +V 100 +/svn/!svn/ver/745/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java +END +AudioSampleEntry.java +K 25 +svn:wc:ra_dav:version-url +V 105 +/svn/!svn/ver/757/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java +END +VisualSampleEntry.java +K 25 +svn:wc:ra_dav:version-url +V 106 +/svn/!svn/ver/745/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java +END +TextSampleEntry.java +K 25 +svn:wc:ra_dav:version-url +V 104 +/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java +END +MpegSampleEntry.java +K 25 +svn:wc:ra_dav:version-url +V 104 +/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java +END +AmrSpecificBox.java +K 25 +svn:wc:ra_dav:version-url +V 103 +/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java +END diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/entries b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/entries new file mode 100644 index 0000000..3891d06 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/entries @@ -0,0 +1,300 @@ +10 + +dir +778 +http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry +http://mp4parser.googlecode.com/svn + + + +2012-08-17T05:55:12.215481Z +757 +michael.stattmann@gmail.com + + + + + + + + + + + + + + +7decde4b-c250-0410-a0da-51896bc88be6 + +SubtitleSampleEntry.java +file + + + + +2012-09-14T17:27:52.647249Z +a1d02883384ec405c3d62e1a4d157b5e +2012-04-21T22:05:38.425329Z +507 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +2055 + +Ovc1VisualSampleEntryImpl.java +file + + + + +2012-09-14T17:27:52.647249Z +c92067b340193f4ffa776fd1e449dcf5 +2012-04-21T22:05:38.425329Z +507 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1018 + +SampleEntry.java +file + + + + +2012-09-14T17:27:52.647249Z +8d726941a0af28eaa7b3cc9abcf4bd55 +2012-08-14T19:18:50.777750Z +745 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +5020 + +AudioSampleEntry.java +file + + + + +2012-09-14T17:27:52.647249Z +3ee1365e9bd772c4e77c3011765ae58a +2012-08-17T05:55:12.215481Z +757 +michael.stattmann@gmail.com + + + + + + + + + + + + + + + + + + + + + +8585 + +VisualSampleEntry.java +file + + + + +2012-09-14T17:27:52.647249Z +5616cce8d163f57f4e105fd3dbf34e61 +2012-08-14T19:18:50.777750Z +745 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +6899 + +TextSampleEntry.java +file + + + + +2012-09-14T17:27:52.647249Z +96794e77ef63fbcc1cb861b25ddbb784 +2012-04-21T22:05:38.425329Z +507 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +9126 + +MpegSampleEntry.java +file + + + + +2012-09-14T17:27:52.647249Z +97170f2c4511a4f03915f73d5690cb4d +2012-04-21T22:05:38.425329Z +507 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1079 + +AmrSpecificBox.java +file + + + + +2012-09-14T17:27:52.647249Z +c306ac7445479a0a2642022bb8428d8f +2012-04-21T22:05:38.425329Z +507 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +2974 + diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AmrSpecificBox.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AmrSpecificBox.java.svn-base new file mode 100644 index 0000000..f69de7b --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AmrSpecificBox.java.svn-base @@ -0,0 +1,101 @@ +/* + * 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.boxes.sampleentry; + + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.AbstractBox; + +import java.nio.ByteBuffer; + +/** + * AMR audio format specific subbox of an audio sample entry. + * + * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry + */ +public class AmrSpecificBox extends AbstractBox { + public static final String TYPE = "damr"; + + private String vendor; + private int decoderVersion; + private int modeSet; + private int modeChangePeriod; + private int framesPerSample; + + public AmrSpecificBox() { + super(TYPE); + } + + public String getVendor() { + return vendor; + } + + public int getDecoderVersion() { + return decoderVersion; + } + + public int getModeSet() { + return modeSet; + } + + public int getModeChangePeriod() { + return modeChangePeriod; + } + + public int getFramesPerSample() { + return framesPerSample; + } + + protected long getContentSize() { + return 9; + } + + @Override + public void _parseDetails(ByteBuffer content) { + byte[] v = new byte[4]; + content.get(v); + vendor = IsoFile.bytesToFourCC(v); + + decoderVersion = IsoTypeReader.readUInt8(content); + modeSet = IsoTypeReader.readUInt16(content); + modeChangePeriod = IsoTypeReader.readUInt8(content); + framesPerSample = IsoTypeReader.readUInt8(content); + + } + + + public void getContent(ByteBuffer byteBuffer) { + byteBuffer.put(IsoFile.fourCCtoBytes(vendor)); + IsoTypeWriter.writeUInt8(byteBuffer, decoderVersion); + IsoTypeWriter.writeUInt16(byteBuffer, modeSet); + IsoTypeWriter.writeUInt8(byteBuffer, modeChangePeriod); + IsoTypeWriter.writeUInt8(byteBuffer, framesPerSample); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("AmrSpecificBox[vendor=").append(getVendor()); + buffer.append(";decoderVersion=").append(getDecoderVersion()); + buffer.append(";modeSet=").append(getModeSet()); + buffer.append(";modeChangePeriod=").append(getModeChangePeriod()); + buffer.append(";framesPerSample=").append(getFramesPerSample()); + buffer.append("]"); + return buffer.toString(); + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AudioSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AudioSampleEntry.java.svn-base new file mode 100644 index 0000000..69aeb79 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/AudioSampleEntry.java.svn-base @@ -0,0 +1,278 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; + +import java.nio.ByteBuffer; + +/** + * Contains basic information about the audio samples in this track. Format-specific information + * is appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2. + */ +public class AudioSampleEntry extends SampleEntry implements ContainerBox { + + public static final String TYPE1 = "samr"; + public static final String TYPE2 = "sawb"; + public static final String TYPE3 = "mp4a"; + public static final String TYPE4 = "drms"; + public static final String TYPE5 = "alac"; + public static final String TYPE7 = "owma"; + public static final String TYPE8 = "ac-3"; /* ETSI TS 102 366 1.2.1 Annex F */ + public static final String TYPE9 = "ec-3"; /* ETSI TS 102 366 1.2.1 Annex F */ + public static final String TYPE10 = "mlpa"; + public static final String TYPE11 = "dtsl"; + public static final String TYPE12 = "dtsh"; + public static final String TYPE13 = "dtse"; + + /** + * Identifier for an encrypted audio track. + * + * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox + */ + public static final String TYPE_ENCRYPTED = "enca"; + + private int channelCount; + private int sampleSize; + private long sampleRate; + private int soundVersion; + private int compressionId; + private int packetSize; + private long samplesPerPacket; + private long bytesPerPacket; + private long bytesPerFrame; + private long bytesPerSample; + + private int reserved1; + private long reserved2; + private byte[] soundVersion2Data; + private BoxParser boxParser; + + public AudioSampleEntry(String type) { + super(type); + } + + public int getChannelCount() { + return channelCount; + } + + public int getSampleSize() { + return sampleSize; + } + + public long getSampleRate() { + return sampleRate; + } + + public int getSoundVersion() { + return soundVersion; + } + + public int getCompressionId() { + return compressionId; + } + + public int getPacketSize() { + return packetSize; + } + + public long getSamplesPerPacket() { + return samplesPerPacket; + } + + public long getBytesPerPacket() { + return bytesPerPacket; + } + + public long getBytesPerFrame() { + return bytesPerFrame; + } + + public long getBytesPerSample() { + return bytesPerSample; + } + + public byte[] getSoundVersion2Data() { + return soundVersion2Data; + } + + public int getReserved1() { + return reserved1; + } + + public long getReserved2() { + return reserved2; + } + + public void setChannelCount(int channelCount) { + this.channelCount = channelCount; + } + + public void setSampleSize(int sampleSize) { + this.sampleSize = sampleSize; + } + + public void setSampleRate(long sampleRate) { + this.sampleRate = sampleRate; + } + + public void setSoundVersion(int soundVersion) { + this.soundVersion = soundVersion; + } + + public void setCompressionId(int compressionId) { + this.compressionId = compressionId; + } + + public void setPacketSize(int packetSize) { + this.packetSize = packetSize; + } + + public void setSamplesPerPacket(long samplesPerPacket) { + this.samplesPerPacket = samplesPerPacket; + } + + public void setBytesPerPacket(long bytesPerPacket) { + this.bytesPerPacket = bytesPerPacket; + } + + public void setBytesPerFrame(long bytesPerFrame) { + this.bytesPerFrame = bytesPerFrame; + } + + public void setBytesPerSample(long bytesPerSample) { + this.bytesPerSample = bytesPerSample; + } + + public void setReserved1(int reserved1) { + this.reserved1 = reserved1; + } + + public void setReserved2(long reserved2) { + this.reserved2 = reserved2; + } + + public void setSoundVersion2Data(byte[] soundVersion2Data) { + this.soundVersion2Data = soundVersion2Data; + } + + public void setBoxParser(BoxParser boxParser) { + this.boxParser = boxParser; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); //parses the six reserved bytes and dataReferenceIndex + // 8 bytes already parsed + //reserved bits - used by qt + soundVersion = IsoTypeReader.readUInt16(content); + + //reserved + reserved1 = IsoTypeReader.readUInt16(content); + reserved2 = IsoTypeReader.readUInt32(content); + + channelCount = IsoTypeReader.readUInt16(content); + sampleSize = IsoTypeReader.readUInt16(content); + //reserved bits - used by qt + compressionId = IsoTypeReader.readUInt16(content); + //reserved bits - used by qt + packetSize = IsoTypeReader.readUInt16(content); + //sampleRate = in.readFixedPoint1616(); + sampleRate = IsoTypeReader.readUInt32(content); + if (!type.equals("mlpa")) { + sampleRate = sampleRate >>> 16; + } + + //more qt stuff - see http://mp4v2.googlecode.com/svn-history/r388/trunk/src/atom_sound.cpp + if (soundVersion > 0) { + samplesPerPacket = IsoTypeReader.readUInt32(content); + bytesPerPacket = IsoTypeReader.readUInt32(content); + bytesPerFrame = IsoTypeReader.readUInt32(content); + bytesPerSample = IsoTypeReader.readUInt32(content); + } + if (soundVersion == 2) { + + soundVersion2Data = new byte[20]; + content.get(20); + } + _parseChildBoxes(content); + + } + + + @Override + protected long getContentSize() { + long contentSize = 28; + contentSize += soundVersion > 0 ? 16 : 0; + contentSize += soundVersion == 2 ? 20 : 0; + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + @Override + public String toString() { + return "AudioSampleEntry{" + + "bytesPerSample=" + bytesPerSample + + ", bytesPerFrame=" + bytesPerFrame + + ", bytesPerPacket=" + bytesPerPacket + + ", samplesPerPacket=" + samplesPerPacket + + ", packetSize=" + packetSize + + ", compressionId=" + compressionId + + ", soundVersion=" + soundVersion + + ", sampleRate=" + sampleRate + + ", sampleSize=" + sampleSize + + ", channelCount=" + channelCount + + ", boxes=" + getBoxes() + + '}'; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUInt16(byteBuffer, soundVersion); + IsoTypeWriter.writeUInt16(byteBuffer, reserved1); + IsoTypeWriter.writeUInt32(byteBuffer, reserved2); + IsoTypeWriter.writeUInt16(byteBuffer, channelCount); + IsoTypeWriter.writeUInt16(byteBuffer, sampleSize); + IsoTypeWriter.writeUInt16(byteBuffer, compressionId); + IsoTypeWriter.writeUInt16(byteBuffer, packetSize); + //isos.writeFixedPont1616(getSampleRate()); + if (type.equals("mlpa")) { + IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate()); + } else { + IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate() << 16); + } + + if (soundVersion > 0) { + IsoTypeWriter.writeUInt32(byteBuffer, samplesPerPacket); + IsoTypeWriter.writeUInt32(byteBuffer, bytesPerPacket); + IsoTypeWriter.writeUInt32(byteBuffer, bytesPerFrame); + IsoTypeWriter.writeUInt32(byteBuffer, bytesPerSample); + } + + if (soundVersion == 2) { + byteBuffer.put(soundVersion2Data); + } + _writeChildBoxes(byteBuffer); + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/MpegSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/MpegSampleEntry.java.svn-base new file mode 100644 index 0000000..e4a33dc --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/MpegSampleEntry.java.svn-base @@ -0,0 +1,43 @@ +package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+public class MpegSampleEntry extends SampleEntry implements ContainerBox {
+
+ private BoxParser boxParser;
+
+ public MpegSampleEntry(String type) {
+ super(type);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ _parseReservedAndDataReferenceIndex(content);
+ _parseChildBoxes(content);
+
+ }
+
+ @Override
+ protected long getContentSize() {
+ long contentSize = 8;
+ for (Box boxe : boxes) {
+ contentSize += boxe.getSize();
+ }
+ return contentSize;
+ }
+
+ public String toString() {
+ return "MpegSampleEntry" + Arrays.asList(getBoxes());
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ _writeReservedAndDataReferenceIndex(byteBuffer);
+ _writeChildBoxes(byteBuffer);
+ }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/Ovc1VisualSampleEntryImpl.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/Ovc1VisualSampleEntryImpl.java.svn-base new file mode 100644 index 0000000..56b8adb --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/Ovc1VisualSampleEntryImpl.java.svn-base @@ -0,0 +1,45 @@ +package com.coremedia.iso.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; + +import java.nio.ByteBuffer; + + +public class Ovc1VisualSampleEntryImpl extends SampleEntry { + private byte[] vc1Content; + public static final String TYPE = "ovc1"; + + + @Override + protected long getContentSize() { + long size = 8; + + for (Box box : boxes) { + size += box.getSize(); + } + size += vc1Content.length; + return size; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + vc1Content = new byte[content.remaining()]; + content.get(vc1Content); + + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + byteBuffer.put(new byte[6]); + IsoTypeWriter.writeUInt16(byteBuffer, getDataReferenceIndex()); + byteBuffer.put(vc1Content); + } + + + protected Ovc1VisualSampleEntryImpl() { + super(TYPE); + } + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SampleEntry.java.svn-base new file mode 100644 index 0000000..a1a5486 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SampleEntry.java.svn-base @@ -0,0 +1,159 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.AbstractBox; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; +import com.googlecode.mp4parser.util.ByteBufferByteChannel; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * Abstract base class for all sample entries. + * + * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry + * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry + * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry + */ +public abstract class SampleEntry extends AbstractBox implements ContainerBox { + + + private int dataReferenceIndex = 1; + protected List<Box> boxes = new LinkedList<Box>(); + private BoxParser boxParser; + + + protected SampleEntry(String type) { + super(type); + } + + public void setType(String type) { + this.type = type; + } + + public int getDataReferenceIndex() { + return dataReferenceIndex; + } + + public void setDataReferenceIndex(int dataReferenceIndex) { + this.dataReferenceIndex = dataReferenceIndex; + } + + public void setBoxes(List<Box> boxes) { + this.boxes = new LinkedList<Box>(boxes); + } + + public void addBox(Box b) { + b.setParent(this); + boxes.add(b); + } + + public boolean removeBox(Box b) { + b.setParent(this); + return boxes.remove(b); + } + + public List<Box> getBoxes() { + return boxes; + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) { + List<T> boxesToBeReturned = new ArrayList<T>(2); + for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()? + if (clazz == boxe.getClass()) { + boxesToBeReturned.add((T) boxe); + } + + if (recursive && boxe instanceof ContainerBox) { + boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive)); + } + } + // Optimize here! Spare object creation work on arrays directly! System.arrayCopy + return boxesToBeReturned; + //return (T[]) boxesToBeReturned.toArray(); + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz) { + return getBoxes(clazz, false); + } + + @Override + public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { + super.parse(readableByteChannel, header, contentSize, boxParser); + this.boxParser = boxParser; + } + + + public void _parseReservedAndDataReferenceIndex(ByteBuffer content) { + content.get(new byte[6]); // ignore 6 reserved bytes; + dataReferenceIndex = IsoTypeReader.readUInt16(content); + } + + public void _parseChildBoxes(ByteBuffer content) { + while (content.remaining() > 8) { + try { + boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + setDeadBytes(content.slice()); + } + + public void _writeReservedAndDataReferenceIndex(ByteBuffer bb) { + bb.put(new byte[6]); + IsoTypeWriter.writeUInt16(bb, dataReferenceIndex); + } + + public void _writeChildBoxes(ByteBuffer bb) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + WritableByteChannel wbc = Channels.newChannel(baos); + try { + for (Box box : boxes) { + box.getBox(wbc); + } + wbc.close(); + } catch (IOException e) { + throw new RuntimeException("Cannot happen. Everything should be in memory and therefore no exceptions."); + } + bb.put(baos.toByteArray()); + } + + public long getNumOfBytesToFirstChild() { + long sizeOfChildren = 0; + for (Box box : boxes) { + sizeOfChildren += box.getSize(); + } + return getSize() - sizeOfChildren; + } + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SubtitleSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SubtitleSampleEntry.java.svn-base new file mode 100644 index 0000000..21d0cc4 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/SubtitleSampleEntry.java.svn-base @@ -0,0 +1,76 @@ +package com.coremedia.iso.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; + +import java.nio.ByteBuffer; + +/** + * Created by IntelliJ IDEA. + * User: magnus + * Date: 2012-03-08 + * Time: 11:36 + * To change this template use File | Settings | File Templates. + */ +public class SubtitleSampleEntry extends SampleEntry { + + public static final String TYPE1 = "stpp"; + + public static final String TYPE_ENCRYPTED = ""; // This is not known! + + private String namespace; + private String schemaLocation; + private String imageMimeType; + + public SubtitleSampleEntry(String type) { + super(type); + } + + @Override + protected long getContentSize() { + long contentSize = 8 + namespace.length() + schemaLocation.length() + imageMimeType.length() + 3; + return contentSize; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + namespace = IsoTypeReader.readString(content); + schemaLocation = IsoTypeReader.readString(content); + imageMimeType = IsoTypeReader.readString(content); + _parseChildBoxes(content); + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUtf8String(byteBuffer, namespace); + IsoTypeWriter.writeUtf8String(byteBuffer, schemaLocation); + IsoTypeWriter.writeUtf8String(byteBuffer, imageMimeType); + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getSchemaLocation() { + return schemaLocation; + } + + public void setSchemaLocation(String schemaLocation) { + this.schemaLocation = schemaLocation; + } + + public String getImageMimeType() { + return imageMimeType; + } + + public void setImageMimeType(String imageMimeType) { + this.imageMimeType = imageMimeType; + } +} + diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/TextSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/TextSampleEntry.java.svn-base new file mode 100644 index 0000000..3a0b83a --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/TextSampleEntry.java.svn-base @@ -0,0 +1,305 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Entry type for timed text samples defined in the timed text specification (ISO/IEC 14496-17). + */ +public class TextSampleEntry extends SampleEntry { + + public static final String TYPE1 = "tx3g"; + + public static final String TYPE_ENCRYPTED = "enct"; + +/* class TextSampleEntry() extends SampleEntry ('tx3g') { + unsigned int(32) displayFlags; + signed int(8) horizontal-justification; + signed int(8) vertical-justification; + unsigned int(8) background-color-rgba[4]; + BoxRecord default-text-box; + StyleRecord default-style; + FontTableBox font-table; + } + */ + + private long displayFlags; // 32 bits + private int horizontalJustification; // 8 bit + private int verticalJustification; // 8 bit + private int[] backgroundColorRgba = new int[4]; // 4 bytes + private BoxRecord boxRecord = new BoxRecord(); + private StyleRecord styleRecord = new StyleRecord(); + + public TextSampleEntry(String type) { + super(type); + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + displayFlags = IsoTypeReader.readUInt32(content); + horizontalJustification = IsoTypeReader.readUInt8(content); + verticalJustification = IsoTypeReader.readUInt8(content); + backgroundColorRgba = new int[4]; + backgroundColorRgba[0] = IsoTypeReader.readUInt8(content); + backgroundColorRgba[1] = IsoTypeReader.readUInt8(content); + backgroundColorRgba[2] = IsoTypeReader.readUInt8(content); + backgroundColorRgba[3] = IsoTypeReader.readUInt8(content); + boxRecord = new BoxRecord(); + boxRecord.parse(content); + + styleRecord = new StyleRecord(); + styleRecord.parse(content); + _parseChildBoxes(content); + } + + + protected long getContentSize() { + long contentSize = 18; + contentSize += boxRecord.getSize(); + contentSize += styleRecord.getSize(); + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + public String toString() { + return "TextSampleEntry"; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUInt32(byteBuffer, displayFlags); + IsoTypeWriter.writeUInt8(byteBuffer, horizontalJustification); + IsoTypeWriter.writeUInt8(byteBuffer, verticalJustification); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[0]); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[1]); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[2]); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[3]); + boxRecord.getContent(byteBuffer); + styleRecord.getContent(byteBuffer); + + _writeChildBoxes(byteBuffer); + } + + public BoxRecord getBoxRecord() { + return boxRecord; + } + + public void setBoxRecord(BoxRecord boxRecord) { + this.boxRecord = boxRecord; + } + + public StyleRecord getStyleRecord() { + return styleRecord; + } + + public void setStyleRecord(StyleRecord styleRecord) { + this.styleRecord = styleRecord; + } + + public boolean isScrollIn() { + return (displayFlags & 0x00000020) == 0x00000020; + } + + public void setScrollIn(boolean scrollIn) { + if (scrollIn) { + displayFlags |= 0x00000020; + } else { + displayFlags &= ~0x00000020; + } + } + + public boolean isScrollOut() { + return (displayFlags & 0x00000040) == 0x00000040; + } + + public void setScrollOut(boolean scrollOutIn) { + if (scrollOutIn) { + displayFlags |= 0x00000040; + } else { + displayFlags &= ~0x00000040; + } + } + + public boolean isScrollDirection() { + return (displayFlags & 0x00000180) == 0x00000180; + } + + public void setScrollDirection(boolean scrollOutIn) { + if (scrollOutIn) { + displayFlags |= 0x00000180; + } else { + displayFlags &= ~0x00000180; + } + } + + public boolean isContinuousKaraoke() { + return (displayFlags & 0x00000800) == 0x00000800; + } + + public void setContinuousKaraoke(boolean continuousKaraoke) { + if (continuousKaraoke) { + displayFlags |= 0x00000800; + } else { + displayFlags &= ~0x00000800; + } + } + + public boolean isWriteTextVertically() { + return (displayFlags & 0x00020000) == 0x00020000; + } + + public void setWriteTextVertically(boolean writeTextVertically) { + if (writeTextVertically) { + displayFlags |= 0x00020000; + } else { + displayFlags &= ~0x00020000; + } + } + + + public boolean isFillTextRegion() { + return (displayFlags & 0x00040000) == 0x00040000; + } + + public void setFillTextRegion(boolean fillTextRegion) { + if (fillTextRegion) { + displayFlags |= 0x00040000; + } else { + displayFlags &= ~0x00040000; + } + } + + + public int getHorizontalJustification() { + return horizontalJustification; + } + + public void setHorizontalJustification(int horizontalJustification) { + this.horizontalJustification = horizontalJustification; + } + + public int getVerticalJustification() { + return verticalJustification; + } + + public void setVerticalJustification(int verticalJustification) { + this.verticalJustification = verticalJustification; + } + + public int[] getBackgroundColorRgba() { + return backgroundColorRgba; + } + + public void setBackgroundColorRgba(int[] backgroundColorRgba) { + this.backgroundColorRgba = backgroundColorRgba; + } + + public static class BoxRecord { + int top; + int left; + int bottom; + int right; + + public void parse(ByteBuffer in) { + top = IsoTypeReader.readUInt16(in); + left = IsoTypeReader.readUInt16(in); + bottom = IsoTypeReader.readUInt16(in); + right = IsoTypeReader.readUInt16(in); + } + + public void getContent(ByteBuffer bb) { + IsoTypeWriter.writeUInt16(bb, top); + IsoTypeWriter.writeUInt16(bb, left); + IsoTypeWriter.writeUInt16(bb, bottom); + IsoTypeWriter.writeUInt16(bb, right); + } + + public int getSize() { + return 8; + } + } + + /* + class FontRecord { + unsigned int(16) font-ID; + unsigned int(8) font-name-length; + unsigned int(8) font[font-name-length]; +} + */ + + + /* + aligned(8) class StyleRecord { + unsigned int(16) startChar; + unsigned int(16) endChar; + unsigned int(16) font-ID; + unsigned int(8) face-style-flags; + unsigned int(8) font-size; + unsigned int(8) text-color-rgba[4]; +} + */ + public static class StyleRecord { + int startChar; + int endChar; + int fontId; + int faceStyleFlags; + int fontSize; + int[] textColor = new int[]{0xff, 0xff, 0xff, 0xff}; + + public void parse(ByteBuffer in) { + startChar = IsoTypeReader.readUInt16(in); + endChar = IsoTypeReader.readUInt16(in); + fontId = IsoTypeReader.readUInt16(in); + faceStyleFlags = IsoTypeReader.readUInt8(in); + fontSize = IsoTypeReader.readUInt8(in); + textColor = new int[4]; + textColor[0] = IsoTypeReader.readUInt8(in); + textColor[1] = IsoTypeReader.readUInt8(in); + textColor[2] = IsoTypeReader.readUInt8(in); + textColor[3] = IsoTypeReader.readUInt8(in); + } + + + public void getContent(ByteBuffer bb) { + IsoTypeWriter.writeUInt16(bb, startChar); + IsoTypeWriter.writeUInt16(bb, endChar); + IsoTypeWriter.writeUInt16(bb, fontId); + IsoTypeWriter.writeUInt8(bb, faceStyleFlags); + IsoTypeWriter.writeUInt8(bb, fontSize); + IsoTypeWriter.writeUInt8(bb, textColor[0]); + IsoTypeWriter.writeUInt8(bb, textColor[1]); + IsoTypeWriter.writeUInt8(bb, textColor[2]); + IsoTypeWriter.writeUInt8(bb, textColor[3]); + } + + public int getSize() { + return 12; + } + } + + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/VisualSampleEntry.java.svn-base b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/VisualSampleEntry.java.svn-base new file mode 100644 index 0000000..407e79f --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/.svn/text-base/VisualSampleEntry.java.svn-base @@ -0,0 +1,213 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.Utf8; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; + +import java.nio.ByteBuffer; + +/** + * Contains information common to all visual tracks. + * <code> + * <pre> + * class VisualSampleEntry(codingname) extends SampleEntry (codingname){ + * unsigned int(16) pre_defined = 0; + * const unsigned int(16) reserved = 0; + * unsigned int(32)[3] pre_defined = 0; + * unsigned int(16) width; + * unsigned int(16) height; + * template unsigned int(32) horizresolution = 0x00480000; // 72 dpi + * template unsigned int(32) vertresolution = 0x00480000; // 72 dpi + * const unsigned int(32) reserved = 0; + * template unsigned int(16) frame_count = 1; + * string[32] compressorname; + * template unsigned int(16) depth = 0x0018; + * int(16) pre_defined = -1; + * }<br> + * </pre> + * </code> + * <p/> + * Format-specific informationis appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2. + */ +public class VisualSampleEntry extends SampleEntry implements ContainerBox { + public static final String TYPE1 = "mp4v"; + public static final String TYPE2 = "s263"; + public static final String TYPE3 = "avc1"; + + + /** + * Identifier for an encrypted video track. + * + * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox + */ + public static final String TYPE_ENCRYPTED = "encv"; + + + private int width; + private int height; + private double horizresolution = 72; + private double vertresolution = 72; + private int frameCount = 1; + private String compressorname; + private int depth = 24; + + private long[] predefined = new long[3]; + + public VisualSampleEntry(String type) { + super(type); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public double getHorizresolution() { + return horizresolution; + } + + public double getVertresolution() { + return vertresolution; + } + + public int getFrameCount() { + return frameCount; + } + + public String getCompressorname() { + return compressorname; + } + + public int getDepth() { + return depth; + } + + public void setCompressorname(String compressorname) { + this.compressorname = compressorname; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setHorizresolution(double horizresolution) { + this.horizresolution = horizresolution; + } + + public void setVertresolution(double vertresolution) { + this.vertresolution = vertresolution; + } + + public void setFrameCount(int frameCount) { + this.frameCount = frameCount; + } + + public void setDepth(int depth) { + this.depth = depth; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + long tmp = IsoTypeReader.readUInt16(content); + assert 0 == tmp : "reserved byte not 0"; + tmp = IsoTypeReader.readUInt16(content); + assert 0 == tmp : "reserved byte not 0"; + predefined[0] = IsoTypeReader.readUInt32(content); // should be zero + predefined[1] = IsoTypeReader.readUInt32(content); // should be zero + predefined[2] = IsoTypeReader.readUInt32(content); // should be zero + width = IsoTypeReader.readUInt16(content); + height = IsoTypeReader.readUInt16(content); + horizresolution = IsoTypeReader.readFixedPoint1616(content); + vertresolution = IsoTypeReader.readFixedPoint1616(content); + tmp = IsoTypeReader.readUInt32(content); + assert 0 == tmp : "reserved byte not 0"; + frameCount = IsoTypeReader.readUInt16(content); + int compressornameDisplayAbleData = IsoTypeReader.readUInt8(content); + if (compressornameDisplayAbleData > 31) { + System.out.println("invalid compressor name displayable data: " + compressornameDisplayAbleData); + compressornameDisplayAbleData = 31; + } + byte[] bytes = new byte[compressornameDisplayAbleData]; + content.get(bytes); + compressorname = Utf8.convert(bytes); + if (compressornameDisplayAbleData < 31) { + byte[] zeros = new byte[31 - compressornameDisplayAbleData]; + content.get(zeros); + //assert Arrays.equals(zeros, new byte[zeros.length]) : "The compressor name length was not filled up with zeros"; + } + depth = IsoTypeReader.readUInt16(content); + tmp = IsoTypeReader.readUInt16(content); + assert 0xFFFF == tmp; + + _parseChildBoxes(content); + + } + + + protected long getContentSize() { + long contentSize = 78; + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUInt16(byteBuffer, 0); + IsoTypeWriter.writeUInt16(byteBuffer, 0); + IsoTypeWriter.writeUInt32(byteBuffer, predefined[0]); + IsoTypeWriter.writeUInt32(byteBuffer, predefined[1]); + IsoTypeWriter.writeUInt32(byteBuffer, predefined[2]); + + IsoTypeWriter.writeUInt16(byteBuffer, getWidth()); + IsoTypeWriter.writeUInt16(byteBuffer, getHeight()); + + IsoTypeWriter.writeFixedPont1616(byteBuffer, getHorizresolution()); + IsoTypeWriter.writeFixedPont1616(byteBuffer, getVertresolution()); + + + IsoTypeWriter.writeUInt32(byteBuffer, 0); + IsoTypeWriter.writeUInt16(byteBuffer, getFrameCount()); + IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(getCompressorname())); + byteBuffer.put(Utf8.convert(getCompressorname())); + int a = Utf8.utf8StringLengthInBytes(getCompressorname()); + while (a < 31) { + a++; + byteBuffer.put((byte) 0); + } + IsoTypeWriter.writeUInt16(byteBuffer, getDepth()); + IsoTypeWriter.writeUInt16(byteBuffer, 0xFFFF); + + _writeChildBoxes(byteBuffer); + + } + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java new file mode 100644 index 0000000..f69de7b --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AmrSpecificBox.java @@ -0,0 +1,101 @@ +/* + * 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.boxes.sampleentry; + + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.AbstractBox; + +import java.nio.ByteBuffer; + +/** + * AMR audio format specific subbox of an audio sample entry. + * + * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry + */ +public class AmrSpecificBox extends AbstractBox { + public static final String TYPE = "damr"; + + private String vendor; + private int decoderVersion; + private int modeSet; + private int modeChangePeriod; + private int framesPerSample; + + public AmrSpecificBox() { + super(TYPE); + } + + public String getVendor() { + return vendor; + } + + public int getDecoderVersion() { + return decoderVersion; + } + + public int getModeSet() { + return modeSet; + } + + public int getModeChangePeriod() { + return modeChangePeriod; + } + + public int getFramesPerSample() { + return framesPerSample; + } + + protected long getContentSize() { + return 9; + } + + @Override + public void _parseDetails(ByteBuffer content) { + byte[] v = new byte[4]; + content.get(v); + vendor = IsoFile.bytesToFourCC(v); + + decoderVersion = IsoTypeReader.readUInt8(content); + modeSet = IsoTypeReader.readUInt16(content); + modeChangePeriod = IsoTypeReader.readUInt8(content); + framesPerSample = IsoTypeReader.readUInt8(content); + + } + + + public void getContent(ByteBuffer byteBuffer) { + byteBuffer.put(IsoFile.fourCCtoBytes(vendor)); + IsoTypeWriter.writeUInt8(byteBuffer, decoderVersion); + IsoTypeWriter.writeUInt16(byteBuffer, modeSet); + IsoTypeWriter.writeUInt8(byteBuffer, modeChangePeriod); + IsoTypeWriter.writeUInt8(byteBuffer, framesPerSample); + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("AmrSpecificBox[vendor=").append(getVendor()); + buffer.append(";decoderVersion=").append(getDecoderVersion()); + buffer.append(";modeSet=").append(getModeSet()); + buffer.append(";modeChangePeriod=").append(getModeChangePeriod()); + buffer.append(";framesPerSample=").append(getFramesPerSample()); + buffer.append("]"); + return buffer.toString(); + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java new file mode 100644 index 0000000..69aeb79 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/AudioSampleEntry.java @@ -0,0 +1,278 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; + +import java.nio.ByteBuffer; + +/** + * Contains basic information about the audio samples in this track. Format-specific information + * is appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2. + */ +public class AudioSampleEntry extends SampleEntry implements ContainerBox { + + public static final String TYPE1 = "samr"; + public static final String TYPE2 = "sawb"; + public static final String TYPE3 = "mp4a"; + public static final String TYPE4 = "drms"; + public static final String TYPE5 = "alac"; + public static final String TYPE7 = "owma"; + public static final String TYPE8 = "ac-3"; /* ETSI TS 102 366 1.2.1 Annex F */ + public static final String TYPE9 = "ec-3"; /* ETSI TS 102 366 1.2.1 Annex F */ + public static final String TYPE10 = "mlpa"; + public static final String TYPE11 = "dtsl"; + public static final String TYPE12 = "dtsh"; + public static final String TYPE13 = "dtse"; + + /** + * Identifier for an encrypted audio track. + * + * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox + */ + public static final String TYPE_ENCRYPTED = "enca"; + + private int channelCount; + private int sampleSize; + private long sampleRate; + private int soundVersion; + private int compressionId; + private int packetSize; + private long samplesPerPacket; + private long bytesPerPacket; + private long bytesPerFrame; + private long bytesPerSample; + + private int reserved1; + private long reserved2; + private byte[] soundVersion2Data; + private BoxParser boxParser; + + public AudioSampleEntry(String type) { + super(type); + } + + public int getChannelCount() { + return channelCount; + } + + public int getSampleSize() { + return sampleSize; + } + + public long getSampleRate() { + return sampleRate; + } + + public int getSoundVersion() { + return soundVersion; + } + + public int getCompressionId() { + return compressionId; + } + + public int getPacketSize() { + return packetSize; + } + + public long getSamplesPerPacket() { + return samplesPerPacket; + } + + public long getBytesPerPacket() { + return bytesPerPacket; + } + + public long getBytesPerFrame() { + return bytesPerFrame; + } + + public long getBytesPerSample() { + return bytesPerSample; + } + + public byte[] getSoundVersion2Data() { + return soundVersion2Data; + } + + public int getReserved1() { + return reserved1; + } + + public long getReserved2() { + return reserved2; + } + + public void setChannelCount(int channelCount) { + this.channelCount = channelCount; + } + + public void setSampleSize(int sampleSize) { + this.sampleSize = sampleSize; + } + + public void setSampleRate(long sampleRate) { + this.sampleRate = sampleRate; + } + + public void setSoundVersion(int soundVersion) { + this.soundVersion = soundVersion; + } + + public void setCompressionId(int compressionId) { + this.compressionId = compressionId; + } + + public void setPacketSize(int packetSize) { + this.packetSize = packetSize; + } + + public void setSamplesPerPacket(long samplesPerPacket) { + this.samplesPerPacket = samplesPerPacket; + } + + public void setBytesPerPacket(long bytesPerPacket) { + this.bytesPerPacket = bytesPerPacket; + } + + public void setBytesPerFrame(long bytesPerFrame) { + this.bytesPerFrame = bytesPerFrame; + } + + public void setBytesPerSample(long bytesPerSample) { + this.bytesPerSample = bytesPerSample; + } + + public void setReserved1(int reserved1) { + this.reserved1 = reserved1; + } + + public void setReserved2(long reserved2) { + this.reserved2 = reserved2; + } + + public void setSoundVersion2Data(byte[] soundVersion2Data) { + this.soundVersion2Data = soundVersion2Data; + } + + public void setBoxParser(BoxParser boxParser) { + this.boxParser = boxParser; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); //parses the six reserved bytes and dataReferenceIndex + // 8 bytes already parsed + //reserved bits - used by qt + soundVersion = IsoTypeReader.readUInt16(content); + + //reserved + reserved1 = IsoTypeReader.readUInt16(content); + reserved2 = IsoTypeReader.readUInt32(content); + + channelCount = IsoTypeReader.readUInt16(content); + sampleSize = IsoTypeReader.readUInt16(content); + //reserved bits - used by qt + compressionId = IsoTypeReader.readUInt16(content); + //reserved bits - used by qt + packetSize = IsoTypeReader.readUInt16(content); + //sampleRate = in.readFixedPoint1616(); + sampleRate = IsoTypeReader.readUInt32(content); + if (!type.equals("mlpa")) { + sampleRate = sampleRate >>> 16; + } + + //more qt stuff - see http://mp4v2.googlecode.com/svn-history/r388/trunk/src/atom_sound.cpp + if (soundVersion > 0) { + samplesPerPacket = IsoTypeReader.readUInt32(content); + bytesPerPacket = IsoTypeReader.readUInt32(content); + bytesPerFrame = IsoTypeReader.readUInt32(content); + bytesPerSample = IsoTypeReader.readUInt32(content); + } + if (soundVersion == 2) { + + soundVersion2Data = new byte[20]; + content.get(20); + } + _parseChildBoxes(content); + + } + + + @Override + protected long getContentSize() { + long contentSize = 28; + contentSize += soundVersion > 0 ? 16 : 0; + contentSize += soundVersion == 2 ? 20 : 0; + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + @Override + public String toString() { + return "AudioSampleEntry{" + + "bytesPerSample=" + bytesPerSample + + ", bytesPerFrame=" + bytesPerFrame + + ", bytesPerPacket=" + bytesPerPacket + + ", samplesPerPacket=" + samplesPerPacket + + ", packetSize=" + packetSize + + ", compressionId=" + compressionId + + ", soundVersion=" + soundVersion + + ", sampleRate=" + sampleRate + + ", sampleSize=" + sampleSize + + ", channelCount=" + channelCount + + ", boxes=" + getBoxes() + + '}'; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUInt16(byteBuffer, soundVersion); + IsoTypeWriter.writeUInt16(byteBuffer, reserved1); + IsoTypeWriter.writeUInt32(byteBuffer, reserved2); + IsoTypeWriter.writeUInt16(byteBuffer, channelCount); + IsoTypeWriter.writeUInt16(byteBuffer, sampleSize); + IsoTypeWriter.writeUInt16(byteBuffer, compressionId); + IsoTypeWriter.writeUInt16(byteBuffer, packetSize); + //isos.writeFixedPont1616(getSampleRate()); + if (type.equals("mlpa")) { + IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate()); + } else { + IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate() << 16); + } + + if (soundVersion > 0) { + IsoTypeWriter.writeUInt32(byteBuffer, samplesPerPacket); + IsoTypeWriter.writeUInt32(byteBuffer, bytesPerPacket); + IsoTypeWriter.writeUInt32(byteBuffer, bytesPerFrame); + IsoTypeWriter.writeUInt32(byteBuffer, bytesPerSample); + } + + if (soundVersion == 2) { + byteBuffer.put(soundVersion2Data); + } + _writeChildBoxes(byteBuffer); + } +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java new file mode 100644 index 0000000..e4a33dc --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/MpegSampleEntry.java @@ -0,0 +1,43 @@ +package com.coremedia.iso.boxes.sampleentry;
+
+import com.coremedia.iso.BoxParser;
+import com.coremedia.iso.boxes.Box;
+import com.coremedia.iso.boxes.ContainerBox;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+public class MpegSampleEntry extends SampleEntry implements ContainerBox {
+
+ private BoxParser boxParser;
+
+ public MpegSampleEntry(String type) {
+ super(type);
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ _parseReservedAndDataReferenceIndex(content);
+ _parseChildBoxes(content);
+
+ }
+
+ @Override
+ protected long getContentSize() {
+ long contentSize = 8;
+ for (Box boxe : boxes) {
+ contentSize += boxe.getSize();
+ }
+ return contentSize;
+ }
+
+ public String toString() {
+ return "MpegSampleEntry" + Arrays.asList(getBoxes());
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ _writeReservedAndDataReferenceIndex(byteBuffer);
+ _writeChildBoxes(byteBuffer);
+ }
+}
diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java new file mode 100644 index 0000000..56b8adb --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/Ovc1VisualSampleEntryImpl.java @@ -0,0 +1,45 @@ +package com.coremedia.iso.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; + +import java.nio.ByteBuffer; + + +public class Ovc1VisualSampleEntryImpl extends SampleEntry { + private byte[] vc1Content; + public static final String TYPE = "ovc1"; + + + @Override + protected long getContentSize() { + long size = 8; + + for (Box box : boxes) { + size += box.getSize(); + } + size += vc1Content.length; + return size; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + vc1Content = new byte[content.remaining()]; + content.get(vc1Content); + + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + byteBuffer.put(new byte[6]); + IsoTypeWriter.writeUInt16(byteBuffer, getDataReferenceIndex()); + byteBuffer.put(vc1Content); + } + + + protected Ovc1VisualSampleEntryImpl() { + super(TYPE); + } + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java new file mode 100644 index 0000000..a1a5486 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SampleEntry.java @@ -0,0 +1,159 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.AbstractBox; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; +import com.googlecode.mp4parser.util.ByteBufferByteChannel; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * Abstract base class for all sample entries. + * + * @see com.coremedia.iso.boxes.sampleentry.AudioSampleEntry + * @see com.coremedia.iso.boxes.sampleentry.VisualSampleEntry + * @see com.coremedia.iso.boxes.sampleentry.TextSampleEntry + */ +public abstract class SampleEntry extends AbstractBox implements ContainerBox { + + + private int dataReferenceIndex = 1; + protected List<Box> boxes = new LinkedList<Box>(); + private BoxParser boxParser; + + + protected SampleEntry(String type) { + super(type); + } + + public void setType(String type) { + this.type = type; + } + + public int getDataReferenceIndex() { + return dataReferenceIndex; + } + + public void setDataReferenceIndex(int dataReferenceIndex) { + this.dataReferenceIndex = dataReferenceIndex; + } + + public void setBoxes(List<Box> boxes) { + this.boxes = new LinkedList<Box>(boxes); + } + + public void addBox(Box b) { + b.setParent(this); + boxes.add(b); + } + + public boolean removeBox(Box b) { + b.setParent(this); + return boxes.remove(b); + } + + public List<Box> getBoxes() { + return boxes; + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) { + List<T> boxesToBeReturned = new ArrayList<T>(2); + for (Box boxe : boxes) { //clazz.isInstance(boxe) / clazz == boxe.getClass()? + if (clazz == boxe.getClass()) { + boxesToBeReturned.add((T) boxe); + } + + if (recursive && boxe instanceof ContainerBox) { + boxesToBeReturned.addAll(((ContainerBox) boxe).getBoxes(clazz, recursive)); + } + } + // Optimize here! Spare object creation work on arrays directly! System.arrayCopy + return boxesToBeReturned; + //return (T[]) boxesToBeReturned.toArray(); + } + + @SuppressWarnings("unchecked") + public <T extends Box> List<T> getBoxes(Class<T> clazz) { + return getBoxes(clazz, false); + } + + @Override + public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { + super.parse(readableByteChannel, header, contentSize, boxParser); + this.boxParser = boxParser; + } + + + public void _parseReservedAndDataReferenceIndex(ByteBuffer content) { + content.get(new byte[6]); // ignore 6 reserved bytes; + dataReferenceIndex = IsoTypeReader.readUInt16(content); + } + + public void _parseChildBoxes(ByteBuffer content) { + while (content.remaining() > 8) { + try { + boxes.add(boxParser.parseBox(new ByteBufferByteChannel(content), this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + setDeadBytes(content.slice()); + } + + public void _writeReservedAndDataReferenceIndex(ByteBuffer bb) { + bb.put(new byte[6]); + IsoTypeWriter.writeUInt16(bb, dataReferenceIndex); + } + + public void _writeChildBoxes(ByteBuffer bb) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + WritableByteChannel wbc = Channels.newChannel(baos); + try { + for (Box box : boxes) { + box.getBox(wbc); + } + wbc.close(); + } catch (IOException e) { + throw new RuntimeException("Cannot happen. Everything should be in memory and therefore no exceptions."); + } + bb.put(baos.toByteArray()); + } + + public long getNumOfBytesToFirstChild() { + long sizeOfChildren = 0; + for (Box box : boxes) { + sizeOfChildren += box.getSize(); + } + return getSize() - sizeOfChildren; + } + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java new file mode 100644 index 0000000..21d0cc4 --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/SubtitleSampleEntry.java @@ -0,0 +1,76 @@ +package com.coremedia.iso.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; + +import java.nio.ByteBuffer; + +/** + * Created by IntelliJ IDEA. + * User: magnus + * Date: 2012-03-08 + * Time: 11:36 + * To change this template use File | Settings | File Templates. + */ +public class SubtitleSampleEntry extends SampleEntry { + + public static final String TYPE1 = "stpp"; + + public static final String TYPE_ENCRYPTED = ""; // This is not known! + + private String namespace; + private String schemaLocation; + private String imageMimeType; + + public SubtitleSampleEntry(String type) { + super(type); + } + + @Override + protected long getContentSize() { + long contentSize = 8 + namespace.length() + schemaLocation.length() + imageMimeType.length() + 3; + return contentSize; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + namespace = IsoTypeReader.readString(content); + schemaLocation = IsoTypeReader.readString(content); + imageMimeType = IsoTypeReader.readString(content); + _parseChildBoxes(content); + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUtf8String(byteBuffer, namespace); + IsoTypeWriter.writeUtf8String(byteBuffer, schemaLocation); + IsoTypeWriter.writeUtf8String(byteBuffer, imageMimeType); + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getSchemaLocation() { + return schemaLocation; + } + + public void setSchemaLocation(String schemaLocation) { + this.schemaLocation = schemaLocation; + } + + public String getImageMimeType() { + return imageMimeType; + } + + public void setImageMimeType(String imageMimeType) { + this.imageMimeType = imageMimeType; + } +} + diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java new file mode 100644 index 0000000..3a0b83a --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/TextSampleEntry.java @@ -0,0 +1,305 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Entry type for timed text samples defined in the timed text specification (ISO/IEC 14496-17). + */ +public class TextSampleEntry extends SampleEntry { + + public static final String TYPE1 = "tx3g"; + + public static final String TYPE_ENCRYPTED = "enct"; + +/* class TextSampleEntry() extends SampleEntry ('tx3g') { + unsigned int(32) displayFlags; + signed int(8) horizontal-justification; + signed int(8) vertical-justification; + unsigned int(8) background-color-rgba[4]; + BoxRecord default-text-box; + StyleRecord default-style; + FontTableBox font-table; + } + */ + + private long displayFlags; // 32 bits + private int horizontalJustification; // 8 bit + private int verticalJustification; // 8 bit + private int[] backgroundColorRgba = new int[4]; // 4 bytes + private BoxRecord boxRecord = new BoxRecord(); + private StyleRecord styleRecord = new StyleRecord(); + + public TextSampleEntry(String type) { + super(type); + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + displayFlags = IsoTypeReader.readUInt32(content); + horizontalJustification = IsoTypeReader.readUInt8(content); + verticalJustification = IsoTypeReader.readUInt8(content); + backgroundColorRgba = new int[4]; + backgroundColorRgba[0] = IsoTypeReader.readUInt8(content); + backgroundColorRgba[1] = IsoTypeReader.readUInt8(content); + backgroundColorRgba[2] = IsoTypeReader.readUInt8(content); + backgroundColorRgba[3] = IsoTypeReader.readUInt8(content); + boxRecord = new BoxRecord(); + boxRecord.parse(content); + + styleRecord = new StyleRecord(); + styleRecord.parse(content); + _parseChildBoxes(content); + } + + + protected long getContentSize() { + long contentSize = 18; + contentSize += boxRecord.getSize(); + contentSize += styleRecord.getSize(); + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + public String toString() { + return "TextSampleEntry"; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUInt32(byteBuffer, displayFlags); + IsoTypeWriter.writeUInt8(byteBuffer, horizontalJustification); + IsoTypeWriter.writeUInt8(byteBuffer, verticalJustification); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[0]); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[1]); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[2]); + IsoTypeWriter.writeUInt8(byteBuffer, backgroundColorRgba[3]); + boxRecord.getContent(byteBuffer); + styleRecord.getContent(byteBuffer); + + _writeChildBoxes(byteBuffer); + } + + public BoxRecord getBoxRecord() { + return boxRecord; + } + + public void setBoxRecord(BoxRecord boxRecord) { + this.boxRecord = boxRecord; + } + + public StyleRecord getStyleRecord() { + return styleRecord; + } + + public void setStyleRecord(StyleRecord styleRecord) { + this.styleRecord = styleRecord; + } + + public boolean isScrollIn() { + return (displayFlags & 0x00000020) == 0x00000020; + } + + public void setScrollIn(boolean scrollIn) { + if (scrollIn) { + displayFlags |= 0x00000020; + } else { + displayFlags &= ~0x00000020; + } + } + + public boolean isScrollOut() { + return (displayFlags & 0x00000040) == 0x00000040; + } + + public void setScrollOut(boolean scrollOutIn) { + if (scrollOutIn) { + displayFlags |= 0x00000040; + } else { + displayFlags &= ~0x00000040; + } + } + + public boolean isScrollDirection() { + return (displayFlags & 0x00000180) == 0x00000180; + } + + public void setScrollDirection(boolean scrollOutIn) { + if (scrollOutIn) { + displayFlags |= 0x00000180; + } else { + displayFlags &= ~0x00000180; + } + } + + public boolean isContinuousKaraoke() { + return (displayFlags & 0x00000800) == 0x00000800; + } + + public void setContinuousKaraoke(boolean continuousKaraoke) { + if (continuousKaraoke) { + displayFlags |= 0x00000800; + } else { + displayFlags &= ~0x00000800; + } + } + + public boolean isWriteTextVertically() { + return (displayFlags & 0x00020000) == 0x00020000; + } + + public void setWriteTextVertically(boolean writeTextVertically) { + if (writeTextVertically) { + displayFlags |= 0x00020000; + } else { + displayFlags &= ~0x00020000; + } + } + + + public boolean isFillTextRegion() { + return (displayFlags & 0x00040000) == 0x00040000; + } + + public void setFillTextRegion(boolean fillTextRegion) { + if (fillTextRegion) { + displayFlags |= 0x00040000; + } else { + displayFlags &= ~0x00040000; + } + } + + + public int getHorizontalJustification() { + return horizontalJustification; + } + + public void setHorizontalJustification(int horizontalJustification) { + this.horizontalJustification = horizontalJustification; + } + + public int getVerticalJustification() { + return verticalJustification; + } + + public void setVerticalJustification(int verticalJustification) { + this.verticalJustification = verticalJustification; + } + + public int[] getBackgroundColorRgba() { + return backgroundColorRgba; + } + + public void setBackgroundColorRgba(int[] backgroundColorRgba) { + this.backgroundColorRgba = backgroundColorRgba; + } + + public static class BoxRecord { + int top; + int left; + int bottom; + int right; + + public void parse(ByteBuffer in) { + top = IsoTypeReader.readUInt16(in); + left = IsoTypeReader.readUInt16(in); + bottom = IsoTypeReader.readUInt16(in); + right = IsoTypeReader.readUInt16(in); + } + + public void getContent(ByteBuffer bb) { + IsoTypeWriter.writeUInt16(bb, top); + IsoTypeWriter.writeUInt16(bb, left); + IsoTypeWriter.writeUInt16(bb, bottom); + IsoTypeWriter.writeUInt16(bb, right); + } + + public int getSize() { + return 8; + } + } + + /* + class FontRecord { + unsigned int(16) font-ID; + unsigned int(8) font-name-length; + unsigned int(8) font[font-name-length]; +} + */ + + + /* + aligned(8) class StyleRecord { + unsigned int(16) startChar; + unsigned int(16) endChar; + unsigned int(16) font-ID; + unsigned int(8) face-style-flags; + unsigned int(8) font-size; + unsigned int(8) text-color-rgba[4]; +} + */ + public static class StyleRecord { + int startChar; + int endChar; + int fontId; + int faceStyleFlags; + int fontSize; + int[] textColor = new int[]{0xff, 0xff, 0xff, 0xff}; + + public void parse(ByteBuffer in) { + startChar = IsoTypeReader.readUInt16(in); + endChar = IsoTypeReader.readUInt16(in); + fontId = IsoTypeReader.readUInt16(in); + faceStyleFlags = IsoTypeReader.readUInt8(in); + fontSize = IsoTypeReader.readUInt8(in); + textColor = new int[4]; + textColor[0] = IsoTypeReader.readUInt8(in); + textColor[1] = IsoTypeReader.readUInt8(in); + textColor[2] = IsoTypeReader.readUInt8(in); + textColor[3] = IsoTypeReader.readUInt8(in); + } + + + public void getContent(ByteBuffer bb) { + IsoTypeWriter.writeUInt16(bb, startChar); + IsoTypeWriter.writeUInt16(bb, endChar); + IsoTypeWriter.writeUInt16(bb, fontId); + IsoTypeWriter.writeUInt8(bb, faceStyleFlags); + IsoTypeWriter.writeUInt8(bb, fontSize); + IsoTypeWriter.writeUInt8(bb, textColor[0]); + IsoTypeWriter.writeUInt8(bb, textColor[1]); + IsoTypeWriter.writeUInt8(bb, textColor[2]); + IsoTypeWriter.writeUInt8(bb, textColor[3]); + } + + public int getSize() { + return 12; + } + } + + +} diff --git a/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java new file mode 100644 index 0000000..407e79f --- /dev/null +++ b/isoparser/src/main/java/com/coremedia/iso/boxes/sampleentry/VisualSampleEntry.java @@ -0,0 +1,213 @@ +/* + * 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.boxes.sampleentry; + +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.Utf8; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.ContainerBox; + +import java.nio.ByteBuffer; + +/** + * Contains information common to all visual tracks. + * <code> + * <pre> + * class VisualSampleEntry(codingname) extends SampleEntry (codingname){ + * unsigned int(16) pre_defined = 0; + * const unsigned int(16) reserved = 0; + * unsigned int(32)[3] pre_defined = 0; + * unsigned int(16) width; + * unsigned int(16) height; + * template unsigned int(32) horizresolution = 0x00480000; // 72 dpi + * template unsigned int(32) vertresolution = 0x00480000; // 72 dpi + * const unsigned int(32) reserved = 0; + * template unsigned int(16) frame_count = 1; + * string[32] compressorname; + * template unsigned int(16) depth = 0x0018; + * int(16) pre_defined = -1; + * }<br> + * </pre> + * </code> + * <p/> + * Format-specific informationis appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2. + */ +public class VisualSampleEntry extends SampleEntry implements ContainerBox { + public static final String TYPE1 = "mp4v"; + public static final String TYPE2 = "s263"; + public static final String TYPE3 = "avc1"; + + + /** + * Identifier for an encrypted video track. + * + * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox + */ + public static final String TYPE_ENCRYPTED = "encv"; + + + private int width; + private int height; + private double horizresolution = 72; + private double vertresolution = 72; + private int frameCount = 1; + private String compressorname; + private int depth = 24; + + private long[] predefined = new long[3]; + + public VisualSampleEntry(String type) { + super(type); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public double getHorizresolution() { + return horizresolution; + } + + public double getVertresolution() { + return vertresolution; + } + + public int getFrameCount() { + return frameCount; + } + + public String getCompressorname() { + return compressorname; + } + + public int getDepth() { + return depth; + } + + public void setCompressorname(String compressorname) { + this.compressorname = compressorname; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setHorizresolution(double horizresolution) { + this.horizresolution = horizresolution; + } + + public void setVertresolution(double vertresolution) { + this.vertresolution = vertresolution; + } + + public void setFrameCount(int frameCount) { + this.frameCount = frameCount; + } + + public void setDepth(int depth) { + this.depth = depth; + } + + @Override + public void _parseDetails(ByteBuffer content) { + _parseReservedAndDataReferenceIndex(content); + long tmp = IsoTypeReader.readUInt16(content); + assert 0 == tmp : "reserved byte not 0"; + tmp = IsoTypeReader.readUInt16(content); + assert 0 == tmp : "reserved byte not 0"; + predefined[0] = IsoTypeReader.readUInt32(content); // should be zero + predefined[1] = IsoTypeReader.readUInt32(content); // should be zero + predefined[2] = IsoTypeReader.readUInt32(content); // should be zero + width = IsoTypeReader.readUInt16(content); + height = IsoTypeReader.readUInt16(content); + horizresolution = IsoTypeReader.readFixedPoint1616(content); + vertresolution = IsoTypeReader.readFixedPoint1616(content); + tmp = IsoTypeReader.readUInt32(content); + assert 0 == tmp : "reserved byte not 0"; + frameCount = IsoTypeReader.readUInt16(content); + int compressornameDisplayAbleData = IsoTypeReader.readUInt8(content); + if (compressornameDisplayAbleData > 31) { + System.out.println("invalid compressor name displayable data: " + compressornameDisplayAbleData); + compressornameDisplayAbleData = 31; + } + byte[] bytes = new byte[compressornameDisplayAbleData]; + content.get(bytes); + compressorname = Utf8.convert(bytes); + if (compressornameDisplayAbleData < 31) { + byte[] zeros = new byte[31 - compressornameDisplayAbleData]; + content.get(zeros); + //assert Arrays.equals(zeros, new byte[zeros.length]) : "The compressor name length was not filled up with zeros"; + } + depth = IsoTypeReader.readUInt16(content); + tmp = IsoTypeReader.readUInt16(content); + assert 0xFFFF == tmp; + + _parseChildBoxes(content); + + } + + + protected long getContentSize() { + long contentSize = 78; + for (Box boxe : boxes) { + contentSize += boxe.getSize(); + } + return contentSize; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + _writeReservedAndDataReferenceIndex(byteBuffer); + IsoTypeWriter.writeUInt16(byteBuffer, 0); + IsoTypeWriter.writeUInt16(byteBuffer, 0); + IsoTypeWriter.writeUInt32(byteBuffer, predefined[0]); + IsoTypeWriter.writeUInt32(byteBuffer, predefined[1]); + IsoTypeWriter.writeUInt32(byteBuffer, predefined[2]); + + IsoTypeWriter.writeUInt16(byteBuffer, getWidth()); + IsoTypeWriter.writeUInt16(byteBuffer, getHeight()); + + IsoTypeWriter.writeFixedPont1616(byteBuffer, getHorizresolution()); + IsoTypeWriter.writeFixedPont1616(byteBuffer, getVertresolution()); + + + IsoTypeWriter.writeUInt32(byteBuffer, 0); + IsoTypeWriter.writeUInt16(byteBuffer, getFrameCount()); + IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(getCompressorname())); + byteBuffer.put(Utf8.convert(getCompressorname())); + int a = Utf8.utf8StringLengthInBytes(getCompressorname()); + while (a < 31) { + a++; + byteBuffer.put((byte) 0); + } + IsoTypeWriter.writeUInt16(byteBuffer, getDepth()); + IsoTypeWriter.writeUInt16(byteBuffer, 0xFFFF); + + _writeChildBoxes(byteBuffer); + + } + +} |