in src/main/java/com/netflix/imflibrary/IMFConstraints.java [72:315]
public static HeaderPartitionIMF checkIMFCompliance(MXFOperationalPattern1A.HeaderPartitionOP1A headerPartitionOP1A, @Nonnull IMFErrorLogger imfErrorLogger) throws IOException
{
int previousNumberOfErrors = imfErrorLogger.getErrors().size();
HeaderPartition headerPartition = headerPartitionOP1A.getHeaderPartition();
Preface preface = headerPartition.getPreface();
GenericPackage genericPackage = preface.getContentStorage().getEssenceContainerDataList().get(0).getLinkedPackage();
SourcePackage filePackage;
filePackage = (SourcePackage)genericPackage;
UUID packageID = filePackage.getPackageMaterialNumberasUUID();
//check 'Operational Pattern' field in Preface
byte[] bytes = preface.getOperationalPattern().getULAsBytes();
//Section 8.3.3 st377-1:2011 and Section 5.2 st2067-5:2013
if (OperationalPatternHelper.getPackageComplexity(bytes) != OperationalPatternHelper.PackageComplexity.SinglePackage)
{
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String
.format("IMFTrackFile represented by Id %s, Lower four bits of Operational Pattern qualifier byte = 0x%x, should be = 0x01 per the definition of OperationalPattern-1A for Package Complexity.",
packageID.toString(), bytes[13]));
}
//Section 8.3.3 st377-1:2011
if (OperationalPatternHelper.getItemComplexity(bytes) != OperationalPatternHelper.ItemComplexity.SingleItem)
{
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String
.format("IMFTrackFile represented by Id %s, Lower four bits of Operational Pattern qualifier byte = 0x%x, should be = 0x01 per the definition of OperationalPattern-1A for Item Complexity.",
packageID.toString(), bytes[12]));
}
//Section 5.1.1#13 st2067-5:2014 , primary package identifier for Preface shall be set to the top-level file package
if ((preface.getPrimaryPackage() == null) || (!preface.getPrimaryPackage().equals(preface.getContentStorage().getEssenceContainerDataList().get(0).getLinkedPackage())))
{
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("Primary package identifier for Preface is not set to the top-level file package in the IMFTrackFile represented by ID %s.", packageID.toString()));
}
//From st2067-5:2013 section 5.1.3, only one essence track shall exist in the file package
{
MXFUID packageUID = filePackage.getPackageUID();
byte[] packageUID_first16Bytes_Constrained = {0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01, 0x0f, 0x20, 0x13, 0x00, 0x00, 0x00};
byte[] packageUID_first16Bytes = Arrays.copyOfRange(packageUID.getUID(), 0, packageUID_first16Bytes_Constrained.length);
boolean result = packageUID_first16Bytes[0] == packageUID_first16Bytes_Constrained[0];
for(int i=1; i < packageUID_first16Bytes_Constrained.length ; i++){
result &= packageUID_first16Bytes[i] == packageUID_first16Bytes_Constrained[i];
}
//Section 5.1.5 st2067-2:2016
if(!result){
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("PackageUID in FilePackage = %s, which does not obey the constraint that the first 16 bytes = %s in the IMFTrackFile represented by ID %s.",
packageUID.toString(), Utilities.serializeBytesToHexString(packageUID_first16Bytes_Constrained), packageID.toString()));
}
int numEssenceTracks = 0;
MXFDataDefinition filePackageMxfDataDefinition = null;
for (TimelineTrack timelineTrack : filePackage.getTimelineTracks())
{
Sequence sequence = timelineTrack.getSequence();
filePackageMxfDataDefinition = sequence.getMxfDataDefinition();
if (!filePackageMxfDataDefinition.equals(MXFDataDefinition.OTHER))
{
numEssenceTracks++;
}
//Section 5.1.7 st2067-2:2016
if(timelineTrack.getOrigin() != 0){
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("The origin property of a timeline track in the IMFTrackFile represented by ID %s is non-zero, only 0 is allowed.", packageID));
}
}
if (numEssenceTracks != 1)
{
//Section 5.1.3 of SMPTE st2067-5:2013
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("Number of essence tracks in FilePackage %s = %d, which is different from 1, this is invalid in the IMFTrackFile represented by ID %s.",
filePackage.getInstanceUID(), numEssenceTracks, packageID.toString()));
}
}
//From st2067-2-2013 section 5.3.4.1, top-level file package shall reference a Wave Audio Essence Descriptor
//Per st2067-2-2013, section 5.3.4.2, Wave Audio Essence Descriptor shall have 'Channel Assignment' item
{
for (TimelineTrack timelineTrack : filePackage.getTimelineTracks()) {
Sequence sequence = timelineTrack.getSequence();
if (sequence == null) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("TimelineTrack with instanceUID = %s in the IMFTrackFile represented by ID %s has no sequence.",
timelineTrack.getInstanceUID(), packageID.toString()));
} else {
MXFDataDefinition filePackageMxfDataDefinition = sequence.getMxfDataDefinition();
GenericDescriptor genericDescriptor = filePackage.getGenericDescriptor();
if (filePackageMxfDataDefinition.equals(MXFDataDefinition.SOUND)) {
if (genericDescriptor instanceof WaveAudioEssenceDescriptor) {
WaveAudioEssenceDescriptor waveAudioEssenceDescriptor = (WaveAudioEssenceDescriptor) genericDescriptor;
if ((waveAudioEssenceDescriptor.getChannelAssignmentUL() == null) ||
(!waveAudioEssenceDescriptor.getChannelAssignmentUL().equals(new MXFUID(IMFConstraints.IMF_CHANNEL_ASSIGNMENT_UL)))) {
//Section 5.3.4.2 st2067-2:2016
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("ChannelAssignment UL for WaveAudioEssenceDescriptor = %s is different from %s in the IMFTrackFile represented by ID %s.",
waveAudioEssenceDescriptor.getChannelAssignmentUL(), new MXFUID(IMFConstraints.IMF_CHANNEL_ASSIGNMENT_UL), packageID.toString()));
}
//RFC-5646 spoken language is a part of the MCALabelSubDescriptor and SoundFieldGroupLabelSubdescriptors according to Section 5.3.6.5 st2067-2:2016 has language around RFC-5646 primary spoken language
if (headerPartition.getAudioEssenceSpokenLanguage() == null) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("WaveAudioEssenceDescriptor in the IMFTrackFile represented by ID %s does not have a RFC5646 spoken language indicated, language code shall be set in the SoundFieldGroupLabelSubDescriptor, unless the AudioEssence does not have a primary spoken language.", packageID.toString()));
} else {
//Section 6.3.6 st377-4:2012
if (!IMFConstraints.isSpokenLanguageRFC5646Compliant(headerPartition.getAudioEssenceSpokenLanguage())) {
List<String> strings = IMFConstraints.getPrimarySpokenLanguageUnicodeString(headerPartition.getAudioEssenceSpokenLanguage());
imfErrorLogger.addError(new ErrorLogger.ErrorObject(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, String.format("Language Code (%s) in SoundFieldGroupLabelSubdescriptor in the IMFTrackfile represented by ID %s is not RFC5646 compliant", strings, packageID.toString())));
}
}
//Section 5.3.3 st2067-2:2016 and Section 10 st0382:2007
if (!StructuralMetadata.isAudioWaveClipWrapped(waveAudioEssenceDescriptor.getEssenceContainerUL().getULAsBytes()[14])) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("WaveAudioEssenceDescriptor indicates that the Audio Essence within an Audio Track File is not Wave Clip-Wrapped in the IMFTrackFile represented by ID %s.", packageID.toString()));
}
List<InterchangeObject.InterchangeObjectBO> subDescriptors = headerPartition.getSubDescriptors();
//Section 5.3.6.2 st2067-2:2016
if (subDescriptors.size() == 0) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("WaveAudioEssenceDescriptor in the IMFTrackFile represented by ID %s indicates a channel count of %d, however there are %d AudioChannelLabelSubdescriptors, every audio channel should refer to exactly one AudioChannelLabelSubDescriptor and vice versa.", packageID.toString(), waveAudioEssenceDescriptor.getChannelCount(), subDescriptors.size()));
} else {
//Section 5.3.6.2 st2067-2:2016
Map<Long, AudioChannelLabelSubDescriptor> audioChannelLabelSubDescriptorMap = headerPartition.getAudioChannelIDToMCASubDescriptorMap();
if (waveAudioEssenceDescriptor.getChannelCount() == 0 || waveAudioEssenceDescriptor.getChannelCount() != audioChannelLabelSubDescriptorMap.size()) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("WaveAudioEssenceDescriptor in the IMFTrackFile represented by ID %s indicates a channel count of %d, however there are %d AudioChannelLabelSubdescriptors, every audio channel should refer to exactly one AudioChannelLabelSubDescriptor and vice versa.", packageID.toString(), waveAudioEssenceDescriptor.getChannelCount(), audioChannelLabelSubDescriptorMap.size()));
}
for (Long channelID = 1L; channelID <= waveAudioEssenceDescriptor.getChannelCount(); channelID++) {
//Section 5.3.6.5 st2067-2:2016
if (!audioChannelLabelSubDescriptorMap.containsKey(channelID)) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("AudioChannelLabelSubdescriptor missing for ChannelID %d, in the IMFTrackFile represented by ID %s", channelID, packageID.toString()));
}
}
List<InterchangeObject.InterchangeObjectBO> soundFieldGroupLabelSubDescriptors = subDescriptors.subList(0, subDescriptors.size()).stream().filter(interchangeObjectBO -> interchangeObjectBO.getClass().getEnclosingClass().equals(SoundFieldGroupLabelSubDescriptor.class)).collect(Collectors.toList());
//Section 5.3.6.3 st2067-2:2016
if (soundFieldGroupLabelSubDescriptors.size() != 1) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("WaveAudioEssenceDescriptor in the IMFTrackFile represented by ID %s refers to %d SoundFieldGroupLabelSubDescriptors exactly 1 is required", packageID.toString(), soundFieldGroupLabelSubDescriptors.size()));
} else {
SoundFieldGroupLabelSubDescriptor.SoundFieldGroupLabelSubDescriptorBO soundFieldGroupLabelSubDescriptorBO = SoundFieldGroupLabelSubDescriptor.SoundFieldGroupLabelSubDescriptorBO.class.cast(soundFieldGroupLabelSubDescriptors.get(0));
//Section 5.3.6.5 st2067-2:2016
if ((soundFieldGroupLabelSubDescriptorBO.getMCATitle() == null || soundFieldGroupLabelSubDescriptorBO.getMCATitle().isEmpty())
|| (soundFieldGroupLabelSubDescriptorBO.getMCATitleVersion() == null || soundFieldGroupLabelSubDescriptorBO.getMCATitleVersion().isEmpty())
|| (soundFieldGroupLabelSubDescriptorBO.getMCAAudioContentKind() == null || soundFieldGroupLabelSubDescriptorBO.getMCAAudioContentKind().isEmpty())
|| (soundFieldGroupLabelSubDescriptorBO.getMCAAudioElementKind() == null || soundFieldGroupLabelSubDescriptorBO.getMCAAudioElementKind().isEmpty())) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("WaveAudioEssenceDescriptor in the IMFTrackFile represented by ID %s refers to a SoundFieldGroupLabelSubDescriptor that is missing one/all of MCATitle, MCATitleVersion, MCAAudioContentKind, MCAAudioElementKind, %n%s.", packageID.toString(), soundFieldGroupLabelSubDescriptorBO.toString()));
}
SoundFieldGroupLabelSubDescriptor soundFieldGroupLabelSubDescriptor = (SoundFieldGroupLabelSubDescriptor) headerPartition.getSoundFieldGroupLabelSubDescriptors()
.get(0);
List<InterchangeObject> audioChannelLabelSubDescriptors = headerPartition.getAudioChannelLabelSubDescriptors();
//Section 6.3.2 st377-4:2012
if (soundFieldGroupLabelSubDescriptor.getMCALinkId() == null) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("SoundFieldGroupLabelSubDescriptor is missing MCALinkID, in the IMFTrackFile represented by ID %s",
packageID.toString()));
} else {
for (InterchangeObject interchangeObject : audioChannelLabelSubDescriptors) {
AudioChannelLabelSubDescriptor audioChannelLabelSubDescriptor = AudioChannelLabelSubDescriptor.class.cast(interchangeObject);
//Section 5.3.6.3 st2067-2:2016
if (audioChannelLabelSubDescriptor.getSoundfieldGroupLinkId() == null) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("Audio channel with MCALinkID %s is missing SoundfieldGroupLinkId, in the IMFTrackFile represented by ID %s",
audioChannelLabelSubDescriptor.getMCALinkId() != null ? audioChannelLabelSubDescriptor.getMCALinkId().toString() : "",
packageID.toString()));
}
//Section 6.3.2 st377-4:2012
else if (!audioChannelLabelSubDescriptor.getSoundfieldGroupLinkId()
.equals(soundFieldGroupLabelSubDescriptor.getMCALinkId())) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("Audio channel with MCALinkID %s refers to wrong SoundfieldGroupLinkId %s, Should refer to %s, in the IMFTrackFile represented by ID %s",
audioChannelLabelSubDescriptor.getMCALinkId() != null ? audioChannelLabelSubDescriptor.getMCALinkId().toString() : "",
audioChannelLabelSubDescriptor.getSoundfieldGroupLinkId().toString(),
soundFieldGroupLabelSubDescriptor.getMCALinkId().toString(),
packageID.toString()));
}
}
}
}
}
int audioSampleRate = waveAudioEssenceDescriptor.getAudioSamplingRateNumerator() / waveAudioEssenceDescriptor.getAudioSamplingRateDenominator();
//Section 5.3.2.2 st2067-2:2016
if (audioSampleRate != 48000
&& audioSampleRate != 96000) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("WaveAudioEssenceDescriptor in the IMFTrackFile represented by ID %s seems to indicate an Audio Sample Rate = %f, only 48000 and 96000 are allowed.", packageID.toString(), (double) waveAudioEssenceDescriptor.getAudioSamplingRateNumerator() / waveAudioEssenceDescriptor.getAudioSamplingRateDenominator()));
}
int bitDepth = waveAudioEssenceDescriptor.getQuantizationBits();
//Section 5.3.2.3 st2067-2:2016
if (bitDepth != 24) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMF_ESSENCE_EXCEPTION_PREFIX +
String.format("WaveAudioEssenceDescriptor in the IMFTrackFile represented by ID %s seems to indicate an Audio Bit Depth = %d, only 24 is allowed.", packageID.toString(), waveAudioEssenceDescriptor.getQuantizationBits()));
}
}
// else {//Section 5.3.4.1 st2067-2:2016
// imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, IMFConstraints.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("Header Partition does not have a WaveAudioEssenceDescriptor set in the IMFTrackFile represented by ID %s", packageID.toString()));
// }
} else if (filePackageMxfDataDefinition.equals(MXFDataDefinition.DATA)) {
if (genericDescriptor instanceof TimedTextDescriptor) {
TimedTextDescriptor timedTextDescriptor = TimedTextDescriptor.class.cast(genericDescriptor);
//Section 6.8 st2067-2:2016 and st0 429-5 section 7
if (timedTextDescriptor.getEssenceContainerUL().getULAsBytes()[13] != 0x13) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints
.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("Invalid Mapping Kind in TimedText essence container UL within IMFTrackFile represented by ID %s.",
packageID.toString()));
}
//https://www.w3.org/TR/ttml-imsc1/ Section 6.1
if (!timedTextDescriptor.getUCSEncoding().equalsIgnoreCase("UTF-8")) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints
.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("Invalid UCSEncoding(%s) in TimedTextDescriptor within trackFile represented by ID %s. Only UTF-8 is valid UCSEncoding. ",
timedTextDescriptor
.getUCSEncoding(),
packageID.toString()));
}
//https://www.w3.org/TR/ttml-imsc1/ Section 6.3
if (!(Arrays.asList(IMSC1TextProfileDesignators2020).contains(timedTextDescriptor.getNamespaceURI()) || Arrays.asList(IMSC1ImageProfileDesignators2020).contains(timedTextDescriptor.getNamespaceURI()))) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints
.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("Invalid NamespaceURI(%s) in TimedTextDescriptor within trackFile represented by ID %s. Valid NamespaceURIs: " +
"{%s}, {%s}",
timedTextDescriptor.getNamespaceURI(), packageID.toString(), Arrays.toString(IMSC1TextProfileDesignators2020), Arrays.toString(IMSC1ImageProfileDesignators2020)));
}
for(TimeTextResourceSubDescriptor textResourceSubDescriptor : timedTextDescriptor.getSubDescriptorList()) {
//Section 5.4.5 and 5.4.6 st2067-2:2016
if (!textResourceSubDescriptor.getMimeMediaType().equals(IMSC1ImageResourceMimeMediaType) && !textResourceSubDescriptor.getMimeMediaType().equals
(IMSC1FontResourceMimeMediaType)) {
imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CORE_CONSTRAINTS_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.NON_FATAL, IMFConstraints
.IMF_ESSENCE_EXCEPTION_PREFIX + String.format("Invalid MIMEMediaType(%s) in TimedTextResourceSubDescriptor within trackFile represented by ID %s. Valid " +
"MIMEMediaTypes: {%s} {%s}",
timedTextDescriptor.getNamespaceURI(), packageID.toString(), IMSC1ImageResourceMimeMediaType, IMSC1FontResourceMimeMediaType));
}
}
}
}
}
}
//TODO: data essence core constraints check st 2067-2, 2067-5 and 429-5
//TODO: check for data essence clip wrap
}
if(imfErrorLogger.hasFatalErrors(previousNumberOfErrors, imfErrorLogger.getNumberOfErrors())){
throw new IMFException(String.format("Found fatal errors in the in the IMFTrackFile represented by ID %s that violate the IMF Core constraints.", packageID.toString()), imfErrorLogger);
}
return new HeaderPartitionIMF(headerPartitionOP1A);
}