diff options
Diffstat (limited to 'isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff')
16 files changed, 1775 insertions, 0 deletions
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/all-wcprops b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/all-wcprops new file mode 100644 index 0000000..73d7e4e --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/all-wcprops @@ -0,0 +1,47 @@ +K 25 +svn:wc:ra_dav:version-url +V 83 +/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff +END +PlayReadyHeader.java +K 25 +svn:wc:ra_dav:version-url +V 104 +/svn/!svn/ver/525/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java +END +ProtectionSpecificHeader.java +K 25 +svn:wc:ra_dav:version-url +V 113 +/svn/!svn/ver/527/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java +END +UuidBasedProtectionSystemSpecificHeaderBox.java +K 25 +svn:wc:ra_dav:version-url +V 131 +/svn/!svn/ver/616/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java +END +PiffSampleEncryptionBox.java +K 25 +svn:wc:ra_dav:version-url +V 112 +/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java +END +TfrfBox.java +K 25 +svn:wc:ra_dav:version-url +V 96 +/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java +END +PiffTrackEncryptionBox.java +K 25 +svn:wc:ra_dav:version-url +V 111 +/svn/!svn/ver/377/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java +END +TfxdBox.java +K 25 +svn:wc:ra_dav:version-url +V 96 +/svn/!svn/ver/507/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java +END diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/entries b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/entries new file mode 100644 index 0000000..f869342 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/entries @@ -0,0 +1,266 @@ +10 + +dir +778 +http://mp4parser.googlecode.com/svn/trunk/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff +http://mp4parser.googlecode.com/svn + + + +2012-05-17T09:04:15.805545Z +616 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + +7decde4b-c250-0410-a0da-51896bc88be6 + +PlayReadyHeader.java +file + + + + +2012-09-14T17:27:50.797223Z +414299d2fe72802bfdba588cd197cc8d +2012-04-25T19:24:04.485529Z +525 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +8099 + +ProtectionSpecificHeader.java +file + + + + +2012-09-14T17:27:50.797223Z +206bcc330dd14e88a9b36dbdab4b5676 +2012-04-25T23:16:14.370289Z +527 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +2339 + +UuidBasedProtectionSystemSpecificHeaderBox.java +file + + + + +2012-09-14T17:27:50.797223Z +bee6a83aa218637d445d55bb317bf1f0 +2012-05-17T09:04:15.805545Z +616 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +3419 + +PiffSampleEncryptionBox.java +file + + + + +2012-09-14T17:27:50.797223Z +e8e29f48bf61c02cd75f62b654664a1d +2012-03-05T23:28:24.666173Z +377 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +1187 + +TfrfBox.java +file + + + + +2012-09-14T17:27:50.797223Z +87a71e91a262d3294bb9b1e4959b0b99 +2012-04-21T22:05:38.425329Z +507 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +4379 + +PiffTrackEncryptionBox.java +file + + + + +2012-09-14T17:27:50.797223Z +f412ae4506ee42fea327a2b274c0602d +2012-03-05T23:28:24.666173Z +377 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +854 + +TfxdBox.java +file + + + + +2012-09-14T17:27:50.807223Z +d98ba32db0ee574c4130985dee95179a +2012-04-21T22:05:38.425329Z +507 +Sebastian.Annies@gmail.com + + + + + + + + + + + + + + + + + + + + + +2998 + diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffSampleEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffSampleEncryptionBox.java.svn-base new file mode 100644 index 0000000..da3512d --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffSampleEncryptionBox.java.svn-base @@ -0,0 +1,45 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.googlecode.mp4parser.boxes.AbstractSampleEncryptionBox; + +/** + * <pre> + * aligned(8) class SampleEncryptionBox extends FullBox(‘uuid’, extended_type= 0xA2394F52-5A9B-4f14-A244-6C427C648DF4, version=0, flags=0) + * { + * if (flags & 0x000001) + * { + * unsigned int(24) AlgorithmID; + * unsigned int(8) IV_size; + * unsigned int(8)[16] KID; + * } + * unsigned int (32) sample_count; + * { + * unsigned int(IV_size) InitializationVector; + * if (flags & 0x000002) + * { + * unsigned int(16) NumberOfEntries; + * { + * unsigned int(16) BytesOfClearData; + * unsigned int(32) BytesOfEncryptedData; + * } [ NumberOfEntries] + * } + * }[ sample_count ] + * } + * </pre> + */ +public class PiffSampleEncryptionBox extends AbstractSampleEncryptionBox { + + /** + * Creates a AbstractSampleEncryptionBox for non-h264 tracks. + */ + public PiffSampleEncryptionBox() { + super("uuid"); + + } + + @Override + public byte[] getUserType() { + return new byte[]{(byte) 0xA2, 0x39, 0x4F, 0x52, 0x5A, (byte) 0x9B, 0x4f, 0x14, (byte) 0xA2, 0x44, 0x6C, 0x42, 0x7C, 0x64, (byte) 0x8D, (byte) 0xF4}; + } + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffTrackEncryptionBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffTrackEncryptionBox.java.svn-base new file mode 100644 index 0000000..f92c0f3 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffTrackEncryptionBox.java.svn-base @@ -0,0 +1,34 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.googlecode.mp4parser.boxes.AbstractTrackEncryptionBox; + +/** + * aligned(8) class TrackEncryptionBox extends FullBox(‘uuid’, + * extended_type=0x8974dbce-7be7-4c51-84f9-7148f9882554, version=0, + * flags=0) + * { + * unsigned int(24) default_AlgorithmID; + * unsigned int(8) default_IV_size; + * unsigned int(8)[16] default_KID; + * } + */ +public class PiffTrackEncryptionBox extends AbstractTrackEncryptionBox { + + + public PiffTrackEncryptionBox() { + super("uuid"); + } + + @Override + public byte[] getUserType() { + return new byte[]{(byte) 0x89, 0x74, (byte) 0xdb, (byte) 0xce, 0x7b, (byte) 0xe7, 0x4c, 0x51, + (byte) 0x84, (byte) 0xf9, 0x71, 0x48, (byte) 0xf9, (byte) 0x88, 0x25, 0x54}; + } + + @Override + public int getFlags() { + return 0; + } + + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PlayReadyHeader.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PlayReadyHeader.java.svn-base new file mode 100644 index 0000000..74246d0 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PlayReadyHeader.java.svn-base @@ -0,0 +1,253 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.util.Path; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.7. ASF GUIDs + * <p/> + * <p/> + * ASF_Protection_System_Identifier_Object + * 9A04F079-9840-4286-AB92E65BE0885F95 + * <p/> + * ASF_Content_Protection_System_Microsoft_PlayReady + * F4637010-03C3-42CD-B932B48ADF3A6A54 + * <p/> + * ASF_StreamType_PlayReady_Encrypted_Command_Media + * 8683973A-6639-463A-ABD764F1CE3EEAE0 + * <p/> + * <p/> + * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.5. Data Objects > 2.5.1. Payload Extension for AES in Counter Mode + * <p/> + * The sample Id is used as the IV in CTR mode. Block offset, starting at 0 and incremented by 1 after every 16 bytes, from the beginning of the sample is used as the Counter. + * <p/> + * The sample ID for each sample (media object) is stored as an ASF payload extension system with the ID of ASF_Payload_Extension_Encryption_SampleID = {6698B84E-0AFA-4330-AEB2-1C0A98D7A44D}. The payload extension can be stored as a fixed size extension of 8 bytes. + * <p/> + * The sample ID is always stored in big-endian byte order. + */ +public class PlayReadyHeader extends ProtectionSpecificHeader { + private long length; + private List<PlayReadyRecord> records; + + public PlayReadyHeader() { + + } + + @Override + public void parse(ByteBuffer byteBuffer) { + /* + Length DWORD 32 + + PlayReady Record Count WORD 16 + + PlayReady Records See Text Varies + + */ + + length = IsoTypeReader.readUInt32BE(byteBuffer); + int recordCount = IsoTypeReader.readUInt16BE(byteBuffer); + + records = PlayReadyRecord.createFor(byteBuffer, recordCount); + } + + @Override + public ByteBuffer getData() { + + int size = 4 + 2; + for (PlayReadyRecord record : records) { + size += 2 + 2; + size += record.getValue().rewind().limit(); + } + ByteBuffer byteBuffer = ByteBuffer.allocate(size); + + IsoTypeWriter.writeUInt32BE(byteBuffer, size); + IsoTypeWriter.writeUInt16BE(byteBuffer, records.size()); + for (PlayReadyRecord record : records) { + IsoTypeWriter.writeUInt16BE(byteBuffer, record.type); + IsoTypeWriter.writeUInt16BE(byteBuffer, record.getValue().limit()); + ByteBuffer tmp4debug = record.getValue(); + byteBuffer.put(tmp4debug); + } + + return byteBuffer; + } + + public void setRecords(List<PlayReadyRecord> records) { + this.records = records; + } + + public List<PlayReadyRecord> getRecords() { + return Collections.unmodifiableList(records); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("PlayReadyHeader"); + sb.append("{length=").append(length); + sb.append(", recordCount=").append(records.size()); + sb.append(", records=").append(records); + sb.append('}'); + return sb.toString(); + } + + public static abstract class PlayReadyRecord { + int type; + + + public PlayReadyRecord(int type) { + this.type = type; + } + + public static List<PlayReadyRecord> createFor(ByteBuffer byteBuffer, int recordCount) { + List<PlayReadyRecord> records = new ArrayList<PlayReadyRecord>(recordCount); + + for (int i = 0; i < recordCount; i++) { + PlayReadyRecord record; + int type = IsoTypeReader.readUInt16BE(byteBuffer); + int length = IsoTypeReader.readUInt16BE(byteBuffer); + switch (type) { + case 0x1: + record = new RMHeader(); + break; + case 0x2: + record = new DefaulPlayReadyRecord(0x02); + break; + case 0x3: + record = new EmeddedLicenseStore(); + break; + default: + record = new DefaulPlayReadyRecord(type); + } + record.parse((ByteBuffer) byteBuffer.slice().limit(length)); + byteBuffer.position(byteBuffer.position() + length); + records.add(record); + } + + return records; + } + + public abstract void parse(ByteBuffer bytes); + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("PlayReadyRecord"); + sb.append("{type=").append(type); + sb.append(", length=").append(getValue().limit()); +// sb.append(", value=").append(Hex.encodeHex(getValue())).append('\''); + sb.append('}'); + return sb.toString(); + } + + public abstract ByteBuffer getValue(); + + public static class RMHeader extends PlayReadyRecord { + String header; + + public RMHeader() { + super(0x01); + } + + @Override + public void parse(ByteBuffer bytes) { + try { + byte[] str = new byte[bytes.slice().limit()]; + bytes.get(str); + header = new String(str, "UTF-16LE"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + @Override + public ByteBuffer getValue() { + byte[] headerBytes; + try { + headerBytes = header.getBytes("UTF-16LE"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + return ByteBuffer.wrap(headerBytes); + } + + public void setHeader(String header) { + this.header = header; + } + + public String getHeader() { + return header; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("RMHeader"); + sb.append("{length=").append(getValue().limit()); + sb.append(", header='").append(header).append('\''); + sb.append('}'); + return sb.toString(); + } + } + + public static class EmeddedLicenseStore extends PlayReadyRecord { + ByteBuffer value; + + public EmeddedLicenseStore() { + super(0x03); + } + + @Override + public void parse(ByteBuffer bytes) { + this.value = bytes.duplicate(); + } + + @Override + public ByteBuffer getValue() { + return value; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("EmeddedLicenseStore"); + sb.append("{length=").append(getValue().limit()); + //sb.append(", value='").append(Hex.encodeHex(getValue())).append('\''); + sb.append('}'); + return sb.toString(); + } + } + + public static class DefaulPlayReadyRecord extends PlayReadyRecord { + ByteBuffer value; + + public DefaulPlayReadyRecord(int type) { + super(type); + } + + @Override + public void parse(ByteBuffer bytes) { + this.value = bytes.duplicate(); + } + + @Override + public ByteBuffer getValue() { + return value; + } + + } + + } + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/ProtectionSpecificHeader.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/ProtectionSpecificHeader.java.svn-base new file mode 100644 index 0000000..0d2f344 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/ProtectionSpecificHeader.java.svn-base @@ -0,0 +1,79 @@ +package com.googlecode.mp4parser.boxes.piff; + + +import com.coremedia.iso.Hex; + +import java.lang.Class; +import java.lang.IllegalAccessException; +import java.lang.InstantiationException; +import java.lang.Object; +import java.lang.Override; +import java.lang.RuntimeException; +import java.lang.String; +import java.lang.StringBuilder; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +public class ProtectionSpecificHeader { + protected static Map<UUID, Class<? extends ProtectionSpecificHeader>> uuidRegistry = new HashMap<UUID, Class<? extends ProtectionSpecificHeader>>(); + ByteBuffer data; + + static { + uuidRegistry.put(UUID.fromString("9A04F079-9840-4286-AB92-E65BE0885F95"), PlayReadyHeader.class); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ProtectionSpecificHeader) { + if (this.getClass().equals(obj.getClass())) { + return data.equals(((ProtectionSpecificHeader) obj).data); + } + } + return false; + } + + public static ProtectionSpecificHeader createFor(UUID systemId, ByteBuffer bufferWrapper) { + final Class<? extends ProtectionSpecificHeader> aClass = uuidRegistry.get(systemId); + + ProtectionSpecificHeader protectionSpecificHeader = new ProtectionSpecificHeader(); + if (aClass != null) { + try { + protectionSpecificHeader = aClass.newInstance(); + + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + protectionSpecificHeader.parse(bufferWrapper); + return protectionSpecificHeader; + + } + + public void parse(ByteBuffer buffer) { + data = buffer; + + } + + public ByteBuffer getData() { + return data; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("ProtectionSpecificHeader"); + sb.append("{data="); + ByteBuffer data = getData().duplicate(); + data.rewind(); + byte[] bytes = new byte[data.limit()]; + data.get(bytes); + sb.append(Hex.encodeHex(bytes)); + sb.append('}'); + return sb.toString(); + } +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfrfBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfrfBox.java.svn-base new file mode 100644 index 0000000..1e862e9 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfrfBox.java.svn-base @@ -0,0 +1,129 @@ +package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:
+ * TfrfBox = TfrfBoxLength TfrfBoxType [TfrfBoxLongLength] TfrfBoxUUID TfrfBoxFields
+ * TfrfBoxChildren
+ * TfrfBoxType = "u" "u" "i" "d"
+ * TfrfBoxLength = BoxLength
+ * TfrfBoxLongLength = LongBoxLength
+ * TfrfBoxUUID = %xD4 %x80 %x7E %xF2 %xCA %x39 %x46 %x95
+ * %x8E %x54 %x26 %xCB %x9E %x46 %xA7 %x9F
+ * TfrfBoxFields = TfrfBoxVersion
+ * TfrfBoxFlags
+ * FragmentCount
+ * (1* TfrfBoxDataFields32) / (1* TfrfBoxDataFields64)
+ * TfrfBoxVersion = %x00 / %x01
+ * TfrfBoxFlags = 24*24 RESERVED_BIT
+ * FragmentCount = UINT8
+ * TfrfBoxDataFields32 = FragmentAbsoluteTime32
+ * FragmentDuration32
+ * TfrfBoxDataFields64 = FragmentAbsoluteTime64
+ * FragmentDuration64
+ * FragmentAbsoluteTime64 = UNSIGNED_INT32
+ * FragmentDuration64 = UNSIGNED_INT32
+ * FragmentAbsoluteTime64 = UNSIGNED_INT64
+ * FragmentDuration64 = UNSIGNED_INT64
+ * TfrfBoxChildren = *( VendorExtensionUUIDBox )
+ */
+public class TfrfBox extends AbstractFullBox {
+ public List<Entry> entries = new ArrayList<Entry>();
+
+ public TfrfBox() {
+ super("uuid");
+ }
+
+ @Override
+ public byte[] getUserType() {
+ return new byte[]{(byte) 0xd4, (byte) 0x80, (byte) 0x7e, (byte) 0xf2, (byte) 0xca, (byte) 0x39, (byte) 0x46,
+ (byte) 0x95, (byte) 0x8e, (byte) 0x54, 0x26, (byte) 0xcb, (byte) 0x9e, (byte) 0x46, (byte) 0xa7, (byte) 0x9f};
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 5 + entries.size() * (getVersion() == 0x01 ? 16 : 8);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt8(byteBuffer, entries.size());
+
+ for (Entry entry : entries) {
+ if (getVersion() == 0x01) {
+ IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteDuration);
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteDuration);
+ }
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int fragmentCount = IsoTypeReader.readUInt8(content);
+
+ for (int i = 0; i < fragmentCount; i++) {
+ Entry entry = new Entry();
+ if (getVersion() == 0x01) {
+ entry.fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);
+ entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);
+ } else {
+ entry.fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);
+ entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);
+ }
+ entries.add(entry);
+ }
+ }
+
+
+ public long getFragmentCount() {
+ return entries.size();
+ }
+
+ public List<Entry> getEntries() {
+ return entries;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("TfrfBox");
+ sb.append("{entries=").append(entries);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public class Entry {
+ long fragmentAbsoluteTime;
+ long fragmentAbsoluteDuration;
+
+ public long getFragmentAbsoluteTime() {
+ return fragmentAbsoluteTime;
+ }
+
+ public long getFragmentAbsoluteDuration() {
+ return fragmentAbsoluteDuration;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Entry");
+ sb.append("{fragmentAbsoluteTime=").append(fragmentAbsoluteTime);
+ sb.append(", fragmentAbsoluteDuration=").append(fragmentAbsoluteDuration);
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfxdBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfxdBox.java.svn-base new file mode 100644 index 0000000..52e8e87 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfxdBox.java.svn-base @@ -0,0 +1,85 @@ +package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:
+ * TfxdBox = TfxdBoxLength TfxdBoxType [TfxdBoxLongLength] TfxdBoxUUID TfxdBoxFields
+ * TfxdBoxChildren
+ * TfxdBoxType = "u" "u" "i" "d"
+ * TfxdBoxLength = BoxLength
+ * TfxdBoxLongLength = LongBoxLength
+ * TfxdBoxUUID = %x6D %x1D %x9B %x05 %x42 %xD5 %x44 %xE6
+ * %x80 %xE2 %x14 %x1D %xAF %xF7 %x57 %xB2
+ * TfxdBoxFields = TfxdBoxVersion
+ * TfxdBoxFlags
+ * TfxdBoxDataFields32 / TfxdBoxDataFields64
+ * TfxdBoxVersion = %x00 / %x01
+ * TfxdBoxFlags = 24*24 RESERVED_BIT
+ * TfxdBoxDataFields32 = FragmentAbsoluteTime32
+ * FragmentDuration32
+ * TfxdBoxDataFields64 = FragmentAbsoluteTime64
+ * FragmentDuration64
+ * FragmentAbsoluteTime64 = UNSIGNED_INT32
+ * FragmentDuration64 = UNSIGNED_INT32
+ * FragmentAbsoluteTime64 = UNSIGNED_INT64
+ * FragmentDuration64 = UNSIGNED_INT64
+ * TfxdBoxChildren = *( VendorExtensionUUIDBox )
+ */
+//@ExtendedUserType(uuid = "6d1d9b05-42d5-44e6-80e2-141daff757b2")
+public class TfxdBox extends AbstractFullBox {
+ public long fragmentAbsoluteTime;
+ public long fragmentAbsoluteDuration;
+
+ public TfxdBox() {
+ super("uuid");
+ }
+
+ @Override
+ public byte[] getUserType() {
+ return new byte[]{(byte) 0x6d, (byte) 0x1d, (byte) 0x9b, (byte) 0x05, (byte) 0x42, (byte) 0xd5, (byte) 0x44,
+ (byte) 0xe6, (byte) 0x80, (byte) 0xe2, 0x14, (byte) 0x1d, (byte) 0xaf, (byte) 0xf7, (byte) 0x57, (byte) 0xb2};
+ }
+
+ @Override
+ protected long getContentSize() {
+ return getVersion() == 0x01 ? 20 : 12;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+
+ if (getVersion() == 0x01) {
+ fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);
+ fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);
+ } else {
+ fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);
+ fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ if (getVersion() == 0x01) {
+ IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteDuration);
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteDuration);
+ }
+ }
+
+ public long getFragmentAbsoluteTime() {
+ return fragmentAbsoluteTime;
+ }
+
+ public long getFragmentAbsoluteDuration() {
+ return fragmentAbsoluteDuration;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/UuidBasedProtectionSystemSpecificHeaderBox.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/UuidBasedProtectionSystemSpecificHeaderBox.java.svn-base new file mode 100644 index 0000000..b147398 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/UuidBasedProtectionSystemSpecificHeaderBox.java.svn-base @@ -0,0 +1,106 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.AbstractFullBox; +import com.googlecode.mp4parser.util.Path; +import com.googlecode.mp4parser.util.UUIDConverter; + +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.Override;import java.lang.String;import java.lang.StringBuilder;import java.nio.ByteBuffer; +import java.util.UUID; + +import static com.googlecode.mp4parser.util.CastUtils.l2i; + +/** + * aligned(8) class UuidBasedProtectionSystemSpecificHeaderBox extends FullBox(‘uuid’, + * extended_type=0xd08a4f18-10f3-4a82-b6c8-32d8aba183d3, + * version=0, flags=0) + * { + * unsigned int(8)[16] SystemID; + * unsigned int(32) DataSize; + * unsigned int(8)[DataSize] Data; + * } + */ +public class UuidBasedProtectionSystemSpecificHeaderBox extends AbstractFullBox { + public static byte[] USER_TYPE = new byte[]{(byte) 0xd0, (byte) 0x8a, 0x4f, 0x18, 0x10, (byte) 0xf3, 0x4a, (byte) 0x82, + (byte) 0xb6, (byte) 0xc8, 0x32, (byte) 0xd8, (byte) 0xab, (byte) 0xa1, (byte) 0x83, (byte) 0xd3}; + + UUID systemId; + + ProtectionSpecificHeader protectionSpecificHeader; + + public UuidBasedProtectionSystemSpecificHeaderBox() { + super("uuid", USER_TYPE); + } + + @Override + protected long getContentSize() { + return 24 + protectionSpecificHeader.getData().limit(); + } + + @Override + public byte[] getUserType() { + return USER_TYPE; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + writeVersionAndFlags(byteBuffer); + IsoTypeWriter.writeUInt64(byteBuffer, systemId.getMostSignificantBits()); + IsoTypeWriter.writeUInt64(byteBuffer, systemId.getLeastSignificantBits()); + ByteBuffer data = protectionSpecificHeader.getData(); + data.rewind(); + IsoTypeWriter.writeUInt32(byteBuffer, data.limit()); + byteBuffer.put(data); + } + + @Override + protected void _parseDetails(ByteBuffer content) { + parseVersionAndFlags(content); + byte[] systemIdBytes = new byte[16]; + content.get(systemIdBytes); + systemId = UUIDConverter.convert(systemIdBytes); + int dataSize = l2i(IsoTypeReader.readUInt32(content)); + protectionSpecificHeader = ProtectionSpecificHeader.createFor(systemId, content); + } + + public UUID getSystemId() { + return systemId; + } + + public void setSystemId(UUID systemId) { + this.systemId = systemId; + } + + public String getSystemIdString() { + return systemId.toString(); + } + + public ProtectionSpecificHeader getProtectionSpecificHeader() { + return protectionSpecificHeader; + } + + public String getProtectionSpecificHeaderString() { + return protectionSpecificHeader.toString(); + } + + public void setProtectionSpecificHeader(ProtectionSpecificHeader protectionSpecificHeader) { + this.protectionSpecificHeader = protectionSpecificHeader; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("UuidBasedProtectionSystemSpecificHeaderBox"); + sb.append("{systemId=").append(systemId.toString()); + sb.append(", dataSize=").append(protectionSpecificHeader.getData().limit()); + sb.append('}'); + return sb.toString(); + } + + + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java new file mode 100644 index 0000000..da3512d --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java @@ -0,0 +1,45 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.googlecode.mp4parser.boxes.AbstractSampleEncryptionBox; + +/** + * <pre> + * aligned(8) class SampleEncryptionBox extends FullBox(‘uuid’, extended_type= 0xA2394F52-5A9B-4f14-A244-6C427C648DF4, version=0, flags=0) + * { + * if (flags & 0x000001) + * { + * unsigned int(24) AlgorithmID; + * unsigned int(8) IV_size; + * unsigned int(8)[16] KID; + * } + * unsigned int (32) sample_count; + * { + * unsigned int(IV_size) InitializationVector; + * if (flags & 0x000002) + * { + * unsigned int(16) NumberOfEntries; + * { + * unsigned int(16) BytesOfClearData; + * unsigned int(32) BytesOfEncryptedData; + * } [ NumberOfEntries] + * } + * }[ sample_count ] + * } + * </pre> + */ +public class PiffSampleEncryptionBox extends AbstractSampleEncryptionBox { + + /** + * Creates a AbstractSampleEncryptionBox for non-h264 tracks. + */ + public PiffSampleEncryptionBox() { + super("uuid"); + + } + + @Override + public byte[] getUserType() { + return new byte[]{(byte) 0xA2, 0x39, 0x4F, 0x52, 0x5A, (byte) 0x9B, 0x4f, 0x14, (byte) 0xA2, 0x44, 0x6C, 0x42, 0x7C, 0x64, (byte) 0x8D, (byte) 0xF4}; + } + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java new file mode 100644 index 0000000..f92c0f3 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java @@ -0,0 +1,34 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.googlecode.mp4parser.boxes.AbstractTrackEncryptionBox; + +/** + * aligned(8) class TrackEncryptionBox extends FullBox(‘uuid’, + * extended_type=0x8974dbce-7be7-4c51-84f9-7148f9882554, version=0, + * flags=0) + * { + * unsigned int(24) default_AlgorithmID; + * unsigned int(8) default_IV_size; + * unsigned int(8)[16] default_KID; + * } + */ +public class PiffTrackEncryptionBox extends AbstractTrackEncryptionBox { + + + public PiffTrackEncryptionBox() { + super("uuid"); + } + + @Override + public byte[] getUserType() { + return new byte[]{(byte) 0x89, 0x74, (byte) 0xdb, (byte) 0xce, 0x7b, (byte) 0xe7, 0x4c, 0x51, + (byte) 0x84, (byte) 0xf9, 0x71, 0x48, (byte) 0xf9, (byte) 0x88, 0x25, 0x54}; + } + + @Override + public int getFlags() { + return 0; + } + + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java new file mode 100644 index 0000000..74246d0 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java @@ -0,0 +1,253 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.util.Path; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.7. ASF GUIDs + * <p/> + * <p/> + * ASF_Protection_System_Identifier_Object + * 9A04F079-9840-4286-AB92E65BE0885F95 + * <p/> + * ASF_Content_Protection_System_Microsoft_PlayReady + * F4637010-03C3-42CD-B932B48ADF3A6A54 + * <p/> + * ASF_StreamType_PlayReady_Encrypted_Command_Media + * 8683973A-6639-463A-ABD764F1CE3EEAE0 + * <p/> + * <p/> + * Specifications > Microsoft PlayReady Format Specification > 2. PlayReady Media Format > 2.5. Data Objects > 2.5.1. Payload Extension for AES in Counter Mode + * <p/> + * The sample Id is used as the IV in CTR mode. Block offset, starting at 0 and incremented by 1 after every 16 bytes, from the beginning of the sample is used as the Counter. + * <p/> + * The sample ID for each sample (media object) is stored as an ASF payload extension system with the ID of ASF_Payload_Extension_Encryption_SampleID = {6698B84E-0AFA-4330-AEB2-1C0A98D7A44D}. The payload extension can be stored as a fixed size extension of 8 bytes. + * <p/> + * The sample ID is always stored in big-endian byte order. + */ +public class PlayReadyHeader extends ProtectionSpecificHeader { + private long length; + private List<PlayReadyRecord> records; + + public PlayReadyHeader() { + + } + + @Override + public void parse(ByteBuffer byteBuffer) { + /* + Length DWORD 32 + + PlayReady Record Count WORD 16 + + PlayReady Records See Text Varies + + */ + + length = IsoTypeReader.readUInt32BE(byteBuffer); + int recordCount = IsoTypeReader.readUInt16BE(byteBuffer); + + records = PlayReadyRecord.createFor(byteBuffer, recordCount); + } + + @Override + public ByteBuffer getData() { + + int size = 4 + 2; + for (PlayReadyRecord record : records) { + size += 2 + 2; + size += record.getValue().rewind().limit(); + } + ByteBuffer byteBuffer = ByteBuffer.allocate(size); + + IsoTypeWriter.writeUInt32BE(byteBuffer, size); + IsoTypeWriter.writeUInt16BE(byteBuffer, records.size()); + for (PlayReadyRecord record : records) { + IsoTypeWriter.writeUInt16BE(byteBuffer, record.type); + IsoTypeWriter.writeUInt16BE(byteBuffer, record.getValue().limit()); + ByteBuffer tmp4debug = record.getValue(); + byteBuffer.put(tmp4debug); + } + + return byteBuffer; + } + + public void setRecords(List<PlayReadyRecord> records) { + this.records = records; + } + + public List<PlayReadyRecord> getRecords() { + return Collections.unmodifiableList(records); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("PlayReadyHeader"); + sb.append("{length=").append(length); + sb.append(", recordCount=").append(records.size()); + sb.append(", records=").append(records); + sb.append('}'); + return sb.toString(); + } + + public static abstract class PlayReadyRecord { + int type; + + + public PlayReadyRecord(int type) { + this.type = type; + } + + public static List<PlayReadyRecord> createFor(ByteBuffer byteBuffer, int recordCount) { + List<PlayReadyRecord> records = new ArrayList<PlayReadyRecord>(recordCount); + + for (int i = 0; i < recordCount; i++) { + PlayReadyRecord record; + int type = IsoTypeReader.readUInt16BE(byteBuffer); + int length = IsoTypeReader.readUInt16BE(byteBuffer); + switch (type) { + case 0x1: + record = new RMHeader(); + break; + case 0x2: + record = new DefaulPlayReadyRecord(0x02); + break; + case 0x3: + record = new EmeddedLicenseStore(); + break; + default: + record = new DefaulPlayReadyRecord(type); + } + record.parse((ByteBuffer) byteBuffer.slice().limit(length)); + byteBuffer.position(byteBuffer.position() + length); + records.add(record); + } + + return records; + } + + public abstract void parse(ByteBuffer bytes); + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("PlayReadyRecord"); + sb.append("{type=").append(type); + sb.append(", length=").append(getValue().limit()); +// sb.append(", value=").append(Hex.encodeHex(getValue())).append('\''); + sb.append('}'); + return sb.toString(); + } + + public abstract ByteBuffer getValue(); + + public static class RMHeader extends PlayReadyRecord { + String header; + + public RMHeader() { + super(0x01); + } + + @Override + public void parse(ByteBuffer bytes) { + try { + byte[] str = new byte[bytes.slice().limit()]; + bytes.get(str); + header = new String(str, "UTF-16LE"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + @Override + public ByteBuffer getValue() { + byte[] headerBytes; + try { + headerBytes = header.getBytes("UTF-16LE"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + return ByteBuffer.wrap(headerBytes); + } + + public void setHeader(String header) { + this.header = header; + } + + public String getHeader() { + return header; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("RMHeader"); + sb.append("{length=").append(getValue().limit()); + sb.append(", header='").append(header).append('\''); + sb.append('}'); + return sb.toString(); + } + } + + public static class EmeddedLicenseStore extends PlayReadyRecord { + ByteBuffer value; + + public EmeddedLicenseStore() { + super(0x03); + } + + @Override + public void parse(ByteBuffer bytes) { + this.value = bytes.duplicate(); + } + + @Override + public ByteBuffer getValue() { + return value; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("EmeddedLicenseStore"); + sb.append("{length=").append(getValue().limit()); + //sb.append(", value='").append(Hex.encodeHex(getValue())).append('\''); + sb.append('}'); + return sb.toString(); + } + } + + public static class DefaulPlayReadyRecord extends PlayReadyRecord { + ByteBuffer value; + + public DefaulPlayReadyRecord(int type) { + super(type); + } + + @Override + public void parse(ByteBuffer bytes) { + this.value = bytes.duplicate(); + } + + @Override + public ByteBuffer getValue() { + return value; + } + + } + + } + +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java new file mode 100644 index 0000000..0d2f344 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java @@ -0,0 +1,79 @@ +package com.googlecode.mp4parser.boxes.piff; + + +import com.coremedia.iso.Hex; + +import java.lang.Class; +import java.lang.IllegalAccessException; +import java.lang.InstantiationException; +import java.lang.Object; +import java.lang.Override; +import java.lang.RuntimeException; +import java.lang.String; +import java.lang.StringBuilder; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +public class ProtectionSpecificHeader { + protected static Map<UUID, Class<? extends ProtectionSpecificHeader>> uuidRegistry = new HashMap<UUID, Class<? extends ProtectionSpecificHeader>>(); + ByteBuffer data; + + static { + uuidRegistry.put(UUID.fromString("9A04F079-9840-4286-AB92-E65BE0885F95"), PlayReadyHeader.class); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ProtectionSpecificHeader) { + if (this.getClass().equals(obj.getClass())) { + return data.equals(((ProtectionSpecificHeader) obj).data); + } + } + return false; + } + + public static ProtectionSpecificHeader createFor(UUID systemId, ByteBuffer bufferWrapper) { + final Class<? extends ProtectionSpecificHeader> aClass = uuidRegistry.get(systemId); + + ProtectionSpecificHeader protectionSpecificHeader = new ProtectionSpecificHeader(); + if (aClass != null) { + try { + protectionSpecificHeader = aClass.newInstance(); + + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + protectionSpecificHeader.parse(bufferWrapper); + return protectionSpecificHeader; + + } + + public void parse(ByteBuffer buffer) { + data = buffer; + + } + + public ByteBuffer getData() { + return data; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("ProtectionSpecificHeader"); + sb.append("{data="); + ByteBuffer data = getData().duplicate(); + data.rewind(); + byte[] bytes = new byte[data.limit()]; + data.get(bytes); + sb.append(Hex.encodeHex(bytes)); + sb.append('}'); + return sb.toString(); + } +} diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java new file mode 100644 index 0000000..1e862e9 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java @@ -0,0 +1,129 @@ +package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:
+ * TfrfBox = TfrfBoxLength TfrfBoxType [TfrfBoxLongLength] TfrfBoxUUID TfrfBoxFields
+ * TfrfBoxChildren
+ * TfrfBoxType = "u" "u" "i" "d"
+ * TfrfBoxLength = BoxLength
+ * TfrfBoxLongLength = LongBoxLength
+ * TfrfBoxUUID = %xD4 %x80 %x7E %xF2 %xCA %x39 %x46 %x95
+ * %x8E %x54 %x26 %xCB %x9E %x46 %xA7 %x9F
+ * TfrfBoxFields = TfrfBoxVersion
+ * TfrfBoxFlags
+ * FragmentCount
+ * (1* TfrfBoxDataFields32) / (1* TfrfBoxDataFields64)
+ * TfrfBoxVersion = %x00 / %x01
+ * TfrfBoxFlags = 24*24 RESERVED_BIT
+ * FragmentCount = UINT8
+ * TfrfBoxDataFields32 = FragmentAbsoluteTime32
+ * FragmentDuration32
+ * TfrfBoxDataFields64 = FragmentAbsoluteTime64
+ * FragmentDuration64
+ * FragmentAbsoluteTime64 = UNSIGNED_INT32
+ * FragmentDuration64 = UNSIGNED_INT32
+ * FragmentAbsoluteTime64 = UNSIGNED_INT64
+ * FragmentDuration64 = UNSIGNED_INT64
+ * TfrfBoxChildren = *( VendorExtensionUUIDBox )
+ */
+public class TfrfBox extends AbstractFullBox {
+ public List<Entry> entries = new ArrayList<Entry>();
+
+ public TfrfBox() {
+ super("uuid");
+ }
+
+ @Override
+ public byte[] getUserType() {
+ return new byte[]{(byte) 0xd4, (byte) 0x80, (byte) 0x7e, (byte) 0xf2, (byte) 0xca, (byte) 0x39, (byte) 0x46,
+ (byte) 0x95, (byte) 0x8e, (byte) 0x54, 0x26, (byte) 0xcb, (byte) 0x9e, (byte) 0x46, (byte) 0xa7, (byte) 0x9f};
+ }
+
+ @Override
+ protected long getContentSize() {
+ return 5 + entries.size() * (getVersion() == 0x01 ? 16 : 8);
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ IsoTypeWriter.writeUInt8(byteBuffer, entries.size());
+
+ for (Entry entry : entries) {
+ if (getVersion() == 0x01) {
+ IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt64(byteBuffer, entry.fragmentAbsoluteDuration);
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, entry.fragmentAbsoluteDuration);
+ }
+ }
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+ int fragmentCount = IsoTypeReader.readUInt8(content);
+
+ for (int i = 0; i < fragmentCount; i++) {
+ Entry entry = new Entry();
+ if (getVersion() == 0x01) {
+ entry.fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);
+ entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);
+ } else {
+ entry.fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);
+ entry.fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);
+ }
+ entries.add(entry);
+ }
+ }
+
+
+ public long getFragmentCount() {
+ return entries.size();
+ }
+
+ public List<Entry> getEntries() {
+ return entries;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("TfrfBox");
+ sb.append("{entries=").append(entries);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public class Entry {
+ long fragmentAbsoluteTime;
+ long fragmentAbsoluteDuration;
+
+ public long getFragmentAbsoluteTime() {
+ return fragmentAbsoluteTime;
+ }
+
+ public long getFragmentAbsoluteDuration() {
+ return fragmentAbsoluteDuration;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Entry");
+ sb.append("{fragmentAbsoluteTime=").append(fragmentAbsoluteTime);
+ sb.append(", fragmentAbsoluteDuration=").append(fragmentAbsoluteDuration);
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java new file mode 100644 index 0000000..52e8e87 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java @@ -0,0 +1,85 @@ +package com.googlecode.mp4parser.boxes.piff;
+
+import com.coremedia.iso.IsoTypeReader;
+import com.coremedia.iso.IsoTypeWriter;
+import com.googlecode.mp4parser.AbstractFullBox;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The syntax of the fields defined in this section, specified in ABNF [RFC5234], is as follows:
+ * TfxdBox = TfxdBoxLength TfxdBoxType [TfxdBoxLongLength] TfxdBoxUUID TfxdBoxFields
+ * TfxdBoxChildren
+ * TfxdBoxType = "u" "u" "i" "d"
+ * TfxdBoxLength = BoxLength
+ * TfxdBoxLongLength = LongBoxLength
+ * TfxdBoxUUID = %x6D %x1D %x9B %x05 %x42 %xD5 %x44 %xE6
+ * %x80 %xE2 %x14 %x1D %xAF %xF7 %x57 %xB2
+ * TfxdBoxFields = TfxdBoxVersion
+ * TfxdBoxFlags
+ * TfxdBoxDataFields32 / TfxdBoxDataFields64
+ * TfxdBoxVersion = %x00 / %x01
+ * TfxdBoxFlags = 24*24 RESERVED_BIT
+ * TfxdBoxDataFields32 = FragmentAbsoluteTime32
+ * FragmentDuration32
+ * TfxdBoxDataFields64 = FragmentAbsoluteTime64
+ * FragmentDuration64
+ * FragmentAbsoluteTime64 = UNSIGNED_INT32
+ * FragmentDuration64 = UNSIGNED_INT32
+ * FragmentAbsoluteTime64 = UNSIGNED_INT64
+ * FragmentDuration64 = UNSIGNED_INT64
+ * TfxdBoxChildren = *( VendorExtensionUUIDBox )
+ */
+//@ExtendedUserType(uuid = "6d1d9b05-42d5-44e6-80e2-141daff757b2")
+public class TfxdBox extends AbstractFullBox {
+ public long fragmentAbsoluteTime;
+ public long fragmentAbsoluteDuration;
+
+ public TfxdBox() {
+ super("uuid");
+ }
+
+ @Override
+ public byte[] getUserType() {
+ return new byte[]{(byte) 0x6d, (byte) 0x1d, (byte) 0x9b, (byte) 0x05, (byte) 0x42, (byte) 0xd5, (byte) 0x44,
+ (byte) 0xe6, (byte) 0x80, (byte) 0xe2, 0x14, (byte) 0x1d, (byte) 0xaf, (byte) 0xf7, (byte) 0x57, (byte) 0xb2};
+ }
+
+ @Override
+ protected long getContentSize() {
+ return getVersion() == 0x01 ? 20 : 12;
+ }
+
+ @Override
+ public void _parseDetails(ByteBuffer content) {
+ parseVersionAndFlags(content);
+
+ if (getVersion() == 0x01) {
+ fragmentAbsoluteTime = IsoTypeReader.readUInt64(content);
+ fragmentAbsoluteDuration = IsoTypeReader.readUInt64(content);
+ } else {
+ fragmentAbsoluteTime = IsoTypeReader.readUInt32(content);
+ fragmentAbsoluteDuration = IsoTypeReader.readUInt32(content);
+ }
+ }
+
+ @Override
+ protected void getContent(ByteBuffer byteBuffer) {
+ writeVersionAndFlags(byteBuffer);
+ if (getVersion() == 0x01) {
+ IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt64(byteBuffer, fragmentAbsoluteDuration);
+ } else {
+ IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteTime);
+ IsoTypeWriter.writeUInt32(byteBuffer, fragmentAbsoluteDuration);
+ }
+ }
+
+ public long getFragmentAbsoluteTime() {
+ return fragmentAbsoluteTime;
+ }
+
+ public long getFragmentAbsoluteDuration() {
+ return fragmentAbsoluteDuration;
+ }
+}
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java new file mode 100644 index 0000000..b147398 --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java @@ -0,0 +1,106 @@ +package com.googlecode.mp4parser.boxes.piff; + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeReader; +import com.coremedia.iso.IsoTypeWriter; +import com.googlecode.mp4parser.AbstractFullBox; +import com.googlecode.mp4parser.util.Path; +import com.googlecode.mp4parser.util.UUIDConverter; + +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.Override;import java.lang.String;import java.lang.StringBuilder;import java.nio.ByteBuffer; +import java.util.UUID; + +import static com.googlecode.mp4parser.util.CastUtils.l2i; + +/** + * aligned(8) class UuidBasedProtectionSystemSpecificHeaderBox extends FullBox(‘uuid’, + * extended_type=0xd08a4f18-10f3-4a82-b6c8-32d8aba183d3, + * version=0, flags=0) + * { + * unsigned int(8)[16] SystemID; + * unsigned int(32) DataSize; + * unsigned int(8)[DataSize] Data; + * } + */ +public class UuidBasedProtectionSystemSpecificHeaderBox extends AbstractFullBox { + public static byte[] USER_TYPE = new byte[]{(byte) 0xd0, (byte) 0x8a, 0x4f, 0x18, 0x10, (byte) 0xf3, 0x4a, (byte) 0x82, + (byte) 0xb6, (byte) 0xc8, 0x32, (byte) 0xd8, (byte) 0xab, (byte) 0xa1, (byte) 0x83, (byte) 0xd3}; + + UUID systemId; + + ProtectionSpecificHeader protectionSpecificHeader; + + public UuidBasedProtectionSystemSpecificHeaderBox() { + super("uuid", USER_TYPE); + } + + @Override + protected long getContentSize() { + return 24 + protectionSpecificHeader.getData().limit(); + } + + @Override + public byte[] getUserType() { + return USER_TYPE; + } + + @Override + protected void getContent(ByteBuffer byteBuffer) { + writeVersionAndFlags(byteBuffer); + IsoTypeWriter.writeUInt64(byteBuffer, systemId.getMostSignificantBits()); + IsoTypeWriter.writeUInt64(byteBuffer, systemId.getLeastSignificantBits()); + ByteBuffer data = protectionSpecificHeader.getData(); + data.rewind(); + IsoTypeWriter.writeUInt32(byteBuffer, data.limit()); + byteBuffer.put(data); + } + + @Override + protected void _parseDetails(ByteBuffer content) { + parseVersionAndFlags(content); + byte[] systemIdBytes = new byte[16]; + content.get(systemIdBytes); + systemId = UUIDConverter.convert(systemIdBytes); + int dataSize = l2i(IsoTypeReader.readUInt32(content)); + protectionSpecificHeader = ProtectionSpecificHeader.createFor(systemId, content); + } + + public UUID getSystemId() { + return systemId; + } + + public void setSystemId(UUID systemId) { + this.systemId = systemId; + } + + public String getSystemIdString() { + return systemId.toString(); + } + + public ProtectionSpecificHeader getProtectionSpecificHeader() { + return protectionSpecificHeader; + } + + public String getProtectionSpecificHeaderString() { + return protectionSpecificHeader.toString(); + } + + public void setProtectionSpecificHeader(ProtectionSpecificHeader protectionSpecificHeader) { + this.protectionSpecificHeader = protectionSpecificHeader; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("UuidBasedProtectionSystemSpecificHeaderBox"); + sb.append("{systemId=").append(systemId.toString()); + sb.append(", dataSize=").append(protectionSpecificHeader.getData().limit()); + sb.append('}'); + return sb.toString(); + } + + + +} |