diff --git a/generated/org/smpte_ra/schemas/st2067_21_2016/ObjectFactory.java b/generated/org/smpte_ra/schemas/st2067_21_2016/ObjectFactory.java new file mode 100644 index 00000000..b37f02d9 --- /dev/null +++ b/generated/org/smpte_ra/schemas/st2067_21_2016/ObjectFactory.java @@ -0,0 +1,62 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2020.07.12 at 09:01:40 PM PDT +// + + +package org.smpte_ra.schemas.st2067_21_2016; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.smpte_ra.schemas.st2067_21_2016 package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _MaxCLL_QNAME = new QName("http://www.smpte-ra.org/schemas/2067-21/2016", "MaxCLL"); + private final static QName _MaxFALL_QNAME = new QName("http://www.smpte-ra.org/schemas/2067-21/2016", "MaxFALL"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.smpte_ra.schemas.st2067_21_2016 + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Integer }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/schemas/2067-21/2016", name = "MaxCLL") + public JAXBElement createMaxCLL(Integer value) { + return new JAXBElement(_MaxCLL_QNAME, Integer.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Integer }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/schemas/2067-21/2016", name = "MaxFALL") + public JAXBElement createMaxFALL(Integer value) { + return new JAXBElement(_MaxFALL_QNAME, Integer.class, null, value); + } + +} diff --git a/generated/org/smpte_ra/schemas/st2067_2_2020/CDPSequence.java b/generated/org/smpte_ra/schemas/st2067_2_2020/CDPSequence.java new file mode 100644 index 00000000..1353bbb5 --- /dev/null +++ b/generated/org/smpte_ra/schemas/st2067_2_2020/CDPSequence.java @@ -0,0 +1,76 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2020.07.12 at 07:25:26 PM PDT +// + + +package org.smpte_ra.schemas.st2067_2_2020; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import org.smpte_ra.schemas.st2067_2_2016.SequenceType; + + +/** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType>
+ *   <complexContent>
+ *     <extension base="{http://www.smpte-ra.org/schemas/2067-3/2016}SequenceType">
+ *       <sequence>
+ *         <element name="ParentTrackID" type="{http://www.smpte-ra.org/schemas/433/2008/dcmlTypes/}UUIDType"/>
+ *       </sequence>
+ *     </extension>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "parentTrackID" +}) +@XmlRootElement(name = "CDPSequence") +public class CDPSequence + extends SequenceType +{ + + @XmlElement(name = "ParentTrackID", required = true) + @XmlSchemaType(name = "anyURI") + protected String parentTrackID; + + /** + * Gets the value of the parentTrackID property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getParentTrackID() { + return parentTrackID; + } + + /** + * Sets the value of the parentTrackID property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setParentTrackID(String value) { + this.parentTrackID = value; + } + +} diff --git a/generated/org/smpte_ra/schemas/st2067_2_2020/ObjectFactory.java b/generated/org/smpte_ra/schemas/st2067_2_2020/ObjectFactory.java new file mode 100644 index 00000000..690fd858 --- /dev/null +++ b/generated/org/smpte_ra/schemas/st2067_2_2020/ObjectFactory.java @@ -0,0 +1,170 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2020.07.12 at 07:25:26 PM PDT +// + + +package org.smpte_ra.schemas.st2067_2_2020; + +import java.util.List; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; +import org.smpte_ra.schemas.st2067_2_2016.SequenceType; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.smpte_ra.schemas.st2067_2_2020 package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _CommentarySequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "CommentarySequence"); + private final static QName _MainImageSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "MainImageSequence"); + private final static QName _KaraokeSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "KaraokeSequence"); + private final static QName _ForcedNarrativeSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "ForcedNarrativeSequence"); + private final static QName _MainAudioSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "MainAudioSequence"); + private final static QName _HearingImpairedCaptionsSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "HearingImpairedCaptionsSequence"); + private final static QName _SubtitlesSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "SubtitlesSequence"); + private final static QName _TimedTextResourceID_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "TimedTextResourceID"); + private final static QName _VisuallyImpairedTextSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "VisuallyImpairedTextSequence"); + private final static QName _AncillaryDataSequence_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "AncillaryDataSequence"); + private final static QName _ApplicationIdentification_QNAME = new QName("http://www.smpte-ra.org/ns/2067-2/2020", "ApplicationIdentification"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.smpte_ra.schemas.st2067_2_2020 + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link CDPSequence } + * + */ + public CDPSequence createCDPSequence() { + return new CDPSequence(); + } + + /** + * Create an instance of {@link StereoImageTrackFileResourceType } + * + */ + public StereoImageTrackFileResourceType createStereoImageTrackFileResourceType() { + return new StereoImageTrackFileResourceType(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "CommentarySequence") + public JAXBElement createCommentarySequence(SequenceType value) { + return new JAXBElement(_CommentarySequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "MainImageSequence") + public JAXBElement createMainImageSequence(SequenceType value) { + return new JAXBElement(_MainImageSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "KaraokeSequence") + public JAXBElement createKaraokeSequence(SequenceType value) { + return new JAXBElement(_KaraokeSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "ForcedNarrativeSequence") + public JAXBElement createForcedNarrativeSequence(SequenceType value) { + return new JAXBElement(_ForcedNarrativeSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "MainAudioSequence") + public JAXBElement createMainAudioSequence(SequenceType value) { + return new JAXBElement(_MainAudioSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "HearingImpairedCaptionsSequence") + public JAXBElement createHearingImpairedCaptionsSequence(SequenceType value) { + return new JAXBElement(_HearingImpairedCaptionsSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "SubtitlesSequence") + public JAXBElement createSubtitlesSequence(SequenceType value) { + return new JAXBElement(_SubtitlesSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "TimedTextResourceID") + public JAXBElement createTimedTextResourceID(String value) { + return new JAXBElement(_TimedTextResourceID_QNAME, String.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "VisuallyImpairedTextSequence") + public JAXBElement createVisuallyImpairedTextSequence(SequenceType value) { + return new JAXBElement(_VisuallyImpairedTextSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link SequenceType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "AncillaryDataSequence") + public JAXBElement createAncillaryDataSequence(SequenceType value) { + return new JAXBElement(_AncillaryDataSequence_QNAME, SequenceType.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link List }{@code <}{@link String }{@code >}{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", name = "ApplicationIdentification") + public JAXBElement> createApplicationIdentification(List value) { + return new JAXBElement>(_ApplicationIdentification_QNAME, ((Class) List.class), null, ((List ) value)); + } + +} diff --git a/generated/org/smpte_ra/schemas/st2067_2_2020/StereoImageTrackFileResourceType.java b/generated/org/smpte_ra/schemas/st2067_2_2020/StereoImageTrackFileResourceType.java new file mode 100644 index 00000000..31523951 --- /dev/null +++ b/generated/org/smpte_ra/schemas/st2067_2_2020/StereoImageTrackFileResourceType.java @@ -0,0 +1,101 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2020.07.12 at 07:25:26 PM PDT +// + + +package org.smpte_ra.schemas.st2067_2_2020; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import org.smpte_ra.schemas.st2067_2_2016.BaseResourceType; +import org.smpte_ra.schemas.st2067_2_2016.TrackFileResourceType; + + +/** + *

Java class for StereoImageTrackFileResourceType complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="StereoImageTrackFileResourceType">
+ *   <complexContent>
+ *     <extension base="{http://www.smpte-ra.org/schemas/2067-3/2016}BaseResourceType">
+ *       <sequence>
+ *         <element name="LeftEye" type="{http://www.smpte-ra.org/schemas/2067-3/2016}TrackFileResourceType"/>
+ *         <element name="RightEye" type="{http://www.smpte-ra.org/schemas/2067-3/2016}TrackFileResourceType"/>
+ *       </sequence>
+ *     </extension>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "StereoImageTrackFileResourceType", propOrder = { + "leftEye", + "rightEye" +}) +public class StereoImageTrackFileResourceType + extends BaseResourceType +{ + + @XmlElement(name = "LeftEye", required = true) + protected TrackFileResourceType leftEye; + @XmlElement(name = "RightEye", required = true) + protected TrackFileResourceType rightEye; + + /** + * Gets the value of the leftEye property. + * + * @return + * possible object is + * {@link TrackFileResourceType } + * + */ + public TrackFileResourceType getLeftEye() { + return leftEye; + } + + /** + * Sets the value of the leftEye property. + * + * @param value + * allowed object is + * {@link TrackFileResourceType } + * + */ + public void setLeftEye(TrackFileResourceType value) { + this.leftEye = value; + } + + /** + * Gets the value of the rightEye property. + * + * @return + * possible object is + * {@link TrackFileResourceType } + * + */ + public TrackFileResourceType getRightEye() { + return rightEye; + } + + /** + * Sets the value of the rightEye property. + * + * @param value + * allowed object is + * {@link TrackFileResourceType } + * + */ + public void setRightEye(TrackFileResourceType value) { + this.rightEye = value; + } + +} diff --git a/generated/org/smpte_ra/schemas/st2067_2_2020/package-info.java b/generated/org/smpte_ra/schemas/st2067_2_2020/package-info.java new file mode 100644 index 00000000..105736dc --- /dev/null +++ b/generated/org/smpte_ra/schemas/st2067_2_2020/package-info.java @@ -0,0 +1,9 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2020.07.12 at 07:25:26 PM PDT +// + +@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.smpte-ra.org/ns/2067-2/2020", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) +package org.smpte_ra.schemas.st2067_2_2020; diff --git a/src/main/java/com/netflix/imflibrary/app/IMPFixer.java b/src/main/java/com/netflix/imflibrary/app/IMPFixer.java index 75009cfa..1fb30fc5 100755 --- a/src/main/java/com/netflix/imflibrary/app/IMPFixer.java +++ b/src/main/java/com/netflix/imflibrary/app/IMPFixer.java @@ -17,6 +17,7 @@ import com.netflix.imflibrary.st0429_9.BasicMapProfileV2MappedFileSet; import com.netflix.imflibrary.st2067_2.ApplicationComposition; import com.netflix.imflibrary.st2067_2.ApplicationCompositionFactory; +import com.netflix.imflibrary.st2067_2.CoreConstraints; import com.netflix.imflibrary.st2067_2.IMFEssenceComponentVirtualTrack; import com.netflix.imflibrary.utils.*; import com.netflix.imflibrary.writerTools.CompositionPlaylistBuilder_2016; @@ -228,16 +229,18 @@ public static List analyzePackageAndWrite(File rootFile Set trackFileIDsSet = trackFileIDToHeaderPartitionPayLoadMap.keySet(); if(versionCPLSchema.equals("")) { - if (applicationComposition.getCoreConstraintsVersion().contains("st2067_2_2013")) { + String coreConstraintsSchema = applicationComposition.getCoreConstraintsSchema(); + if (coreConstraintsSchema.equals(CoreConstraints.NAMESPACE_IMF_2013)) { versionCPLSchema = "2013"; } - else if (applicationComposition.getCoreConstraintsVersion().contains("st2067_2_2016")) { + else if (coreConstraintsSchema.equals(CoreConstraints.NAMESPACE_IMF_2016) + || coreConstraintsSchema.equals(CoreConstraints.NAMESPACE_IMF_2020)) { versionCPLSchema = "2016"; } else { imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, - String.format("Input package CoreConstraintsVersion %s not supported", applicationComposition.getCoreConstraintsVersion().toString())); + String.format("Input package CoreConstraints Schema %s not supported", applicationComposition.getCoreConstraintsSchema())); } } diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/AbstractApplicationComposition.java b/src/main/java/com/netflix/imflibrary/st2067_2/AbstractApplicationComposition.java index 68ed1913..812dee78 100644 --- a/src/main/java/com/netflix/imflibrary/st2067_2/AbstractApplicationComposition.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/AbstractApplicationComposition.java @@ -84,7 +84,7 @@ public abstract class AbstractApplicationComposition implements ApplicationCompo - private final String coreConstraintsVersion; + private final String coreConstraintsSchema; private final Map virtualTrackMap; private final IMFCompositionPlaylistType compositionPlaylistType; private final Map> essenceDescriptorDomNodeMap; @@ -140,7 +140,7 @@ public AbstractApplicationComposition(@Nonnull IMFCompositionPlaylistType imfCom this.regXMLLibDictionary = new RegXMLLibDictionary(); - this.coreConstraintsVersion = this.compositionPlaylistType.getCoreConstraintsVersion(); + this.coreConstraintsSchema = this.compositionPlaylistType.getCoreConstraintsSchema(); this.essenceDescriptorKeyIgnoreSet = Collections.unmodifiableSet(ignoreSet); @@ -375,12 +375,22 @@ private IMFCompositionPlaylistType getCompositionPlaylistType() { } /** - * Getter for the CoreConstraintsURI corresponding to this CompositionPlaylist + * Get the Java package string for the Core Constraints version + * @deprecated Instead use {@link #getCoreConstraintsSchema()} * - * @return the uri for the CoreConstraints schema for this CompositionPlaylist + * @return package containing the Core Constraints classes */ + @Deprecated public String getCoreConstraintsVersion() { - return this.coreConstraintsVersion; + return CoreConstraints.packageFromSchema(this.coreConstraintsSchema); + } + + /** + * Getter for the Core Constraints schema URI. + * @return URI for the Core Constraints schema + */ + @Nonnull public String getCoreConstraintsSchema() { + return this.coreConstraintsSchema; } /** diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/Application2Composition.java b/src/main/java/com/netflix/imflibrary/st2067_2/Application2Composition.java index 45e68894..c19b3b34 100755 --- a/src/main/java/com/netflix/imflibrary/st2067_2/Application2Composition.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/Application2Composition.java @@ -25,6 +25,8 @@ * A class that models Composition with Application 2 constraints from 2067-20 specification */ public class Application2Composition extends AbstractApplicationComposition { + public static final String SCHEMA_URI_APP2_2013 = "http://www.smpte-ra.org/schemas/2067-20/2013"; + public static final String SCHEMA_URI_APP2_2016 = "http://www.smpte-ra.org/schemas/2067-20/2016"; public static final Integer MAX_IMAGE_FRAME_WIDTH = 1920; public static final Integer MAX_IMAGE_FRAME_HEIGHT = 1080; public static final SetprogressiveSampleRateSupported = Collections.unmodifiableSet(new HashSet() {{ diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/Application2ExtendedComposition.java b/src/main/java/com/netflix/imflibrary/st2067_2/Application2ExtendedComposition.java index e43b9616..59438692 100755 --- a/src/main/java/com/netflix/imflibrary/st2067_2/Application2ExtendedComposition.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/Application2ExtendedComposition.java @@ -23,6 +23,9 @@ * A class that models Composition with Application 2Extended constraints from 2067-21 specification */ public class Application2ExtendedComposition extends AbstractApplicationComposition { + public static final String SCHEMA_URI_APP2E_2014 = "http://www.smpte-ra.org/schemas/2067-21/2014"; + public static final String SCHEMA_URI_APP2E_2016 = "http://www.smpte-ra.org/schemas/2067-21/2016"; + public static final String SCHEMA_URI_APP2E_2020 = "http://www.smpte-ra.org/ns/2067-21/2020"; public static final Integer MAX_YUV_IMAGE_FRAME_WIDTH = 3840; public static final Integer MAX_YUV_IMAGE_FRAME_HEIGHT = 2160; public static final Integer MAX_RGB_IMAGE_FRAME_WIDTH = 4096; diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/Application5Composition.java b/src/main/java/com/netflix/imflibrary/st2067_2/Application5Composition.java index 7b63c2c8..24f71648 100644 --- a/src/main/java/com/netflix/imflibrary/st2067_2/Application5Composition.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/Application5Composition.java @@ -44,6 +44,7 @@ * A class that models Composition with Application 5 constraints from 2067-50 specification */ public class Application5Composition extends AbstractApplicationComposition { + public static final String SCHEMA_URI_APP5_2017 = "http://www.smpte-ra.org/ns/2067-50/2017"; public static final Integer MAX_RGB_IMAGE_FRAME_WIDTH = Integer.MAX_VALUE; //TODO: 2067-50 specifies 2^32-1, would require using Long instead of Integer public static final Integer MAX_RGB_IMAGE_FRAME_HEIGHT = Integer.MAX_VALUE; //TODO: 2067-50 specifies 2^32-1, would require using Long instead of Integer public static final Map>colorToBitDepthMap = Collections.unmodifiableMap(new HashMap>() {{ diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationComposition.java b/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationComposition.java index d5c05946..0ba15c0e 100644 --- a/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationComposition.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationComposition.java @@ -106,12 +106,20 @@ public interface ApplicationComposition { public UUID getUUID(); /** - * Getter for the CoreConstraintsURI corresponding to this CompositionPlaylist + * Get the Java package string for the Core Constraints version + * @deprecated Instead use {@link #getCoreConstraintsSchema()} * - * @return the uri for the CoreConstraints schema for this CompositionPlaylist + * @return package containing the Core Constraints classes */ + @Deprecated public String getCoreConstraintsVersion(); + /** + * Getter for the Core Constraints schema URI. + * @return URI for the Core Constraints schema + */ + @Nonnull public String getCoreConstraintsSchema(); + /** * Getter for the essence VirtualTracks in this Composition * diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationCompositionFactory.java b/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationCompositionFactory.java index c4e28e16..b6bc84e5 100755 --- a/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationCompositionFactory.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/ApplicationCompositionFactory.java @@ -44,6 +44,7 @@ public class ApplicationCompositionFactory { private static final Set namespacesApplication2EComposition = Collections.unmodifiableSet(new HashSet() {{ add("http://www.smpte-ra.org/schemas/2067-21/2014"); add("http://www.smpte-ra.org/schemas/2067-21/2016"); + add("http://www.smpte-ra.org/ns/2067-21/2020"); }}); private static final Set namespacesApplication5Composition = Collections.unmodifiableSet(new HashSet() {{ diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2013.java b/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2013.java index 7c8b5d25..f8c4aa2e 100755 --- a/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2013.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2013.java @@ -62,6 +62,22 @@ private CompositionModel_st2067_2_2013(){ // Parse the ApplicationIdentification values Set applicationIDs = parseApplicationIds(compositionPlaylistType, imfErrorLogger); + // Identify the Core Constraints version + String coreConstraintsSchema = CoreConstraints.fromApplicationId(applicationIDs); + if (coreConstraintsSchema == null) + { + // Get the namespaces of each Sequence being used + Set sequenceNamespaces = compositionPlaylistType.getSegmentList().getSegment().get(0) + .getSequenceList().getAny().stream().filter(JAXBElement.class::isInstance) + .map(je -> ((JAXBElement) je).getName().getNamespaceURI()).collect(Collectors.toSet()); + // Find the Core Constraints version, based on the namespaces of the Sequences + coreConstraintsSchema = CoreConstraints.fromElementNamespaces(sequenceNamespaces); + + // If all else fails, assume the minimum version applicable to this CPL version + if (coreConstraintsSchema == null) + coreConstraintsSchema = CoreConstraints.NAMESPACE_IMF_2013; + } + return new IMFCompositionPlaylistType( compositionPlaylistType.getId(), compositionPlaylistType.getEditRate(), (compositionPlaylistType.getAnnotation() == null ? null : compositionPlaylistType.getAnnotation().getValue()), @@ -71,7 +87,8 @@ private CompositionModel_st2067_2_2013(){ (compositionPlaylistType.getContentTitle() == null ? null : compositionPlaylistType.getContentTitle().getValue()), segmentList, essenceDescriptorList, - "org.smpte_ra.schemas.st2067_2_2013", applicationIDs + coreConstraintsSchema, + applicationIDs ); } diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2016.java b/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2016.java index 8a871220..968e0dd5 100755 --- a/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2016.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/CompositionModel_st2067_2_2016.java @@ -62,6 +62,22 @@ private CompositionModel_st2067_2_2016(){ // Parse the ApplicationIdentification values Set applicationIDs = parseApplicationIds(compositionPlaylistType, imfErrorLogger); + // Identify the Core Constraints version + String coreConstraintsSchema = CoreConstraints.fromApplicationId(applicationIDs); + if (coreConstraintsSchema == null) + { + // Get the namespaces of each Sequence being used + Set sequenceNamespaces = compositionPlaylistType.getSegmentList().getSegment().get(0) + .getSequenceList().getAny().stream().filter(JAXBElement.class::isInstance) + .map(je -> ((JAXBElement) je).getName().getNamespaceURI()).collect(Collectors.toSet()); + // Find the Core Constraints version, based on the namespaces of the Sequences + coreConstraintsSchema = CoreConstraints.fromElementNamespaces(sequenceNamespaces); + + // If all else fails, assume the minimum version applicable to this CPL version + if (coreConstraintsSchema == null) + coreConstraintsSchema = CoreConstraints.NAMESPACE_IMF_2016; + } + return new IMFCompositionPlaylistType( compositionPlaylistType.getId(), compositionPlaylistType.getEditRate(), (compositionPlaylistType.getAnnotation() == null ? null : compositionPlaylistType.getAnnotation().getValue()), @@ -71,7 +87,8 @@ private CompositionModel_st2067_2_2016(){ (compositionPlaylistType.getContentTitle() == null ? null : compositionPlaylistType.getContentTitle().getValue()), segmentList, essenceDescriptorList, - "org.smpte_ra.schemas.st2067_2_2016", applicationIDs + coreConstraintsSchema, + applicationIDs ); } @@ -290,7 +307,8 @@ private static JAXBContext createJAXBContext() try { return JAXBContext.newInstance( - org.smpte_ra.schemas.st2067_2_2016.ObjectFactory.class); // 2016 CPL and Core constraints + org.smpte_ra.schemas.st2067_2_2016.ObjectFactory.class, // 2016 CPL and Core constraints + org.smpte_ra.schemas.st2067_2_2020.ObjectFactory.class); // 2020 Core constraints also use 2016 CPL } catch(JAXBException e) { @@ -311,6 +329,7 @@ private static Schema createValidationSchema() InputStream xsd_dcmlTypes = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st0433_2008/dcmlTypes/dcmlTypes.xsd"); InputStream xsd_cpl_2016 = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st2067_3_2016/imf-cpl-20160411.xsd"); InputStream xsd_core_constraints_2016 = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st2067_2_2016/imf-core-constraints-20160411.xsd"); + InputStream xsd_core_constraints_2020 = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st2067_2_2020/imf-core-constraints-2020.xsd") ) { // Build a schema from all of the XSD files provided @@ -320,6 +339,7 @@ private static Schema createValidationSchema() new StreamSource(xsd_dcmlTypes), new StreamSource(xsd_cpl_2016), new StreamSource(xsd_core_constraints_2016), + new StreamSource(xsd_core_constraints_2020), }); } catch(IOException | SAXException e) @@ -328,15 +348,4 @@ private static Schema createValidationSchema() } } } - - /** - * Getter for the CoreConstraintsURI corresponding to this CompositionPlaylist - * - * @return the uri for the CoreConstraints schema for this CompositionPlaylist - * @deprecated This is an instance method of a class declared final, with a private constructor. Should never be callable - */ - @Deprecated - public String getCoreConstraintsVersion() { - return "org.smpte_ra.schemas.st2067_2_2016"; - } } \ No newline at end of file diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/CoreConstraints.java b/src/main/java/com/netflix/imflibrary/st2067_2/CoreConstraints.java new file mode 100644 index 00000000..6b36d474 --- /dev/null +++ b/src/main/java/com/netflix/imflibrary/st2067_2/CoreConstraints.java @@ -0,0 +1,88 @@ +package com.netflix.imflibrary.st2067_2; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public final class CoreConstraints +{ + private CoreConstraints() {} // Prevent instantiation. This class is constants and utilities only + + // SMPTE ST 2067-2 version namespaces + public static final String NAMESPACE_IMF_2013 = "http://www.smpte-ra.org/schemas/2067-2/2013"; + public static final String NAMESPACE_IMF_2016 = "http://www.smpte-ra.org/schemas/2067-2/2016"; + public static final String NAMESPACE_IMF_2020 = "http://www.smpte-ra.org/ns/2067-2/2020"; + + static final List SUPPORTED_NAMESPACES = Collections.unmodifiableList(Arrays.asList( + NAMESPACE_IMF_2013, NAMESPACE_IMF_2016, NAMESPACE_IMF_2020)); + + /** + * @deprecated Remove once all deprecated, package-based, 'getCoreConstraintsVersion' methods are removed. + */ + @Deprecated + static String packageFromSchema(String coreConstraintsSchema) + { + if (coreConstraintsSchema.equals(NAMESPACE_IMF_2013)) + return "org.smpte_ra.schemas.st2067_2_2013"; + else if (coreConstraintsSchema.equals(NAMESPACE_IMF_2016)) + return "org.smpte_ra.schemas.st2067_2_2016"; + else if (coreConstraintsSchema.equals(NAMESPACE_IMF_2020)) + return "org.smpte_ra.schemas.st2067_2_2020"; + else + return coreConstraintsSchema; // No mapping, just return the schema value + } + + // Determine the highest Core Constraints version based on the ApplicationIds used + @Nullable public static String fromApplicationId(@Nonnull Collection applicationIds) + { + // NOTE- When adding new namespaces or core constraint versions, be sure that the most recent core constraints + // are checked first. That way if there are multiple ApplicationIdentifications, the newest version is returned. + if (applicationIds.contains(Application2ExtendedComposition.SCHEMA_URI_APP2E_2020)) + { + return CoreConstraints.NAMESPACE_IMF_2020; + } + else if (applicationIds.contains(Application5Composition.SCHEMA_URI_APP5_2017) + || applicationIds.contains(Application2ExtendedComposition.SCHEMA_URI_APP2E_2016) + || applicationIds.contains(Application2Composition.SCHEMA_URI_APP2_2016)) + { + return CoreConstraints.NAMESPACE_IMF_2016; + } + else if (applicationIds.contains(Application2ExtendedComposition.SCHEMA_URI_APP2E_2014) + || applicationIds.contains(Application2Composition.SCHEMA_URI_APP2_2013)) + { + return CoreConstraints.NAMESPACE_IMF_2013; + } + else + { + return null; + } + } + + // Determine the most recent core constraints version, based on a collection of element namespaces + static String fromElementNamespaces(@Nonnull Collection namespaces) + { + // NOTE- When adding new namespaces or core constraint versions, be sure that the most recent core constraints + // are checked first. That way if there are multiple different namespaces, the newest version is returned. + if (namespaces.contains(CoreConstraints.NAMESPACE_IMF_2020)) + { + return CoreConstraints.NAMESPACE_IMF_2020; + } + else if (namespaces.contains(CoreConstraints.NAMESPACE_IMF_2016)) + { + return CoreConstraints.NAMESPACE_IMF_2016; + } + else if (namespaces.contains(CoreConstraints.NAMESPACE_IMF_2013)) + { + return CoreConstraints.NAMESPACE_IMF_2013; + } + else + { + // TODO- Consider identify core constraints based on other namespaces + // Example- IABSequence "http://www.smpte-ra.org/ns/2067-201/2019" requires core constraints ST 2067-2:2016 + return null; + } + } +} diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/IMFCompositionPlaylistType.java b/src/main/java/com/netflix/imflibrary/st2067_2/IMFCompositionPlaylistType.java index b01b52d5..6ddb1579 100644 --- a/src/main/java/com/netflix/imflibrary/st2067_2/IMFCompositionPlaylistType.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/IMFCompositionPlaylistType.java @@ -60,7 +60,7 @@ final class IMFCompositionPlaylistType { private final List segmentList; private final List essenceDescriptorList; private final IMFErrorLogger imfErrorLogger; - private final String coreConstraintsVersion; + private final String coreConstraintsSchema; private final Set applicationIdSet; /** @@ -79,10 +79,10 @@ public IMFCompositionPlaylistType(String id, String contentTitle, List segmentList, List essenceDescriptorList, - String coreConstraintsVersion, + String coreConstraintsSchema, String applicationId) { - this(id, editRate, annotation, issuer, creator, contentOriginator, contentTitle, segmentList, essenceDescriptorList, coreConstraintsVersion, (applicationId == null ? new HashSet<>() : new HashSet(Arrays.asList(applicationId)))); + this(id, editRate, annotation, issuer, creator, contentOriginator, contentTitle, segmentList, essenceDescriptorList, coreConstraintsSchema, (applicationId == null ? new HashSet<>() : new HashSet(Arrays.asList(applicationId)))); } public IMFCompositionPlaylistType(String id, @@ -94,7 +94,7 @@ public IMFCompositionPlaylistType(String id, String contentTitle, List segmentList, List essenceDescriptorList, - String coreConstraintsVersion, + String coreConstraintsSchema, @Nonnull Set applicationIds) { this.id = UUIDHelper.fromUUIDAsURNStringToUUID(id); @@ -117,7 +117,7 @@ public IMFCompositionPlaylistType(String id, this.contentTitle = contentTitle; this.segmentList = Collections.unmodifiableList(segmentList); this.essenceDescriptorList = Collections.unmodifiableList(essenceDescriptorList); - this.coreConstraintsVersion = coreConstraintsVersion; + this.coreConstraintsSchema = coreConstraintsSchema; this.applicationIdSet = Collections.unmodifiableSet(applicationIds); if(imfErrorLogger.hasFatalErrors()) @@ -318,12 +318,12 @@ public List getEssenceDescriptorList(){ } /** - * Getter for the CoreConstraintsURI corresponding to this CompositionPlaylist + * Getter for the CoreConstraints URI corresponding to this CompositionPlaylist * * @return the uri for the CoreConstraints schema for this CompositionPlaylist */ - public String getCoreConstraintsVersion() { - return this.coreConstraintsVersion; + @Nonnull public String getCoreConstraintsSchema() { + return this.coreConstraintsSchema; } /** diff --git a/src/main/java/com/netflix/imflibrary/st2067_2/IMFCoreConstraintsChecker.java b/src/main/java/com/netflix/imflibrary/st2067_2/IMFCoreConstraintsChecker.java index 66120f3a..5998f9d1 100644 --- a/src/main/java/com/netflix/imflibrary/st2067_2/IMFCoreConstraintsChecker.java +++ b/src/main/java/com/netflix/imflibrary/st2067_2/IMFCoreConstraintsChecker.java @@ -274,7 +274,11 @@ else if( virtualTrack.getSequenceTypeEnum().equals(Composition.SequenceTypeEnum. } //Section 6.3.2 st2067-2:2016 and Section 6.9.3 st2067-3:2016 - if(!foundMainAudioEssence){ + //Section 6.3.2 st2067-2:2020 allows CPLs without Audio Virtual Tracks + if(!foundMainAudioEssence + && (compositionPlaylistType.getCoreConstraintsSchema().equals(CoreConstraints.NAMESPACE_IMF_2013) + || compositionPlaylistType.getCoreConstraintsSchema().equals(CoreConstraints.NAMESPACE_IMF_2016))) + { imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, String.format("The Composition represented by Id %s does not contain a single audio essence in its first segment, one or more is required", compositionPlaylistType.getId().toString())); } diff --git a/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2013.java b/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2013.java index 91e972a5..57e47e12 100755 --- a/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2013.java +++ b/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2013.java @@ -22,6 +22,7 @@ import com.netflix.imflibrary.IMFErrorLoggerImpl; import com.netflix.imflibrary.exceptions.IMFAuthoringException; import com.netflix.imflibrary.st2067_2.Composition; +import com.netflix.imflibrary.st2067_2.CoreConstraints; import com.netflix.imflibrary.st2067_2.IMFEssenceComponentVirtualTrack; import com.netflix.imflibrary.st2067_2.IMFEssenceDescriptorBaseType; import com.netflix.imflibrary.st2067_2.IMFMarkerResourceType; @@ -36,7 +37,6 @@ import org.smpte_ra.schemas.st2067_2_2013.CompositionPlaylistType; import org.smpte_ra.schemas.st2067_2_2013.CompositionTimecodeType; import org.smpte_ra.schemas.st2067_2_2013.ContentVersionType; -import org.smpte_ra.schemas.st2067_2_2013.SequenceType; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; @@ -63,10 +63,12 @@ import java.math.BigInteger; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -94,10 +96,9 @@ public class CompositionPlaylistBuilder_2013 { public final static String defaultHashAlgorithm = "http://www.w3.org/2000/09/xmldsig#sha1"; private final static String defaultContentKindScope = "http://www.smpte-ra.org/schemas/2067-3/XXXX#content-kind"; private final String cplFileName; - - private final String applicationId; - Map trackResourceSourceEncodingMap; - + private final String coreConstraintsSchema; + private final Set applicationIds; + private final Map trackResourceSourceEncodingMap; /** * A constructor for CompositionPlaylistBuilder class to build a CompositionPlaylist document compliant with st2067-2:2013 schema @@ -107,11 +108,12 @@ public class CompositionPlaylistBuilder_2013 { * @param creator a free form human readable text describing the tool used to create the CompositionPlaylist document * @param virtualTracks a list of VirtualTracks of the Composition * @param compositionEditRate the edit rate of the Composition - * @param applicationId ApplicationId for the composition + * @param applicationIds ApplicationIds for the composition * @param totalRunningTime a long value representing in seconds the total running time of this composition * @param trackFileInfoMap a map of the IMFTrackFile's UUID to the track file info * @param workingDirectory a folder location where the constructed CPL document can be written to * @param imfEssenceDescriptorBaseTypeList List of IMFEssenceDescriptorBaseType + * @param coreConstraintsSchema schema defining core constraints version */ public CompositionPlaylistBuilder_2013(@Nonnull UUID uuid, @Nonnull org.smpte_ra.schemas.st2067_2_2013.UserTextType annotationText, @@ -119,29 +121,29 @@ public CompositionPlaylistBuilder_2013(@Nonnull UUID uuid, @Nonnull org.smpte_ra.schemas.st2067_2_2013.UserTextType creator, @Nonnull List virtualTracks, @Nonnull Composition.EditRate compositionEditRate, - @Nonnull String applicationId, + @Nonnull Set applicationIds, long totalRunningTime, @Nonnull Map trackFileInfoMap, @Nonnull File workingDirectory, - @Nonnull List imfEssenceDescriptorBaseTypeList){ + @Nonnull List imfEssenceDescriptorBaseTypeList, + @Nonnull String coreConstraintsSchema){ this.uuid = uuid; this.annotationText = annotationText; this.issuer = issuer; this.creator = creator; this.issueDate = IMFUtils.createXMLGregorianCalendar(); this.virtualTracks = Collections.unmodifiableList(virtualTracks); - List editRate = new ArrayList() {{add(compositionEditRate.getNumerator()); - add(compositionEditRate.getDenominator());}}; - this.compositionEditRate = Collections.unmodifiableList(editRate); + this.compositionEditRate = Collections.unmodifiableList(Arrays.asList(compositionEditRate.getNumerator(), compositionEditRate.getDenominator())); this.totalRunningTime = totalRunningTime; this.trackFileInfoMap = Collections.unmodifiableMap(trackFileInfoMap); this.workingDirectory = workingDirectory; this.imfErrorLogger = new IMFErrorLoggerImpl(); - cplFileName = "CPL-" + this.uuid.toString() + ".xml"; - this.applicationId = applicationId; - this.trackResourceSourceEncodingMap = new HashMap<>();//Map of TrackFileId -> SourceEncodingElement of each resource of this VirtualTrack + this.cplFileName = "CPL-" + this.uuid.toString() + ".xml"; + this.applicationIds = Collections.unmodifiableSet(applicationIds); this.imfEssenceDescriptorBaseTypeList = Collections.unmodifiableList(imfEssenceDescriptorBaseTypeList); + this.coreConstraintsSchema = coreConstraintsSchema; + Map trackEncodingMap = new HashMap<>(); //Map of TrackFileId -> SourceEncodingElement of each resource of this VirtualTrack for(Composition.VirtualTrack virtualTrack : virtualTracks) { if (!(virtualTrack instanceof IMFEssenceComponentVirtualTrack)) { continue; // Skip non-essence tracks @@ -149,13 +151,42 @@ public CompositionPlaylistBuilder_2013(@Nonnull UUID uuid, IMFEssenceComponentVirtualTrack essenceTrack = (IMFEssenceComponentVirtualTrack) virtualTrack; for (IMFTrackFileResourceType trackResource : essenceTrack.getTrackFileResourceList()) { - UUID sourceEncoding = trackResourceSourceEncodingMap.get(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId())); + UUID sourceEncoding = trackEncodingMap.get(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId())); if (sourceEncoding == null) { - trackResourceSourceEncodingMap.put(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId()), UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getSourceEncoding())); + trackEncodingMap.put(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId()), UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getSourceEncoding())); } } } + this.trackResourceSourceEncodingMap = Collections.unmodifiableMap(trackEncodingMap); + } + /** + * A constructor for CompositionPlaylistBuilder class to build a CompositionPlaylist document compliant with st2067-2:2013 schema + * @param uuid identifying the CompositionPlaylist document + * @param annotationText a free form human readable text + * @param issuer a free form human readable text describing the issuer of the CompositionPlaylist document + * @param creator a free form human readable text describing the tool used to create the CompositionPlaylist document + * @param virtualTracks a list of VirtualTracks of the Composition + * @param compositionEditRate the edit rate of the Composition + * @param applicationId ApplicationId for the composition + * @param totalRunningTime a long value representing in seconds the total running time of this composition + * @param trackFileInfoMap a map of the IMFTrackFile's UUID to the track file info + * @param workingDirectory a folder location where the constructed CPL document can be written to + * @param imfEssenceDescriptorBaseTypeList List of IMFEssenceDescriptorBaseType + */ + @Deprecated + public CompositionPlaylistBuilder_2013(@Nonnull UUID uuid, + @Nonnull org.smpte_ra.schemas.st2067_2_2013.UserTextType annotationText, + @Nonnull org.smpte_ra.schemas.st2067_2_2013.UserTextType issuer, + @Nonnull org.smpte_ra.schemas.st2067_2_2013.UserTextType creator, + @Nonnull List virtualTracks, + @Nonnull Composition.EditRate compositionEditRate, + @Nonnull String applicationId, + long totalRunningTime, + @Nonnull Map trackFileInfoMap, + @Nonnull File workingDirectory, + @Nonnull List imfEssenceDescriptorBaseTypeList){ + this(uuid, annotationText, issuer, creator, virtualTracks, compositionEditRate, Collections.singleton(applicationId), totalRunningTime, trackFileInfoMap, workingDirectory, imfEssenceDescriptorBaseTypeList, CoreConstraints.NAMESPACE_IMF_2013); } @@ -172,6 +203,7 @@ public CompositionPlaylistBuilder_2013(@Nonnull UUID uuid, * @param trackFileInfoMap a map of the IMFTrackFile's UUID to the track file info * @param workingDirectory a folder location where the constructed CPL document can be written to */ + @Deprecated public CompositionPlaylistBuilder_2013(@Nonnull UUID uuid, @Nonnull org.smpte_ra.schemas.st2067_2_2013.UserTextType annotationText, @Nonnull org.smpte_ra.schemas.st2067_2_2013.UserTextType issuer, @@ -241,24 +273,15 @@ public List build() throws IOException, ParserConfigura cplRoot.setSegmentList(buildSegmentList(new ArrayList(){{add(segmentType);}})); cplRoot.setSigner(null); cplRoot.setSignature(null); - try { - String nodeString = "" + - this.applicationId + - ""; - - Element element = DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(nodeString.getBytes("UTF-8"))) - .getDocumentElement(); + if (!this.applicationIds.isEmpty()) + { + JAXBElement> appIdElement = new org.smpte_ra.schemas.st2067_2_2013.ObjectFactory() + .createApplicationIdentification(new ArrayList<>(this.applicationIds)); + org.smpte_ra.schemas.st2067_2_2013.CompositionPlaylistType.ExtensionProperties extensionProperties = new org.smpte_ra.schemas.st2067_2_2013.CompositionPlaylistType.ExtensionProperties(); - extensionProperties.getAny().add(element); + extensionProperties.getAny().add(appIdElement); cplRoot.setExtensionProperties( extensionProperties); } - catch(SAXException ex) { - imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, - "Failed to create DOM node for ApplicationIdentification"); - } File outputFile = new File(this.workingDirectory + File.separator + this.cplFileName); List errors = serializeCPLToXML(cplRoot, outputFile); diff --git a/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2016.java b/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2016.java index 9b230e83..55cd48c4 100755 --- a/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2016.java +++ b/src/main/java/com/netflix/imflibrary/writerTools/CompositionPlaylistBuilder_2016.java @@ -21,6 +21,7 @@ import com.netflix.imflibrary.IMFErrorLoggerImpl; import com.netflix.imflibrary.exceptions.IMFAuthoringException; import com.netflix.imflibrary.st2067_2.Composition; +import com.netflix.imflibrary.st2067_2.CoreConstraints; import com.netflix.imflibrary.st2067_2.IMFEssenceComponentVirtualTrack; import com.netflix.imflibrary.st2067_2.IMFEssenceDescriptorBaseType; import com.netflix.imflibrary.st2067_2.IMFMarkerResourceType; @@ -37,7 +38,7 @@ import org.smpte_ra.schemas.st2067_2_2016.ContentVersionType; import org.smpte_ra.schemas.st2067_2_2016.EssenceDescriptorBaseType; import org.smpte_ra.schemas.st2067_2_2016.SegmentType; -import org.smpte_ra.schemas.st2067_2_2016.SequenceType; +import org.smpte_ra.schemas.st2067_2_2016.UserTextType; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; @@ -64,10 +65,12 @@ import java.math.BigInteger; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -94,23 +97,25 @@ public class CompositionPlaylistBuilder_2016 { public final static String defaultHashAlgorithm = "http://www.w3.org/2000/09/xmldsig#sha1"; private final static String defaultContentKindScope = "http://www.smpte-ra.org/schemas/2067-3/XXXX#content-kind"; private final String cplFileName; - private final String applicationId; - Map trackResourceSourceEncodingMap; + private final Set applicationIds; + private final String coreConstraintsSchema; + private final Map trackResourceSourceEncodingMap; /** - * A constructor for CompositionPlaylistBuilder class to build a CompositionPlaylist document compliant with st2067-2:2013 schema + * A constructor for CompositionPlaylistBuilder class to build a CompositionPlaylist document compliant with st2067-2:2016 schema * @param uuid identifying the CompositionPlaylist document * @param annotationText a free form human readable text * @param issuer a free form human readable text describing the issuer of the CompositionPlaylist document * @param creator a free form human readable text describing the tool used to create the CompositionPlaylist document * @param virtualTracks a list of VirtualTracks of the Composition * @param compositionEditRate the edit rate of the Composition - * @param applicationId ApplicationId for the composition + * @param applicationIds ApplicationIds for the composition * @param totalRunningTime a long value representing in seconds the total running time of this composition * @param trackFileInfoMap a map of the IMFTrackFile's UUID to the track file info * @param workingDirectory a folder location where the constructed CPL document can be written to * @param imfEssenceDescriptorBaseTypeList List of IMFEssenceDescriptorBaseType + * @param coreConstraintsSchema schema defining core constraints version */ public CompositionPlaylistBuilder_2016(@Nonnull UUID uuid, @Nonnull org.smpte_ra.schemas.st2067_2_2016.UserTextType annotationText, @@ -118,29 +123,29 @@ public CompositionPlaylistBuilder_2016(@Nonnull UUID uuid, @Nonnull org.smpte_ra.schemas.st2067_2_2016.UserTextType creator, @Nonnull List virtualTracks, @Nonnull Composition.EditRate compositionEditRate, - @Nonnull String applicationId, + @Nonnull Set applicationIds, long totalRunningTime, @Nonnull Map trackFileInfoMap, @Nonnull File workingDirectory, - @Nonnull List imfEssenceDescriptorBaseTypeList){ + @Nonnull List imfEssenceDescriptorBaseTypeList, + @Nonnull String coreConstraintsSchema){ this.uuid = uuid; this.annotationText = annotationText; this.issuer = issuer; this.creator = creator; this.issueDate = IMFUtils.createXMLGregorianCalendar(); this.virtualTracks = Collections.unmodifiableList(virtualTracks); - List editRate = new ArrayList() {{add(compositionEditRate.getNumerator()); - add(compositionEditRate.getDenominator());}}; - this.compositionEditRate = Collections.unmodifiableList(editRate); + this.compositionEditRate = Collections.unmodifiableList(Arrays.asList(compositionEditRate.getNumerator(), compositionEditRate.getDenominator())); this.totalRunningTime = totalRunningTime; this.trackFileInfoMap = Collections.unmodifiableMap(trackFileInfoMap); this.workingDirectory = workingDirectory; this.imfErrorLogger = new IMFErrorLoggerImpl(); - cplFileName = "CPL-" + this.uuid.toString() + ".xml"; - this.applicationId = applicationId; - this.trackResourceSourceEncodingMap = new HashMap<>();//Map of TrackFileId -> SourceEncodingElement of each resource of this VirtualTrack + this.cplFileName = "CPL-" + this.uuid.toString() + ".xml"; + this.applicationIds = Collections.unmodifiableSet(applicationIds); this.imfEssenceDescriptorBaseTypeList = Collections.unmodifiableList(imfEssenceDescriptorBaseTypeList); + this.coreConstraintsSchema = coreConstraintsSchema; + Map trackEncodingMap = new HashMap<>(); //Map of TrackFileId -> SourceEncodingElement of each resource of this VirtualTrack for(Composition.VirtualTrack virtualTrack : virtualTracks) { if (!(virtualTrack instanceof IMFEssenceComponentVirtualTrack)) { continue; // Skip non-essence tracks @@ -148,13 +153,43 @@ public CompositionPlaylistBuilder_2016(@Nonnull UUID uuid, IMFEssenceComponentVirtualTrack essenceTrack = (IMFEssenceComponentVirtualTrack) virtualTrack; for (IMFTrackFileResourceType trackResource : essenceTrack.getTrackFileResourceList()) { - UUID sourceEncoding = trackResourceSourceEncodingMap.get(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId())); + UUID sourceEncoding = trackEncodingMap.get(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId())); if (sourceEncoding == null) { - trackResourceSourceEncodingMap.put(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId()), UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getSourceEncoding())); + trackEncodingMap.put(UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getTrackFileId()), UUIDHelper.fromUUIDAsURNStringToUUID(trackResource.getSourceEncoding())); } } } + this.trackResourceSourceEncodingMap = Collections.unmodifiableMap(trackEncodingMap); + } + /** + * @deprecated Instead use {{@link #CompositionPlaylistBuilder_2016(UUID, UserTextType, UserTextType, UserTextType, List, Composition.EditRate, Set, long, Map, File, List, String)}} + * A constructor for CompositionPlaylistBuilder class to build a CompositionPlaylist document compliant with st2067-2:2016 schema + * @param uuid identifying the CompositionPlaylist document + * @param annotationText a free form human readable text + * @param issuer a free form human readable text describing the issuer of the CompositionPlaylist document + * @param creator a free form human readable text describing the tool used to create the CompositionPlaylist document + * @param virtualTracks a list of VirtualTracks of the Composition + * @param compositionEditRate the edit rate of the Composition + * @param applicationId ApplicationId for the composition + * @param totalRunningTime a long value representing in seconds the total running time of this composition + * @param trackFileInfoMap a map of the IMFTrackFile's UUID to the track file info + * @param workingDirectory a folder location where the constructed CPL document can be written to + * @param imfEssenceDescriptorBaseTypeList List of IMFEssenceDescriptorBaseType + */ + @Deprecated + public CompositionPlaylistBuilder_2016(@Nonnull UUID uuid, + @Nonnull org.smpte_ra.schemas.st2067_2_2016.UserTextType annotationText, + @Nonnull org.smpte_ra.schemas.st2067_2_2016.UserTextType issuer, + @Nonnull org.smpte_ra.schemas.st2067_2_2016.UserTextType creator, + @Nonnull List virtualTracks, + @Nonnull Composition.EditRate compositionEditRate, + @Nonnull String applicationId, + long totalRunningTime, + @Nonnull Map trackFileInfoMap, + @Nonnull File workingDirectory, + @Nonnull List imfEssenceDescriptorBaseTypeList){ + this(uuid, annotationText, issuer, creator, virtualTracks, compositionEditRate, Collections.singleton(applicationId), totalRunningTime, trackFileInfoMap, workingDirectory, imfEssenceDescriptorBaseTypeList, CoreConstraints.NAMESPACE_IMF_2016); } /** @@ -217,24 +252,25 @@ public List build() throws IOException, ParserConfigura cplRoot.setSegmentList(buildSegmentList(new ArrayList(){{add(segmentType);}})); cplRoot.setSigner(null); cplRoot.setSignature(null); - try { - String nodeString = "" + - this.applicationId + - ""; - - Element element = DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(nodeString.getBytes("UTF-8"))) - .getDocumentElement(); + + if (!this.applicationIds.isEmpty()) + { + JAXBElement> appIdElement; + if (this.coreConstraintsSchema.equals(CoreConstraints.NAMESPACE_IMF_2020)) + { + appIdElement = new org.smpte_ra.schemas.st2067_2_2020.ObjectFactory().createApplicationIdentification(new ArrayList<>(this.applicationIds)); + } + else + { + appIdElement = new org.smpte_ra.schemas.st2067_2_2016.ObjectFactory().createApplicationIdentification(new ArrayList<>(this.applicationIds)); + } + org.smpte_ra.schemas.st2067_2_2016.CompositionPlaylistType.ExtensionProperties extensionProperties = new org.smpte_ra.schemas.st2067_2_2016.CompositionPlaylistType.ExtensionProperties(); - extensionProperties.getAny().add(element); + extensionProperties.getAny().add(appIdElement); cplRoot.setExtensionProperties( extensionProperties); } - catch(SAXException ex) { - imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, - "Failed to create DOM node for ApplicationIdentification"); - }File outputFile = new File(this.workingDirectory + File.separator + this.cplFileName); + + File outputFile = new File(this.workingDirectory + File.separator + this.cplFileName); serializeCPLToXML(cplRoot, outputFile); return imfErrorLogger.getErrors(); } @@ -260,7 +296,8 @@ else if (virtualTrack instanceof IMFMarkerVirtualTrack) return Collections.unmodifiableList(trackResourceList); } - private void serializeCPLToXML(org.smpte_ra.schemas.st2067_2_2016.CompositionPlaylistType cplRoot, File outputFile) throws IOException, JAXBException, SAXException{ + // TODO- Refactor this and consolidate all marshall/unmarshall logic into CompositionModel_st2067_2_2016.java + private void serializeCPLToXML(org.smpte_ra.schemas.st2067_2_2016.CompositionPlaylistType cplRoot, File outputFile) throws IOException, JAXBException, SAXException{ int numErrors = imfErrorLogger.getNumberOfErrors(); boolean formatted = true; @@ -270,18 +307,22 @@ private void serializeCPLToXML(org.smpte_ra.schemas.st2067_2_2016.CompositionPla InputStream dcmlSchemaAsAStream = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st0433_2008/dcmlTypes/dcmlTypes.xsd"); InputStream cplSchemaAsAStream = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st2067_3_2016/imf-cpl-20160411.xsd"); InputStream coreConstraintsSchemaAsAStream = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st2067_2_2016/imf-core-constraints-20160411.xsd"); + InputStream xsd_core_constraints_2020 = contextClassLoader.getResourceAsStream("org/smpte_ra/schemas/st2067_2_2020/imf-core-constraints-2020.xsd"); OutputStream outputStream = new FileOutputStream(outputFile) ) { SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI ); - StreamSource[] schemaSources = new StreamSource[4]; + StreamSource[] schemaSources = new StreamSource[5]; schemaSources[0] = new StreamSource(dsigSchemaAsAStream); schemaSources[1] = new StreamSource(dcmlSchemaAsAStream); schemaSources[2] = new StreamSource(cplSchemaAsAStream); schemaSources[3] = new StreamSource(coreConstraintsSchemaAsAStream); + schemaSources[4] = new StreamSource(xsd_core_constraints_2020); Schema schema = schemaFactory.newSchema(schemaSources); - JAXBContext jaxbContext = JAXBContext.newInstance("org.smpte_ra.schemas.st2067_2_2016"); + JAXBContext jaxbContext = JAXBContext.newInstance( + org.smpte_ra.schemas.st2067_2_2016.ObjectFactory.class, // 2016 CPL and Core constraints + org.smpte_ra.schemas.st2067_2_2020.ObjectFactory.class); // 2020 Core constraints also use 2016 CPL Marshaller marshaller = jaxbContext.createMarshaller(); ValidationEventHandlerImpl validationEventHandler = new ValidationEventHandlerImpl(true); marshaller.setEventHandler(validationEventHandler); @@ -522,29 +563,56 @@ public org.smpte_ra.schemas.st2067_2_2016.SequenceType.ResourceList buildResourc */ public void populateSequenceListForSegment(List sequenceTypeTuples, org.smpte_ra.schemas.st2067_2_2016.SegmentType segment) { - - org.smpte_ra.schemas.st2067_2_2016.ObjectFactory objectFactory = new org.smpte_ra.schemas.st2067_2_2016.ObjectFactory(); List any = segment.getSequenceList().getAny(); - - for(SequenceTypeTuple sequenceTypeTuple : sequenceTypeTuples){ - switch(sequenceTypeTuple.getSequenceType()){ - case MainImageSequence: - any.add(objectFactory.createMainImageSequence(sequenceTypeTuple.getSequence())); - break; - case MainAudioSequence: - any.add(objectFactory.createMainAudioSequence(sequenceTypeTuple.getSequence())); - break; - case IABSequence: - any.add(objectFactory.createIABSequence(sequenceTypeTuple.getSequence())); - break; - case MarkerSequence: - segment.getSequenceList().setMarkerSequence(sequenceTypeTuple.getSequence()); - break; - default: - throw new IMFAuthoringException(String.format("Currently we only support %s, %s, %s, and %s sequence types in building a Composition Playlist document, the type of sequence being requested is %s", - Composition.SequenceTypeEnum.MainAudioSequence, Composition.SequenceTypeEnum.MainImageSequence, Composition.SequenceTypeEnum.IABSequence, Composition.SequenceTypeEnum.MarkerSequence, sequenceTypeTuple.getSequenceType())); + if (this.coreConstraintsSchema.equals(CoreConstraints.NAMESPACE_IMF_2020)) + { + org.smpte_ra.schemas.st2067_2_2020.ObjectFactory objectFactory = new org.smpte_ra.schemas.st2067_2_2020.ObjectFactory(); + for(SequenceTypeTuple sequenceTypeTuple : sequenceTypeTuples){ + switch(sequenceTypeTuple.getSequenceType()){ + case MainImageSequence: + any.add(objectFactory.createMainImageSequence(sequenceTypeTuple.getSequence())); + break; + case MainAudioSequence: + any.add(objectFactory.createMainAudioSequence(sequenceTypeTuple.getSequence())); + break; + case IABSequence: + // JAXB class for IABSequence was generated in the CC 2016 package. Use that + any.add(new org.smpte_ra.schemas.st2067_2_2016.ObjectFactory() + .createIABSequence(sequenceTypeTuple.getSequence())); + break; + case MarkerSequence: + segment.getSequenceList().setMarkerSequence(sequenceTypeTuple.getSequence()); + break; + default: + throw new IMFAuthoringException(String.format("Currently we only support %s, %s, %s, and %s sequence types in building a Composition Playlist document, the type of sequence being requested is %s", + Composition.SequenceTypeEnum.MainAudioSequence, Composition.SequenceTypeEnum.MainImageSequence, Composition.SequenceTypeEnum.IABSequence, Composition.SequenceTypeEnum.MarkerSequence, sequenceTypeTuple.getSequenceType())); + } } } + else + { + org.smpte_ra.schemas.st2067_2_2016.ObjectFactory objectFactory = new org.smpte_ra.schemas.st2067_2_2016.ObjectFactory(); + for(SequenceTypeTuple sequenceTypeTuple : sequenceTypeTuples){ + switch(sequenceTypeTuple.getSequenceType()){ + case MainImageSequence: + any.add(objectFactory.createMainImageSequence(sequenceTypeTuple.getSequence())); + break; + case MainAudioSequence: + any.add(objectFactory.createMainAudioSequence(sequenceTypeTuple.getSequence())); + break; + case IABSequence: + any.add(objectFactory.createIABSequence(sequenceTypeTuple.getSequence())); + break; + case MarkerSequence: + segment.getSequenceList().setMarkerSequence(sequenceTypeTuple.getSequence()); + break; + default: + throw new IMFAuthoringException(String.format("Currently we only support %s, %s, %s, and %s sequence types in building a Composition Playlist document, the type of sequence being requested is %s", + Composition.SequenceTypeEnum.MainAudioSequence, Composition.SequenceTypeEnum.MainImageSequence, Composition.SequenceTypeEnum.IABSequence, Composition.SequenceTypeEnum.MarkerSequence, sequenceTypeTuple.getSequenceType())); + } + } + } + } /** diff --git a/src/main/java/com/netflix/imflibrary/writerTools/IMPBuilder.java b/src/main/java/com/netflix/imflibrary/writerTools/IMPBuilder.java index d1362896..fdbfbd3e 100755 --- a/src/main/java/com/netflix/imflibrary/writerTools/IMPBuilder.java +++ b/src/main/java/com/netflix/imflibrary/writerTools/IMPBuilder.java @@ -11,6 +11,7 @@ import com.netflix.imflibrary.st0377.header.InterchangeObject; import com.netflix.imflibrary.st2067_2.AbstractApplicationComposition; import com.netflix.imflibrary.st2067_2.Composition; +import com.netflix.imflibrary.st2067_2.CoreConstraints; import com.netflix.imflibrary.st2067_2.IMFEssenceComponentVirtualTrack; import com.netflix.imflibrary.st2067_2.IMFEssenceDescriptorBaseType; import com.netflix.imflibrary.st2067_2.IMFTrackFileResourceType; @@ -40,6 +41,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -133,6 +135,10 @@ public static List buildIMP_2013(@Nonnull String annota IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl(); int numErrors = imfErrorLogger.getNumberOfErrors(); UUID cplUUID = IMFUUIDGenerator.getInstance().generateUUID(); + Set applicationIds = Collections.singleton(applicationId); + String coreConstraintsSchema = CoreConstraints.fromApplicationId(applicationIds); + if (coreConstraintsSchema == null) + coreConstraintsSchema = CoreConstraints.NAMESPACE_IMF_2013; Composition.VirtualTrack mainImageVirtualTrack = null; for(Composition.VirtualTrack virtualTrack : virtualTracks){ @@ -177,11 +183,12 @@ public static List buildIMP_2013(@Nonnull String annota CompositionPlaylistBuilder_2013.buildCPLUserTextType_2013("Photon PackingListBuilder", "en"), virtualTracks, compositionEditRate, - applicationId, + applicationIds, totalRunningTime, trackFileInfoMap, workingDirectory, - imfEssenceDescriptorBaseTypeList); + imfEssenceDescriptorBaseTypeList, + coreConstraintsSchema); imfErrorLogger.addAllErrors(compositionPlaylistBuilder_2013.build()); @@ -372,6 +379,10 @@ public static List buildIMP_2016(@Nonnull String annota IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl(); int numErrors = imfErrorLogger.getNumberOfErrors(); UUID cplUUID = IMFUUIDGenerator.getInstance().generateUUID(); + Set applicationIds = Collections.singleton(applicationId); + String coreConstraintsSchema = CoreConstraints.fromApplicationId(applicationIds); + if (coreConstraintsSchema == null) + coreConstraintsSchema = CoreConstraints.NAMESPACE_IMF_2016; Composition.VirtualTrack mainImageVirtualTrack = null; for(Composition.VirtualTrack virtualTrack : virtualTracks){ @@ -416,11 +427,12 @@ public static List buildIMP_2016(@Nonnull String annota CompositionPlaylistBuilder_2016.buildCPLUserTextType_2016("Photon PackingListBuilder", "en"), virtualTracks, compositionEditRate, - applicationId, + applicationIds, totalRunningTime, trackFileInfoMap, workingDirectory, - imfEssenceDescriptorBaseTypeList); + imfEssenceDescriptorBaseTypeList, + coreConstraintsSchema); imfErrorLogger.addAllErrors(compositionPlaylistBuilder_2016.build()); diff --git a/src/main/resources/org/smpte_ra/schemas/st2067_21_2016/app2e-2016.xsd b/src/main/resources/org/smpte_ra/schemas/st2067_21_2016/app2e-2016.xsd new file mode 100644 index 00000000..e0965148 --- /dev/null +++ b/src/main/resources/org/smpte_ra/schemas/st2067_21_2016/app2e-2016.xsd @@ -0,0 +1,62 @@ + + + + + + + + + + + diff --git a/src/main/resources/org/smpte_ra/schemas/st2067_2_2020/imf-core-constraints-2020.xsd b/src/main/resources/org/smpte_ra/schemas/st2067_2_2020/imf-core-constraints-2020.xsd new file mode 100644 index 00000000..b97fa28f --- /dev/null +++ b/src/main/resources/org/smpte_ra/schemas/st2067_2_2020/imf-core-constraints-2020.xsd @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/netflix/imflibrary/st2067_2/CompositionTest.java b/src/test/java/com/netflix/imflibrary/st2067_2/CompositionTest.java index 99a0ac0d..9c8aff1b 100644 --- a/src/test/java/com/netflix/imflibrary/st2067_2/CompositionTest.java +++ b/src/test/java/com/netflix/imflibrary/st2067_2/CompositionTest.java @@ -333,4 +333,35 @@ public void compositionWithMultipleApplicationIdentificationFullyNegativeTest() ApplicationCompositionFactory.getApplicationComposition(inputFile, imfErrorLogger); Assert.assertEquals(imfErrorLogger.getErrors().size(), 2); } + + @Test + public void composition2020Test() throws IOException { + File inputFile = TestHelper.findResourceByPath + ("TestIMP/IMF-2020/CPL-2020_updated-core-constraints.xml"); + IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl(); + ApplicationComposition applicationComposition = ApplicationCompositionFactory.getApplicationComposition(inputFile, imfErrorLogger); + Assert.assertEquals(imfErrorLogger.getErrors().size(), 0); + Assert.assertEquals(applicationComposition.getCoreConstraintsSchema(), CoreConstraints.NAMESPACE_IMF_2020); + } + + @Test + public void composition2020WithoutAudioTrackTest() throws IOException { + File inputFile = TestHelper.findResourceByPath + ("TestIMP/IMF-2020/CPL-2020_no-audio-track.xml"); + IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl(); + ApplicationComposition applicationComposition = ApplicationCompositionFactory.getApplicationComposition(inputFile, imfErrorLogger); + Assert.assertEquals(imfErrorLogger.getErrors().size(), 0); + Assert.assertEquals(applicationComposition.getCoreConstraintsSchema(), CoreConstraints.NAMESPACE_IMF_2020); + } + + @Test + public void composition2016WithoutAudioTrackNegativeTest() throws IOException { + File inputFile = TestHelper.findResourceByPath + ("TestIMP/IMF-2020/CPL-2016_no-audio-track.xml"); + IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl(); + ApplicationComposition applicationComposition = ApplicationCompositionFactory.getApplicationComposition(inputFile, imfErrorLogger); + Assert.assertTrue(imfErrorLogger.getErrors().stream().anyMatch(e -> + e.getErrorCode() == IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR)); + Assert.assertNull(applicationComposition); + } } diff --git a/src/test/java/com/netflix/imflibrary/writerTools/IMPBuilderFunctionalTest.java b/src/test/java/com/netflix/imflibrary/writerTools/IMPBuilderFunctionalTest.java index 707e67c9..815300b0 100755 --- a/src/test/java/com/netflix/imflibrary/writerTools/IMPBuilderFunctionalTest.java +++ b/src/test/java/com/netflix/imflibrary/writerTools/IMPBuilderFunctionalTest.java @@ -27,6 +27,7 @@ import com.netflix.imflibrary.st0377.header.GenericPackage; import com.netflix.imflibrary.st0377.header.Preface; import com.netflix.imflibrary.st0377.header.SourcePackage; +import com.netflix.imflibrary.st2067_2.Application2ExtendedComposition; import com.netflix.imflibrary.st2067_2.ApplicationComposition; import com.netflix.imflibrary.st2067_2.ApplicationCompositionFactory; import com.netflix.imflibrary.utils.ByteArrayByteRangeProvider; @@ -76,6 +77,10 @@ private Object[][] getCplList() { {"TestIMP/Netflix_Sony_Plugfest_2015/CPL_BLACKL_202_HD_REC709_178_ENG_fe8cf2f4-1bcd-4145-8f72-6775af4038c4.xml", "2016", false, 0}, {"TestIMP/Netflix_Sony_Plugfest_2015/CPL_BLACKL_202_HD_REC709_178_ENG_fe8cf2f4-1bcd-4145-8f72-6775af4038c4_duplicate_source_encoding_element.xml", "2016", false, 0}, {"TestIMP/IAB/CompleteIMP/CPL_e0265fda-cb35-4e35-a4e4-4f44d82d2a52.xml", "2016", false, 0}, + {"TestIMP/IMF-2020/CPL-2020_no-audio-track.xml", "2020", false, 0}, + {"TestIMP/IMF-2020/CPL-2020_no-audio-track.xml", "2016", false, 1}, + {"TestIMP/Netflix_Sony_Plugfest_2015/CPL_BLACKL_202_HD_REC709_178_ENG_fe8cf2f4-1bcd-4145-8f72-6775af4038c4.xml", "2020", true, 1}, + {"TestIMP/Netflix_Sony_Plugfest_2015/CPL_BLACKL_202_HD_REC709_178_ENG_fe8cf2f4-1bcd-4145-8f72-6775af4038c4.xml", "2020", false, 0}, }; } @@ -105,7 +110,15 @@ private void buildIMPAndValidate(ApplicationComposition applicationComposition, "Netflix", applicationComposition.getVirtualTracks(), applicationComposition.getEditRate(), - "http://www.smpte-ra.org/schemas/2067-21/2016", + Application2ExtendedComposition.SCHEMA_URI_APP2E_2016, + buildTrackFileMetadataMap(imfErrorLogger), + tempDir); + } else if (schemaVersion.equals("2020")) { + IMPBuilder.buildIMP_2016("IMP", + "Netflix", + applicationComposition.getVirtualTracks(), + applicationComposition.getEditRate(), + Application2ExtendedComposition.SCHEMA_URI_APP2E_2020, buildTrackFileMetadataMap(imfErrorLogger), tempDir); } else if (schemaVersion.equals("2013")) { @@ -113,7 +126,7 @@ private void buildIMPAndValidate(ApplicationComposition applicationComposition, "Netflix", applicationComposition.getVirtualTracks(), applicationComposition.getEditRate(), - "http://www.smpte-ra.org/schemas/2067-21/2016", + Application2ExtendedComposition.SCHEMA_URI_APP2E_2014, buildTrackFileMetadataMap(imfErrorLogger), tempDir); } @@ -123,7 +136,16 @@ private void buildIMPAndValidate(ApplicationComposition applicationComposition, "Netflix", applicationComposition.getVirtualTracks(), applicationComposition.getEditRate(), - "http://www.smpte-ra.org/schemas/2067-21/2016", + Application2ExtendedComposition.SCHEMA_URI_APP2E_2016, + buildTrackFileInfoMap(imfErrorLogger), + tempDir, + applicationComposition.getEssenceDescriptorDomNodeMap()); + } else if (schemaVersion.equals("2020")) { + IMPBuilder.buildIMP_2016("IMP", + "Netflix", + applicationComposition.getVirtualTracks(), + applicationComposition.getEditRate(), + Application2ExtendedComposition.SCHEMA_URI_APP2E_2020, buildTrackFileInfoMap(imfErrorLogger), tempDir, applicationComposition.getEssenceDescriptorDomNodeMap()); @@ -132,7 +154,7 @@ private void buildIMPAndValidate(ApplicationComposition applicationComposition, "Netflix", applicationComposition.getVirtualTracks(), applicationComposition.getEditRate(), - "http://www.smpte-ra.org/schemas/2067-21/2016", + Application2ExtendedComposition.SCHEMA_URI_APP2E_2014, buildTrackFileInfoMap(imfErrorLogger), tempDir, applicationComposition.getEssenceDescriptorDomNodeMap()); diff --git a/src/test/resources/TestIMP/IMF-2020/CPL-2016_no-audio-track.xml b/src/test/resources/TestIMP/IMF-2020/CPL-2016_no-audio-track.xml new file mode 100644 index 00000000..11767baa --- /dev/null +++ b/src/test/resources/TestIMP/IMF-2020/CPL-2016_no-audio-track.xml @@ -0,0 +1,211 @@ + + + urn:uuid:82038b2e-8fdd-485d-884e-d71b9ba19de2 + 2020-08-06T11:00:00Z + Netflix + Manually Edited + Netflix + Photon Test- CPL 2016, No audio track. This violates st2067-2:2016 6.3.2 + + + urn:uuid:ee8a1971-e46b-47e9-8687-078495f48c59 + + urn:uuid:8674e535-879c-4042-bf9f-1780a4c0019c + + + CompRed + 10 + + + CompGreen + 10 + + + CompBlue + 10 + + + CompFill + 2 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + 0 + 1023 + ScanningDirection_LeftToRightTopToBottom + 0 + 0 + + 42 + 0 + + 0 + 0 + 1080 + 1920 + 1080 + 1920 + 1080 + 1920 + FullFrame + 16/9 + 24000/1001 + urn:smpte:ul:060e2b34.0401010d.04010202.03010113 + 255 + urn:smpte:ul:060e2b34.04010106.04010101.03030000 + urn:smpte:ul:060e2b34.04010101.04010101.01020000 + urn:smpte:ul:060e2b34.04010101.04010101.02020000 + 0 + + + urn:uuid:7a8500ed-bc85-4bbd-91aa-3374ce3af3ce + 259 + 1920 + 1080 + 0 + 0 + 1920 + 1080 + 0 + 0 + 3 + + + 9 + 1 + 1 + + + 9 + 1 + 1 + + + 9 + 1 + 1 + + + + + CompRed + 10 + + + CompGreen + 10 + + + CompBlue + 10 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + 01040001010503030000778888888888 + 22871e86ea86ea86bc7f007f007ee2774c774c776460036003604567d267d26761 + + + urn:smpte:ul:060e2b34.0401010d.0d010301.020c0600 + 2 + 240 + + + + urn:uuid:78a82f04-9118-482c-8f2f-87e75beaaa23 + + urn:uuid:f3c50ea8-a293-40b7-9640-bddd78faa528 + + + urn:uuid:42546c35-ab1e-44d0-a3da-8a6e7e2a7078 + urn:smpte:ul:060e2b34.0401010d.03020221.00000000 + urn:uuid:f3ebd314-3d98-43da-8b01-92de6efb31fc + IAB + IAB + en + + + 1 + 24000/1001 + 240 + urn:smpte:ul:060e2b34.0401010d.0d010301.021d0101 + 48000/1 + False + 0 + 24 + urn:smpte:ul:060e2b34.04010105.0e090604.00000000 + + + + 24000 1001 + + http://www.smpte-ra.org/schemas/2067-21/2016 + + + + urn:uuid:fde40176-48aa-44e1-bf0c-b8c5e0f85b8f + + + urn:uuid:0ded5e28-933f-405f-9c5f-5e1683814c1f + urn:uuid:86d10356-f32f-4006-8f22-acb380222a25 + + + urn:uuid:716bc90d-df98-4331-9781-bfb8aab3dc09 + 240 + 240 + urn:uuid:ee8a1971-e46b-47e9-8687-078495f48c59 + urn:uuid:418e4d1f-f5c7-4c71-8c62-6f796446de20 + + + + + urn:uuid:893eca6a-e09d-40b9-9958-e2d06765462e + urn:uuid:914b49d7-33d5-46fc-827e-9167bfda77a3 + + + urn:uuid:6a6294d3-f5ce-4663-9c29-2098679634f2 + 24000 1001 + 240 + 240 + urn:uuid:78a82f04-9118-482c-8f2f-87e75beaaa23 + urn:uuid:17c68559-b6de-4525-93f8-17c8ae77f599 + + + + + + + diff --git a/src/test/resources/TestIMP/IMF-2020/CPL-2020_no-audio-track.xml b/src/test/resources/TestIMP/IMF-2020/CPL-2020_no-audio-track.xml new file mode 100644 index 00000000..96a9d0c2 --- /dev/null +++ b/src/test/resources/TestIMP/IMF-2020/CPL-2020_no-audio-track.xml @@ -0,0 +1,211 @@ + + + urn:uuid:5eaad89f-79d5-4795-a712-3af4753c3d50 + 2020-08-06T11:00:00Z + Netflix + Manually Edited + Netflix + Photon Test- CPL 2020, No audio track + + + urn:uuid:ee8a1971-e46b-47e9-8687-078495f48c59 + + urn:uuid:8674e535-879c-4042-bf9f-1780a4c0019c + + + CompRed + 10 + + + CompGreen + 10 + + + CompBlue + 10 + + + CompFill + 2 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + 0 + 1023 + ScanningDirection_LeftToRightTopToBottom + 0 + 0 + + 42 + 0 + + 0 + 0 + 1080 + 1920 + 1080 + 1920 + 1080 + 1920 + FullFrame + 16/9 + 24000/1001 + urn:smpte:ul:060e2b34.0401010d.04010202.03010113 + 255 + urn:smpte:ul:060e2b34.04010106.04010101.03030000 + urn:smpte:ul:060e2b34.04010101.04010101.01020000 + urn:smpte:ul:060e2b34.04010101.04010101.02020000 + 0 + + + urn:uuid:7a8500ed-bc85-4bbd-91aa-3374ce3af3ce + 259 + 1920 + 1080 + 0 + 0 + 1920 + 1080 + 0 + 0 + 3 + + + 9 + 1 + 1 + + + 9 + 1 + 1 + + + 9 + 1 + 1 + + + + + CompRed + 10 + + + CompGreen + 10 + + + CompBlue + 10 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + 01040001010503030000778888888888 + 22871e86ea86ea86bc7f007f007ee2774c774c776460036003604567d267d26761 + + + urn:smpte:ul:060e2b34.0401010d.0d010301.020c0600 + 2 + 240 + + + + urn:uuid:78a82f04-9118-482c-8f2f-87e75beaaa23 + + urn:uuid:f3c50ea8-a293-40b7-9640-bddd78faa528 + + + urn:uuid:42546c35-ab1e-44d0-a3da-8a6e7e2a7078 + urn:smpte:ul:060e2b34.0401010d.03020221.00000000 + urn:uuid:f3ebd314-3d98-43da-8b01-92de6efb31fc + IAB + IAB + en + + + 1 + 24000/1001 + 240 + urn:smpte:ul:060e2b34.0401010d.0d010301.021d0101 + 48000/1 + False + 0 + 24 + urn:smpte:ul:060e2b34.04010105.0e090604.00000000 + + + + 24000 1001 + + http://www.smpte-ra.org/ns/2067-21/2020 + + + + urn:uuid:fde40176-48aa-44e1-bf0c-b8c5e0f85b8f + + + urn:uuid:0ded5e28-933f-405f-9c5f-5e1683814c1f + urn:uuid:86d10356-f32f-4006-8f22-acb380222a25 + + + urn:uuid:716bc90d-df98-4331-9781-bfb8aab3dc09 + 240 + 240 + urn:uuid:ee8a1971-e46b-47e9-8687-078495f48c59 + urn:uuid:418e4d1f-f5c7-4c71-8c62-6f796446de20 + + + + + urn:uuid:893eca6a-e09d-40b9-9958-e2d06765462e + urn:uuid:914b49d7-33d5-46fc-827e-9167bfda77a3 + + + urn:uuid:6a6294d3-f5ce-4663-9c29-2098679634f2 + 24000 1001 + 240 + 240 + urn:uuid:78a82f04-9118-482c-8f2f-87e75beaaa23 + urn:uuid:17c68559-b6de-4525-93f8-17c8ae77f599 + + + + + + + diff --git a/src/test/resources/TestIMP/IMF-2020/CPL-2020_updated-core-constraints.xml b/src/test/resources/TestIMP/IMF-2020/CPL-2020_updated-core-constraints.xml new file mode 100644 index 00000000..62a3387b --- /dev/null +++ b/src/test/resources/TestIMP/IMF-2020/CPL-2020_updated-core-constraints.xml @@ -0,0 +1,276 @@ + + + urn:uuid:48841f18-1998-468e-97a2-61e76c2e55dd + 2020-08-06T11:00:00Z + Netflix + Manually Edited + Netflix + Photon Test- CPL 2020 + + + urn:uuid:ee8a1971-e46b-47e9-8687-078495f48c59 + + urn:uuid:8674e535-879c-4042-bf9f-1780a4c0019c + + + CompRed + 10 + + + CompGreen + 10 + + + CompBlue + 10 + + + CompFill + 2 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + 0 + 1023 + ScanningDirection_LeftToRightTopToBottom + 0 + 0 + + 42 + 0 + + 0 + 0 + 1080 + 1920 + 1080 + 1920 + 1080 + 1920 + FullFrame + 16/9 + 24000/1001 + urn:smpte:ul:060e2b34.0401010d.04010202.03010113 + 255 + urn:smpte:ul:060e2b34.04010106.04010101.03030000 + urn:smpte:ul:060e2b34.04010101.04010101.01020000 + urn:smpte:ul:060e2b34.04010101.04010101.02020000 + 0 + + + urn:uuid:7a8500ed-bc85-4bbd-91aa-3374ce3af3ce + 259 + 1920 + 1080 + 0 + 0 + 1920 + 1080 + 0 + 0 + 3 + + + 9 + 1 + 1 + + + 9 + 1 + 1 + + + 9 + 1 + 1 + + + + + CompRed + 10 + + + CompGreen + 10 + + + CompBlue + 10 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + CompNull + 0 + + + 01040001010503030000778888888888 + 22871e86ea86ea86bc7f007f007ee2774c774c776460036003604567d267d26761 + + + urn:smpte:ul:060e2b34.0401010d.0d010301.020c0600 + 2 + 240 + + + + urn:uuid:9204a08f-e51a-49c5-91db-d98651aa20b8 + + urn:uuid:98990c3f-4733-4ae6-bf72-8a8d0a17fff1 + 48000/1 + 48000/1 + 2 + 24 + True + 0 + ElectroSpatialFormulation_Default + 6 + 288000 + urn:smpte:ul:060e2b34.0401010d.04020210.04010000 + + + urn:uuid:0018de35-b0d3-43fe-af1b-01492763a6ae + urn:smpte:ul:060e2b34.0401010d.03020101.00000000 + urn:uuid:09b93154-dbb9-4d36-8d35-369b97cfb772 + chL + Left + 1 + urn:uuid:8dc9dd54-bbe6-4a4e-ae07-69835da9ef5d + + + urn:uuid:4a8300e5-aaf4-41e7-8748-6653104d8587 + urn:smpte:ul:060e2b34.0401010d.03020102.00000000 + urn:uuid:1196b768-a9c3-4df7-8814-9c3f61dfa759 + chR + Right + 2 + urn:uuid:8dc9dd54-bbe6-4a4e-ae07-69835da9ef5d + + + urn:uuid:1daec10d-141a-4a00-bdc6-70ca6e3048d0 + urn:smpte:ul:060e2b34.0401010d.03020220.01000000 + urn:uuid:8dc9dd54-bbe6-4a4e-ae07-69835da9ef5d + sgST + Standard Stereo + Untitled Project + 2019-08-22T13:06:51 + Primary + PRM + en + + + urn:smpte:ul:060e2b34.04010101.0d010301.02060200 + 2 + 480480 + + + + urn:uuid:78a82f04-9118-482c-8f2f-87e75beaaa23 + + urn:uuid:f3c50ea8-a293-40b7-9640-bddd78faa528 + + + urn:uuid:42546c35-ab1e-44d0-a3da-8a6e7e2a7078 + urn:smpte:ul:060e2b34.0401010d.03020221.00000000 + urn:uuid:f3ebd314-3d98-43da-8b01-92de6efb31fc + IAB + IAB + en + + + 1 + 24000/1001 + 240 + urn:smpte:ul:060e2b34.0401010d.0d010301.021d0101 + 48000/1 + False + 0 + 24 + urn:smpte:ul:060e2b34.04010105.0e090604.00000000 + + + + 24000 1001 + + http://www.smpte-ra.org/ns/2067-21/2020 + + + + urn:uuid:fde40176-48aa-44e1-bf0c-b8c5e0f85b8f + + + urn:uuid:0ded5e28-933f-405f-9c5f-5e1683814c1f + urn:uuid:86d10356-f32f-4006-8f22-acb380222a25 + + + urn:uuid:716bc90d-df98-4331-9781-bfb8aab3dc09 + 240 + 240 + urn:uuid:ee8a1971-e46b-47e9-8687-078495f48c59 + urn:uuid:418e4d1f-f5c7-4c71-8c62-6f796446de20 + + + + + urn:uuid:77af2d39-5ed5-4f80-b157-6420b6fbc43b + urn:uuid:686dcf4b-645d-4187-8e20-c1306f22d796 + + + urn:uuid:6bc4c295-ec13-4109-9942-ad496a60d45b + 48000 1 + 480480 + 480480 + urn:uuid:9204a08f-e51a-49c5-91db-d98651aa20b8 + urn:uuid:299b877c-d40b-4f9e-aa22-4fadf7ebf2b9 + + + + + urn:uuid:893eca6a-e09d-40b9-9958-e2d06765462e + urn:uuid:914b49d7-33d5-46fc-827e-9167bfda77a3 + + + urn:uuid:6a6294d3-f5ce-4663-9c29-2098679634f2 + 24000 1001 + 240 + 240 + urn:uuid:78a82f04-9118-482c-8f2f-87e75beaaa23 + urn:uuid:17c68559-b6de-4525-93f8-17c8ae77f599 + + + + + + +