Skip navigation links
Media Authoring with Java API (MAJ)

MAJ API Overview

This documentation describes the Media Authoring with Java API (MAJ API), some generic media industry and an implementation of the classes of the Advanced Authoring Format specification in Java.

See: Description

Packages 
Package Description
tv.amwa.maj.constant
Defines constant values used throughout the MAJ API and defined by external specifications.
tv.amwa.maj.enumeration
Defines Java enumerations representing the enumerations specified in the AAF object specification and other enumerations used across the MAJ API.
tv.amwa.maj.example
Example code demonstrating the use of the MAJ API.
tv.amwa.maj.exception
Specific exceptions thrown due to exceptional behaviour during the execution of method calls from the MAJ API.
tv.amwa.maj.extensions.avid  
tv.amwa.maj.extensions.avid.impl  
tv.amwa.maj.extensions.example
Example code demonstrating an extension built with the auto generator.
tv.amwa.maj.extensions.example.impl  
tv.amwa.maj.extensions.quantel  
tv.amwa.maj.extensions.quantel.impl  
tv.amwa.maj.extensions.st436  
tv.amwa.maj.extensions.st436.impl  
tv.amwa.maj.industry
Industry for manufacturing, storing and making instances of classes and meta-classes, referenced by names and registered identifiers.
tv.amwa.maj.integer
Provides annotations to label that a value of a Java primitive type in the current context should be interpreted as a particular AAF integer data type.
tv.amwa.maj.io.aaf  
tv.amwa.maj.io.file  
tv.amwa.maj.io.mxf
Support for the serialization of AAF data to and from KLV format files and streams according to the SMPTE MXF standards.
tv.amwa.maj.io.mxf.impl  
tv.amwa.maj.io.xml
Support for the input and output of metadata objects as XML fragments and documents.
tv.amwa.maj.meta
Specifications of all the meta-classes of AAF that provides meta-information about classes, properties and data types.
tv.amwa.maj.meta.impl
A meta engine providing loosely-coupled class, property and type management services.
tv.amwa.maj.misctype
Provides annotations that describe the mapping of miscellaneous AAF data types to Java data types.
tv.amwa.maj.model
Specifications of all the interchangeable classes of AAF as Java interfaces.
tv.amwa.maj.model.impl
Implementation of the AAF interchange object classes.
tv.amwa.maj.record
Specifications of representations of structured values, such as those of the AAF record data types.
tv.amwa.maj.record.impl
Implementations of structured values that can be embedded as properties of entity beans.
tv.amwa.maj.union
Provides interfaces to a union type representing values which may contain one of many different sub-types.
tv.amwa.maj.union.impl
Implementations of classes used to package up collections of values as an argument to a method of the MAJ API.
tv.amwa.maj.util
Static utility methods and generators used internally by the MAJ API that may also be useful to applications using the API.

This documentation describes the Media Authoring with Java API (MAJ API), some generic media industry and an implementation of the classes of the Advanced Authoring Format specification in Java. The media industry is a general purpose library code for making and manipulating structures defined according to SMPTE registers. The AAF classes are implemented as plain old Java objects (POJOs) and that can be mapped to EJB3-style persistent entities.

This API provides the basis for applications that capture. edit, manage and distribute media according to professional standards. The API provides support for AAF, MXF and Reg-XML file formats. It provides extensions mechanism to allow implementors to extend the core classes to meet new standards or represent private data. This API is being developed as a project of the Advanced Media Workflow Association and is licensed under the Apache 2.0 License. Note, however, that support for manipulating essence with MAJ is currently very limited.

This is a developer's release 1.1.4, a number chosen to indicate the level of object model support similar to the AAF SDK reference implementation. The documentation of all the packages is rich and complete, so worthwhile exploring for a technical person. In particular, media engine, forge, and warehouse are at the heart of the API's capabilities, so it is a good place to start exploring.

This page provides some getting started topics:

Writing code from scratch

An application can be written using the AAF data model from scratch without the need to read or write files. One difference between MAJ and the AAF SDK is that you can write code that uses classes of the AAF model without the need to contain them within a virtual file at runtime. For more details, see the documentation of the industry package.

