Example #1
0
  public static List<ErrorLogger.ErrorObject> conformVirtualTracksInCPL(
      PayloadRecord cplPayloadRecord,
      List<PayloadRecord> essencesHeaderPartitionPayloads,
      boolean conformAllVirtualTracks)
      throws IOException {

    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    List<PayloadRecord> essencesHeaderPartition =
        Collections.unmodifiableList(essencesHeaderPartitionPayloads);

    try {
      imfErrorLogger.addAllErrors(validateCPL(cplPayloadRecord));
      if (imfErrorLogger.hasFatalErrors())
        return Collections.unmodifiableList(imfErrorLogger.getErrors());

      Composition composition =
          new Composition(new ByteArrayByteRangeProvider(cplPayloadRecord.getPayload()));

      imfErrorLogger.addAllErrors(validateIMFTrackFileHeaderMetadata(essencesHeaderPartition));

      List<HeaderPartitionTuple> headerPartitionTuples = new ArrayList<>();
      for (PayloadRecord payloadRecord : essencesHeaderPartition) {
        if (payloadRecord.getPayloadAssetType()
            != PayloadRecord.PayloadAssetType.EssencePartition) {
          imfErrorLogger.addError(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMF_MASTER_PACKAGE_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.FATAL,
              String.format(
                  "Payload asset type is %s, expected asset type %s",
                  payloadRecord.getPayloadAssetType(),
                  PayloadRecord.PayloadAssetType.EssencePartition.toString()));
          continue;
        }
        headerPartitionTuples.add(
            new HeaderPartitionTuple(
                new HeaderPartition(
                    new ByteArrayDataProvider(payloadRecord.getPayload()),
                    0L,
                    (long) payloadRecord.getPayload().length,
                    imfErrorLogger),
                new ByteArrayByteRangeProvider(payloadRecord.getPayload())));
      }

      if (imfErrorLogger.hasFatalErrors()) {
        return imfErrorLogger.getErrors();
      }

      imfErrorLogger.addAllErrors(
          composition.conformVirtualTracksInComposition(
              Collections.unmodifiableList(headerPartitionTuples), conformAllVirtualTracks));

      imfErrorLogger.addAllErrors(composition.getErrors());
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }

    return imfErrorLogger.getErrors();
  }
