Support for the serialization of AAF data to and from KLV format files and streams according to the SMPTE MXF standards. The MXF file format is specified by SMPTE 0377-1-2009.

This implementation supports clip-based wrapping of uni-track streams into a generic container according to SMPTE ST 0385-2004. Future versions will support many more mapping and codecs, including the AMWA application specifications.

## Reading MXF partitions

MXF files, also known as AAF-KLV files, consist of sequence of {@linkplain tv.amwa.maj.io.mxf.Partition partitions}. Partitions contain a partition description, known as a {@link tv.amwa.maj.io.mxf.PartitionPack partition pack}, and may contain metadata, index tables and/or body essence streams.

MXF files contain one or more partitions. The first step in reading an MXF file is to build an in memory cache of the structure of those partitions as an {@link tv.amwa.maj.io.mxf.MXFFile MXFFile}. To do this, use the {@link tv.amwa.maj.io.mxf.MXFFactory#readPartitions(String) readParitions()} method of the {@linkplain tv.amwa.maj.io.mxf.MXFFactory MXF factory}. For example:

    import tv.amwa.maj.industry.MediaEngine;
    import tv.amwa.maj.io.mxf.MXFFactory;
    import tv.amwa.maj.io.mxf.MXFFile;

    ...

      MXFFile mxfFile = MXFFactory.readPartitions("filename.mxf");

All MXF files contain a {@linkplain tv.amwa.maj.io.mxf.HeaderPartition header partition}. Most also contain a {@linkplain tv.amwa.maj.io.mxf.FooterPartition footer partition}. To access these, use the {@link tv.amwa.maj.io.mxf.MXFFile#getHeaderPartition() getHeaderPartition()} and {@link tv.amwa.maj.io.mxf.MXFFile#getFooterPartition() getFooterPartition()} methods. For example:

    import tv.amwa.maj.io.mxf.HeaderPartition;
    import tv.amwa.maj.io.mxf.FooterPartition;

    ...

      HeaderPartition header = mxfFile.getHeaderPartition();
      FooterPartition footer = mxfFile.getFooterPartition();

## Reading header metadata

Partitions can contain {@linkplain tv.amwa.maj.io.mxf.HeaderMetadata header metadata} and this is split into a {@linkplain tv.amwa.maj.io.mxf.PrimerPack primer pack} and a {@linkplain tv.amwa.maj.model.Preface preface}. The metadata can be read into memory from a file using the {@link tv.amwa.maj.io.mxf.Partition#readHeaderMetadata() readHeaderMetadata()} method.

If a footer partition is present in an MXF file and it contains header metadata, this version is often the most trusted source for metadata about the file as it was written once the rest of the file is complete. If the footer partition is not present or does not contain header metadata, read the header partition's header metadata instead. For example:

    import tv.amwa.maj.model.Preface;
    import tv.amwa.maj.io.mxf.HeaderMetadata;

    ...

      HeaderMetadata headerMD = null;
      if ((footer != null) && (footer.hasHeaderMetadata())
        headerMD = footer.readHeaderMetadata();
      else
        headerMD = header.readHeaderMetadata();

      Preface preface = headerMD.getPreface();

Methods of the {@linkplain tv.amwa.maj.model.Preface preface interface} can be used to interrogate what is in the MXF file, or you can call `toString()` on the preface to get an XML representation.

## Writing header metadata

To follow.

## Reading the index table

An {@linkplain tv.amwa.maj.io.mxf.IndexTable index table} maps edit unit indexes to stream offsets in essence containers. This enables the data representing a specific frame of video or audio sample to be located in the file, for example to generate a still frame or carry out a partial restore. Any long GOP structure used to store the essence can also be interrogated to work out a safe point to break a file, e.g. don't forget the preceding I-frame!

Any partition may have an index table. To read the index table and find the stream offset to the 10th frame 2nd element, measured in bytes from the beginning of its essence container, use the {@link tv.amwa.maj.io.mxf.Partition#readIndexTable() readIndexTable()} method. For example:

    import tv.amwa.maj.io.mxf.IndexTable;

    ...

      IndexTable index = footer.readIndexTable();
      long tenthFrameOffset = index.streamOffset(10, 2);