The starting point is to initialize the local Java virtual machine so that it supports processing the AAF data model with MediaEngine.initializeAAF(). You can then start creating objects of the AAF data model, including packages, tracks, sequences and source clips, using the make... methods of the @linkplain tv.amwa.maj.industry.Forge forge}, for example make(Class, Object...).

Every class in MAJ provides a registered XML representation as its toString() output, which in turn is created by MediaEngine.toString(MetadataObject). This make debugging fairly easy as you can query a value in the debugger and see a human-readable XML format.

To help you get started, here is a code example:

package tv.amwa.maj.example;

import tv.amwa.maj.industry.Forge;
import tv.amwa.maj.industry.MediaEngine;
import tv.amwa.maj.model.*;

public class AMWADemoClass
    implements tv.amwa.maj.constant.CommonConstants {

    public static void main(String[] args) throws Exception {

        MediaEngine.initializeAAF(); // Required to initialize AAF specified classes

        MaterialPackage amwaPackage = Forge.makeByName(
                AAF_XML_NAMESPACE, "MaterialPackage",
                "PackageID", Forge.randomUMID(), // Randomly generated
                "Name", "AMWADemoPackage",
                "PackageLastModified", Forge.now(),
                "CreationTime", Forge.now());

        Sequence amwaVideoSequence = Forge.makeByName(
                AAF_XML_NAMESPACE, "Sequence",
                "ComponentDataDefinition", "Picture");

        amwaVideoSequence.appendComponentObject(
                Forge.make(
                        SourceClip.class,
                        "ComponentDataDefinition", "Picture",
                        "ComponentLength", 60l,
                        "SourcePackageID", "urn:smpte:umid:060c2b34.02051101.01001000.13000000.11ee08d4.040311d4.8e3d0090.27dfca7c",
                        "SourceTrackID", 1,
                        "StartPosition", 10l));

        TimelineTrack amwaVideoTrack = Forge.make(
                TimelineTrack.class,
                "TrackID", 1,
                "TrackSegment", amwaVideoSequence,
                "EditRate", "25/1",
                "Origin", 0l);

        amwaVideoTrack.setTrackName("AMWA VIDEO TRACK");

        amwaPackage.appendPackageTrack(amwaVideoTrack);
        amwaPackage.appendPackageUserComment("company", "portability 4 media");

        System.out.println(amwaPackage.toString());
    }
}

For a more complex example, see the source for the composition example that is part of the AMWA training course.

MXF files - AAF-KLV

MXF files, also known as AAF-KLV files, consist of sequence of partitions. Partitions contain a partition header and may contain metadata, index tables and/or essence data. Support for reading and writing MXF files is provided in package tv.amwa.maj.io.mxf.

Reading MXF partitions

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. To do this:

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 header partition. Most also contain a footer partition. To access these:

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 header metadata and this is split into a primer pack and a preface. The metadata can be read into memory from file using the 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.

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 from the 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

This code is still in development, but it will take the form of an application altering an existing preface, setting it to replace that within existing header metadata and calling a write method. Well structured MXF should have padding at the end of the existing metadata, allowing the existing metadata to be overwritten and extended. Writing will fail if insufficient padding space is available.

Reading the index table

An 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 previous 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 ...

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

...

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

Note that in interleaved streams, the element number determines whether it is an edit unit worth of video, audio or data track being referred to. You need to know your stream layout to insert the correct element number.

AAF files - AAF-SS

AAF files, also known as AAF-SS or AAF structured storage files, store AAF structured data in a Microsoft structured storage container. To read and write these files, MAJ uses the Apache POI library version 3.7.

Support for reading and writing AAF files is provided in package tv.amwa.maj.io.aaf. MAJ provides a helper class AAFFactory as a starting point for reading and writing AAF files.

Reading a preface from an AAF file

To read a preface from an AAF file, such as those generated by Avid, use the AAFFactory#readPreface(java.lang.String) readPreface() method of the AAFFactory class. For example:

import tv.amwa.maj.io.aaf.AAFFactory;
import tv.amwa.maj.iface.Preface;
import tv.amwa.maj.extensions.avid.AvidFactory;
...

AvidFactory.registerAvidExtensions();
Preface fromAAF = AAFFactory.readPreface("filename.aaf");

Some warning messages will be printed if extensions are unknown. These can be ignored unless the extension data is important to your application.

Writing a metadata-only AAF file

