summaryrefslogtreecommitdiff
path: root/isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff
diff options
context:
space:
mode:
Diffstat (limited to 'isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff')
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/all-wcprops47
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/entries266
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffSampleEncryptionBox.java.svn-base45
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PiffTrackEncryptionBox.java.svn-base34
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/PlayReadyHeader.java.svn-base253
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/ProtectionSpecificHeader.java.svn-base79
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfrfBox.java.svn-base129
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/TfxdBox.java.svn-base85
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/.svn/text-base/UuidBasedProtectionSystemSpecificHeaderBox.java.svn-base106
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffSampleEncryptionBox.java45
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PiffTrackEncryptionBox.java34
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/PlayReadyHeader.java253
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/ProtectionSpecificHeader.java79
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfrfBox.java129
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/TfxdBox.java85
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/boxes/piff/UuidBasedProtectionSystemSpecificHeaderBox.java106
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();
+ }
+
+
+
+}