Example #2
0
  /**
   * A stateless method to retrieve all the VirtualTracks that are a part of a Composition
   *
   * @param cpl - a payload corresponding to the Composition Playlist
   * @return list of VirtualTracks
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<? extends VirtualTrack> getVirtualTracks(PayloadRecord cpl)
      throws IOException {
    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    List<ErrorLogger.ErrorObject> errorList = validateCPL(cpl);

    imfErrorLogger.addAllErrors(errorList);

    if (imfErrorLogger.hasFatalErrors()) {
      throw new IMFException("Virtual track failed validation", imfErrorLogger);
    }

    Composition composition = new Composition(new ByteArrayByteRangeProvider(cpl.getPayload()));
    return composition.getVirtualTracks();
  }
Example #3
0
  /**
   * A stateless method that will validate an IMF Composition document
   *
   * @param cpl - a payload record for a Composition document
   * @return list of error messages encountered while validating an AssetMap document
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> validateCPL(PayloadRecord cpl) throws IOException {
    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    if (cpl.getPayloadAssetType() != PayloadRecord.PayloadAssetType.CompositionPlaylist) {
      throw new IMFException(
          String.format(
              "Payload asset type is %s, expected asset type %s",
              cpl.getPayloadAssetType(),
              PayloadRecord.PayloadAssetType.CompositionPlaylist.toString()));
    }

    try {
      Composition composition = new Composition(new ByteArrayByteRangeProvider(cpl.getPayload()));
      imfErrorLogger.addAllErrors(composition.getErrors());
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }
    return imfErrorLogger.getErrors();
  }
Example #4
0
  /**
   * A stateless method that can be used to determine if a Composition is conformant. Conformance
   * checks perform deeper inspection of the Composition and the EssenceDescriptors corresponding to
   * all the Virtual Tracks that are a part of the Composition
   *
   * @param cplPayloadRecord a payload record corresponding to the Composition payload
   * @param essencesHeaderPartitionPayloads list of payload records containing the raw bytes of the
   *     HeaderPartitions of the IMF Track files that are a part of the Virtual Track/s in the
   *     Composition
   * @return list of error messages encountered while performing conformance validation of the
   *     Composition document
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> areAllVirtualTracksInCPLConformed(
      PayloadRecord cplPayloadRecord, List<PayloadRecord> essencesHeaderPartitionPayloads)
      throws IOException {

    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    Composition composition =
        new Composition(new ByteArrayByteRangeProvider(cplPayloadRecord.getPayload()));

    imfErrorLogger.addAllErrors(composition.getErrors());

    List<VirtualTrack> virtualTracks = new ArrayList<>(composition.getVirtualTracks());
    imfErrorLogger.addAllErrors(
        checkVirtualTrackAndEssencesHeaderPartitionPayloadRecords(
            virtualTracks, essencesHeaderPartitionPayloads));
    if (imfErrorLogger.hasFatalErrors()) {
      return imfErrorLogger.getErrors();
    }
    imfErrorLogger.addAllErrors(
        conformVirtualTracksInCPL(cplPayloadRecord, essencesHeaderPartitionPayloads, true));

    return imfErrorLogger.getErrors();
  }
Example #5
0
  /**
   * A stateless method that determines if the Asset type of the payload is an IMF AssetMap,
   * Packinglist or Composition
   *
   * @param payloadRecord - a payload record corresponding to the asset whose type needs to be
   *     confirmed Note: for now this method only supports text/xml documents identified in the PKL
   *     application/mxf asset types cannot be determined.
   * @return asset type of the payload either one of AssetMap, PackingList or Composition
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static PayloadRecord.PayloadAssetType getPayloadType(PayloadRecord payloadRecord)
      throws IOException {

    ResourceByteRangeProvider resourceByteRangeProvider =
        new ByteArrayByteRangeProvider(payloadRecord.getPayload());
    if (AssetMap.isFileOfSupportedSchema(resourceByteRangeProvider)) {
      return PayloadRecord.PayloadAssetType.AssetMap;
    } else if (PackingList.isFileOfSupportedSchema(resourceByteRangeProvider)) {
      return PayloadRecord.PayloadAssetType.PackingList;
    } else if (Composition.isCompositionPlaylist(resourceByteRangeProvider)) {
      return PayloadRecord.PayloadAssetType.CompositionPlaylist;
    }
    return PayloadRecord.PayloadAssetType.Unknown;
  }
Example #6
0
  /**
   * A stateless method that determines if 2 or more Composition documents corresponding to the same
   * title can be inferred to represent the same presentation timeline. This method is present to
   * work around current limitations in the IMF eco system wherein CPL's might not be built
   * incrementally to include all the IMF essences that are a part of the same timeline
   *
   * @param referenceCPLPayloadRecord - a payload record corresponding to a Reference Composition
   *     document, perhaps the first composition playlist document that was delivered for a
   *     particular composition.
   * @param cplPayloads - a list of payload records corresponding to each of the Composition
   *     documents that need to be verified for mergeability
   * @return a boolean indicating if the CPLs can be merged or not
   * @throws IOException - any I/O related error is exposed through an IOException
   */
  public static List<ErrorLogger.ErrorObject> isCPLMergeable(
      PayloadRecord referenceCPLPayloadRecord, List<PayloadRecord> cplPayloads) throws IOException {

    IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
    List<PayloadRecord> cplPayloadRecords = Collections.unmodifiableList(cplPayloads);
    List<Composition> compositions = new ArrayList<>();
    try {
      compositions.add(
          new Composition(new ByteArrayByteRangeProvider(referenceCPLPayloadRecord.getPayload())));
    } catch (IMFException e) {
      imfErrorLogger.addAllErrors(e.getErrors());
    }

    for (PayloadRecord cpl : cplPayloadRecords) {
      try {
        compositions.add(new Composition(new ByteArrayByteRangeProvider(cpl.getPayload())));
      } catch (IMFException e) {
        imfErrorLogger.addAllErrors(e.getErrors());
      }
    }

    if (imfErrorLogger.hasFatalErrors()) {
      return imfErrorLogger.getErrors();
    }

    VirtualTrack referenceVideoVirtualTrack = compositions.get(0).getVideoVirtualTrack();
    UUID referenceCPLUUID = compositions.get(0).getUUID();
    for (int i = 1; i < compositions.size(); i++) {
      if (!referenceVideoVirtualTrack.equivalent(compositions.get(i).getVideoVirtualTrack())) {
        imfErrorLogger.addError(
            IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR,
            IMFErrorLogger.IMFErrors.ErrorLevels.WARNING,
            String.format(
                "CPL Id %s can't be merged with Reference CPL Id %s, since the video virtual tracks do not seem to represent the same timeline.",
                compositions.get(i).getUUID(), referenceCPLUUID));
      }
    }

    /**
     * Perform AudioTrack mergeability checks 1) Identify AudioTracks that are the same language 2)
     * Compare language tracks to see if they represent the same timeline
     */
    Boolean bAudioVirtualTrackMapFail = false;
    List<Map<Set<DOMNodeObjectModel>, ? extends VirtualTrack>> audioVirtualTracksMapList =
        new ArrayList<>();
    for (Composition composition : compositions) {
      try {
        audioVirtualTracksMapList.add(composition.getAudioVirtualTracksMap());
      } catch (IMFException e) {
        bAudioVirtualTrackMapFail = false;
        imfErrorLogger.addAllErrors(e.getErrors());
      }
    }

    if (!bAudioVirtualTrackMapFail) {
      Map<Set<DOMNodeObjectModel>, ? extends VirtualTrack> referenceAudioVirtualTracksMap =
          audioVirtualTracksMapList.get(0);
      for (int i = 1; i < audioVirtualTracksMapList.size(); i++) {
        if (!compareAudioVirtualTrackMaps(
            Collections.unmodifiableMap(referenceAudioVirtualTracksMap),
            Collections.unmodifiableMap(audioVirtualTracksMapList.get(i)),
            imfErrorLogger)) {
          imfErrorLogger.addError(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.WARNING,
              String.format(
                  "CPL Id %s can't be merged with Reference CPL Id %s, since 2 same language audio tracks do not seem to represent the same timeline.",
                  compositions.get(i).getUUID(), referenceCPLUUID));
        }
      }
    }

    /** Perform MarkerTrack mergeability checks */
    Composition.VirtualTrack referenceMarkerVirtualTrack =
        compositions.get(0).getMarkerVirtualTrack();
    if (referenceMarkerVirtualTrack != null) {
      UUID referenceMarkerCPLUUID = compositions.get(0).getUUID();
      for (int i = 1; i < compositions.size(); i++) {
        if (!referenceVideoVirtualTrack.equivalent(compositions.get(i).getMarkerVirtualTrack())) {
          imfErrorLogger.addError(
              IMFErrorLogger.IMFErrors.ErrorCodes.IMF_CPL_ERROR,
              IMFErrorLogger.IMFErrors.ErrorLevels.WARNING,
              String.format(
                  "CPL Id %s can't be merged with Reference CPL Id %s, since the marker virtual tracks do not seem to represent the same timeline.",
                  compositions.get(i).getUUID(), referenceMarkerCPLUUID));
        }
      }
    }

    return imfErrorLogger.getErrors();
  }