MAJ supports writing metadata-only AAF files, files that do not contain any essence data. AAF is commonly used as a metadata-only representation so this limitation means MAJ still works in many use cases.

To write an existing preface to an AAF file, make sure the Avid extensions are registered (as for reading) and use the AAFFactory#writePreface(tv.amwa.maj.model.Preface, java.lang.String) writePreface() method of the AAFFactory class.

import tv.amwa.maj.io.AAFFactory;
import tv.amwa.maj.iface.Preface;
...

Preface prefaceToWrite = ...;
AAFFactory.writePreface(prefaceToWrite, "filename.aaf");

MAJ will create a dynamic meta dictionary and, if the preface does not contain a valid dictionary already, add in all the required definitions to make the file valid.

Reg-XML files - AAF-XML

AAF XML files are also known as registered data XML files (SMPTE draft standard 2001). MAJ uses this format for the return value of toString() methods almost everywhere, so it is easy to get to learn this format. When you use a debugger and hover over a variable that is a MAJ type, you will see the same XML format.

Support for reading and writing XML files is provided in package tv.amwa.maj.io.xml. MAJ provides a helper class XMLBuilder as a starting point for reading and writing AAF fragments to and from XML.

The methods the serialize objects to and from XML are useful for providing RESTful and web service interfaces to an AAF-based repository. Reading and writing complete files allows XML to be used in file-based workflows in place of the harder-to-analyse MXF and AAF formats.

Serializing an object to XML fragments

To convert a single object and any of its contained strong referenced objects to XML, use method toXML() methods of the XML builder.

import tv.amwa.maj.io.xml.XMLBuilder;
import tv.amwa.maj.iface.MaterialPackage;
...

MaterialPackage material = ...;
String packageAsXML = XMLBuilder.toXML(material);

Any objects that implement XMLSerializable or MetadataObject can be serialized to XML fragments.

Creating objects from an XML fragment

To read the XML representation of an object in XML and create an instance in memory, use either the createFromXML() or createFromXMLString() methods of the XML builder.

import tv.amwa.maj.io.xml.XMLBuilder;
import tv.amwa.maj.iface.MaterialPackage;
...

MaterialPackage material =
        (MaterialPackage) XMLBulder.createFromXMLString(packageAsXML);

Reading complete Reg XML files with MAJ

Complete XML files have a root <AAF> root element. To read a preface from an XML file, register all the required data types and then use the readPreface() static method of the XML factory.

import tv.amwa.maj.io.xml.XMLFactory;
import tv.amwa.maj.model.Preface;
....

Preface preface = XMLFactory.readPreface("input_file.xml");

Catch IO exceptions to find out about any problems parsing the XML.

Note that the automatic processing of extension metadata that is not registered with MAJ is not supported in the current version of the MAJ API.

Writing complete Reg XML files with MAJ

Complete XML files have a root <AAF> root element. To write a complete Reg XML file, use the writePreface() static method of the XML factory.

import tv.amwa.maj.io.xml.XMLFactory;
....

XMLFactory.writePreface(preface, "output_file.xml");

The preface will be automatically updated with a correct dictionary and any extensions classes will be added to the output. Note that an application is expected to have added an appropriate identification to the preface to identify the current version of the file before calling this method.

Extensions

Writing extensions, for example to represent your companies descriptive metadata scheme, can be achieved by writing Java interfaces and classes that represent those extensions. How to do this is described in the industry package and in particular in the description of the MediaClass and MediaProperty annotations. In fact, if you have some existing Java beans, annotating them to work as media classes with MAJ may be quite simple.

If writing all that Java is a scary thought, MAJ provides an auto generator that can take an XML description of metadata extensions and create Java package sourcecode that can be compiled and used with MAJ.

Some Avid Media Composer extensions are provided in package tv.amwa.maj.extensions.avid.

Advanced features

MAJ provides a means for generating Java Persistence API compatible object-relational mappings from its own internal representation of media classes.

MAJ can generate an XML representation of classes, properties and types that it knows about using static method MediaEngine.generateMetaDictionary().

Skip navigation links
Media Authoring with Java API (MAJ)

(c)2007-2016 Richard Cartwright, all rights reserved. Licensed under Apache 2 license and subject to the AMWA IPR policy.