public static HeaderPartitionOP1A checkOperationalPattern1ACompliance()

in src/main/java/com/netflix/imflibrary/MXFOperationalPattern1A.java [63:286]


    public static HeaderPartitionOP1A checkOperationalPattern1ACompliance(@Nonnull HeaderPartition headerPartition, @Nonnull IMFErrorLogger imfErrorLogger)
    {
        int previousNumberOfErrors = imfErrorLogger.getErrors().size();
        Preface preface = headerPartition.getPreface();
        String trackFileID_Prefix = "";
        if(preface != null) {
            GenericPackage genericPackage = preface.getContentStorage().getEssenceContainerDataList().get(0).getLinkedPackage();
            SourcePackage filePackage;
            filePackage = (SourcePackage) genericPackage;
            UUID packageID = filePackage.getPackageMaterialNumberasUUID();
            trackFileID_Prefix = String.format("TrackFile ID : %s - ", packageID.toString());
        }

        //Section 9.5.1 st377-1:2011
        if(preface == null){
            imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Preface does not exist in the header partition, which is invalid."));
        }
        //Preface
        else
        {
            //check 'Operational Pattern' field in Preface
            byte[] bytes = preface.getOperationalPattern().getULAsBytes();
            for (int i=0; i< bytes.length; i++)
            {
                //An IMF track file shall conform to the OP1A requirements as mandated by Section 5.1.1 #10 st2067-5:2013
                if( (MXFOperationalPattern1A.OPERATIONAL_PATTERN1A_KEY_MASK[i] != 0) &&
                        (MXFOperationalPattern1A.OPERATIONAL_PATTERN1A_KEY[i] != bytes[i]) )
                {
                    imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Operational Pattern field in preface = 0x%x at position (zero-indexed) = %d, is different from expected value = 0x%x",
                            bytes[i], i, MXFOperationalPattern1A.OPERATIONAL_PATTERN1A_KEY[i]));
                }
            }

            //check number of essence containers ULs Section 9.4.3 st377-1:2011
            if (preface.getNumberOfEssenceContainerULs() < 1)
            {
                imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Number of EssenceContainer ULs in preface = %d, at least 1 is expected",
                        preface.getNumberOfEssenceContainerULs()));
            }
        }

        //Content Storage
        {
            //check number of Content Storage sets Section 9.5.2 st377-1:2011
            if (headerPartition.getContentStorageList().size() != 1)
            {
                imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Number of Content Storage sets in header partition = %d, is different from 1",
                        headerPartition.getContentStorageList().size()));
            }

            if(preface != null) {
                ContentStorage contentStorage = preface.getContentStorage();
                //Section 9.5.2 st377-1:2011
                if (contentStorage == null) {
                    imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("No Content Storage set was found in header partition"));
                }
                //check number of Essence Container Data sets referred by Content Storage Section 9.4.3 st377-1:2011
                else if (contentStorage.getNumberOfEssenceContainerDataSets() != 1) {
                    imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Number of EssenceContainerData sets referred by Content Storage = %d, is different from 1",
                            contentStorage.getNumberOfEssenceContainerDataSets()));
                }
            }
        }

        //check number of Essence Container Data sets
        {
            //Section 9.4.3 st377-1:2011
            if (headerPartition.getEssenceContainerDataList().size() != 1)
            {
                imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Number of EssenceContainerData sets = %d, is different from 1",
                        headerPartition.getEssenceContainerDataList().size()));
            }
        }

        //check number of Material Packages Section 5.1, Table-1 st378:2004
        if (headerPartition.getMaterialPackages().size() != 1)
        {
            imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Number of Material Packages in header partition = %d, is different from 1",
                    headerPartition.getMaterialPackages().size()));
        }

        //Material Package
        {
            MaterialPackage materialPackage = (MaterialPackage)headerPartition.getMaterialPackages().get(0);

            //check number of source clips per track of Material Package Section 5.1, Table-1 st378:2004
            for (TimelineTrack timelineTrack : materialPackage.getTimelineTracks())
            {
                Sequence sequence = timelineTrack.getSequence();
                //Section 9.5.3 st377-1:2011
                if (sequence == null)
                {
                    imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("TimelineTrack with instanceUID = %s has no sequence",
                            timelineTrack.getInstanceUID()));
                }
                else if (!sequence.getMxfDataDefinition().equals(MXFDataDefinition.OTHER))
                {
                    //Section 5.1, Table-1 st378:2004
                    if (sequence.getSourceClips().size() != 1)
                    {
                        imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Material Package Sequence with UID = %s has %d source clips, exactly one is allowed",
                                sequence.getInstanceUID(), sequence.getSourceClips().size()));
                    }
                }
            }

            //check if Material Package accesses a single source package Section 5.1, Table-1 st378:2004
            MXFUID referencedSourcePackageUMID = null;
            for (TimelineTrack timelineTrack : materialPackage.getTimelineTracks())
            {
                Sequence sequence = timelineTrack.getSequence();
                if (sequence != null
                        && !sequence.getMxfDataDefinition().equals(MXFDataDefinition.OTHER))
                {
                    MXFUID thisSourcePackageUMID = sequence.getSourceClips().get(0).getSourcePackageID();
                    if (referencedSourcePackageUMID == null)
                    {
                        referencedSourcePackageUMID = thisSourcePackageUMID;
                    }
                    else if (!referencedSourcePackageUMID.equals(thisSourcePackageUMID))
                    {
                        imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("SourceClipUID = %s refers to source package UID = %s different from other source clips that refer to source package UID = %s",
                                sequence.getInstanceUID(), thisSourcePackageUMID, referencedSourcePackageUMID));
                    }
                }
            }

            if(referencedSourcePackageUMID == null){
                imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Invalid source package UID, perhaps because one or more timelineTrack has no sequence"));
            }
            if(preface != null) {
                //check if SourcePackageID referenced from Material Package is present in ContentStorage
                ContentStorage contentStorage = preface.getContentStorage();
                if (contentStorage == null) {
                    imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("No Content Storage set was found in header partition"));
                } else {
                    boolean foundReferenceForReferencedSourcePackageUMIDInContentStorage = false;
                    for (SourcePackage sourcePackage : contentStorage.getSourcePackageList()) {
                        if (sourcePackage.getPackageUID().equals(referencedSourcePackageUMID)) {
                            foundReferenceForReferencedSourcePackageUMIDInContentStorage = true;
                            break;
                        }
                    }
                    if (!foundReferenceForReferencedSourcePackageUMIDInContentStorage) {
                        imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Content Storage does not refer to Source Package with packageUID = %s", referencedSourcePackageUMID));
                    }

                    //check if SourcePackageID referenced from Material Package is the same as that referred by EssenceContainer Data set
                    MXFUID linkedPackageUID = contentStorage.getEssenceContainerDataList().get(0).getLinkedPackageUID();
                    if (referencedSourcePackageUMID != null
                            && !linkedPackageUID.equals(referencedSourcePackageUMID)) {
                        imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Package UID = %s referred by EssenceContainerData set is different from %s which is referred by Material Package",
                                linkedPackageUID, referencedSourcePackageUMID));
                    }
                }
            }
        }

        //check if all tracks across the Material Package and the top-level File Package have the same duration st377-1:2011
        double sequenceDuration = 0.0;
        {
            MaterialPackage materialPackage = (MaterialPackage)headerPartition.getMaterialPackages().get(0);
            for (TimelineTrack timelineTrack : materialPackage.getTimelineTracks())
            {

                long thisEditRateNumerator = timelineTrack.getEditRateNumerator();
                long thisEditRateDenominator = timelineTrack.getEditRateDenominator();
                if (thisEditRateNumerator == 0)
                {
                    imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Timeline Track %s has invalid edit rate : numerator = %d, denominator = %d",
                            timelineTrack.getInstanceUID(), thisEditRateNumerator, thisEditRateDenominator));
                }

                Sequence sequence = timelineTrack.getSequence();

                if (sequence != null
                        && !sequence.getMxfDataDefinition().equals(MXFDataDefinition.OTHER))
                {
                    double thisSequenceDuration = ((double)sequence.getDuration()*(double)thisEditRateDenominator)/(double)thisEditRateNumerator;
                    if (Math.abs(sequenceDuration) < MXFOperationalPattern1A.EPSILON)
                    {
                        sequenceDuration = thisSequenceDuration;
                    }
                    else if (Math.abs(sequenceDuration - thisSequenceDuration) > MXFOperationalPattern1A.TOLERANCE)
                    {
                        imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Material Package SequenceUID = %s is associated with duration = %f, which is different from expected value %f",
                                sequence.getInstanceUID(), thisSequenceDuration, sequenceDuration));
                    }
                }
            }

            if(preface != null
                    && preface.getContentStorage() != null) {
                SourcePackage filePackage = (SourcePackage) preface.getContentStorage().getEssenceContainerDataList().get(0).getLinkedPackage();
                for (TimelineTrack timelineTrack : filePackage.getTimelineTracks()) {

                    long thisEditRateNumerator = timelineTrack.getEditRateNumerator();
                    long thisEditRateDenominator = timelineTrack.getEditRateDenominator();
                    if (thisEditRateNumerator == 0) {
                        imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("Timeline Track %s has invalid edit rate : numerator = %d, denominator = %d",
                                timelineTrack.getInstanceUID(), thisEditRateNumerator, thisEditRateDenominator));
                    }

                    Sequence sequence = timelineTrack.getSequence();
                    if (sequence != null
                            && !sequence.getMxfDataDefinition().equals(MXFDataDefinition.OTHER)) {
                        double thisSequenceDuration = ((double) sequence.getDuration() * (double) thisEditRateDenominator) / (double) thisEditRateNumerator;
                        if (Math.abs(sequenceDuration) < MXFOperationalPattern1A.EPSILON) {
                            sequenceDuration = thisSequenceDuration;
                        } else if (Math.abs(sequenceDuration - thisSequenceDuration) > MXFOperationalPattern1A.TOLERANCE) {
                            imfErrorLogger.addError(IMFErrorLogger.IMFErrors.ErrorCodes.IMF_ESSENCE_COMPONENT_ERROR, IMFErrorLogger.IMFErrors.ErrorLevels.FATAL, MXFOperationalPattern1A.OP1A_EXCEPTION_PREFIX + trackFileID_Prefix + String.format("File Package SequenceUID = %s is associated with duration = %f, which is different from expected value %f",
                                    sequence.getInstanceUID(), thisSequenceDuration, sequenceDuration));
                        }
                    }
                }
            }

        }

        if(imfErrorLogger.hasFatalErrors(previousNumberOfErrors, imfErrorLogger.getNumberOfErrors())){
            throw new MXFException(String.format("Found fatal errors in the IMFTrackFile that violate IMF OP1A compliance"), imfErrorLogger);
        }
        return new HeaderPartitionOP1A(headerPartition);
    }