edu.harvard.hul.ois.fits.EbuCoreModel.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.hul.ois.fits.EbuCoreModel.java

Source

/* 
 * Copyright 2015 Harvard University Library
 * 
 * This file is part of FITS (File Information Tool Set).
 * 
 * FITS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * FITS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with FITS.  If not, see <http://www.gnu.org/licenses/>.
 */
package edu.harvard.hul.ois.fits;

//import java.util.UUID;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.jdom.Element;
import org.jdom.Namespace;

import edu.harvard.hul.ois.fits.tools.mediainfo.ChannelPositionParser;
import edu.harvard.hul.ois.fits.tools.mediainfo.ChannelPositionWrapper;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AspectRatio;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AudioBlockFormat;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AudioChannelFormat;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AudioEncoding;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AudioFormat;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AudioFormatExtended;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AudioTrack;
import edu.harvard.hul.ois.ots.schemas.Ebucore.AudioTrackConfiguration;
import edu.harvard.hul.ois.ots.schemas.Ebucore.Codec;
import edu.harvard.hul.ois.ots.schemas.Ebucore.CodecIdentifier;
import edu.harvard.hul.ois.ots.schemas.Ebucore.Comment;
import edu.harvard.hul.ois.ots.schemas.Ebucore.ContainerFormat;
import edu.harvard.hul.ois.ots.schemas.Ebucore.CoreMetadata;
import edu.harvard.hul.ois.ots.schemas.Ebucore.DateTime;
import edu.harvard.hul.ois.ots.schemas.Ebucore.Duration;
import edu.harvard.hul.ois.ots.schemas.Ebucore.EditUnitNumber;
import edu.harvard.hul.ois.ots.schemas.Ebucore.Format;
import edu.harvard.hul.ois.ots.schemas.Ebucore.EbuCoreMain;
import edu.harvard.hul.ois.ots.schemas.Ebucore.FrameRate;
import edu.harvard.hul.ois.ots.schemas.Ebucore.HeightIdentifier;
import edu.harvard.hul.ois.ots.schemas.Ebucore.MimeType;
import edu.harvard.hul.ois.ots.schemas.Ebucore.Position;
import edu.harvard.hul.ois.ots.schemas.Ebucore.Start;
import edu.harvard.hul.ois.ots.schemas.Ebucore.TechnicalAttributeInteger;
import edu.harvard.hul.ois.ots.schemas.Ebucore.TechnicalAttributeString;
import edu.harvard.hul.ois.ots.schemas.Ebucore.VideoEncoding;
import edu.harvard.hul.ois.ots.schemas.Ebucore.VideoFormat;
import edu.harvard.hul.ois.ots.schemas.Ebucore.VideoTrack;
import edu.harvard.hul.ois.ots.schemas.Ebucore.WidthIdentifier;
import edu.harvard.hul.ois.ots.schemas.XmlContent.XmlContentException;

public class EbuCoreModel {

    private final static String UTC_TEXT = "UTC ";

    protected EbuCoreMain ebucoreMain;
    protected Format format;

    protected AudioFormatExtended audioFmtExt;
    protected ContainerFormat containerFormat;
    protected Duration duration;

    //protected final String ebucoreID = "EBUCORE_"+UUID.randomUUID().toString();   

    protected EbuCoreModel() throws XmlContentException {

        //set up base ebucore main object structure       
        ebucoreMain = new EbuCoreMain();

        //ebucoreMain.setSchemaVersion("1.0.0");
        //ebucoreMain.setID(ebucoreID);
        //ebucoreMain.setDisposition("");

        //Identifier ident = new Identifier("","primaryIdentifier");
        //ident.setIdentifierType("FILE_NAME");
        //video.setPrimaryIdentifier(ident);

        containerFormat = new ContainerFormat();
        duration = new Duration();

        format = new Format("format");
        format.setContainerFormat(containerFormat);
        format.setDuration(duration);

        audioFmtExt = new AudioFormatExtended();
        format.setAudioFormatExtended(audioFmtExt);

        CoreMetadata cm = new CoreMetadata();
        cm.setFormat(format);

        ebucoreMain.setCoreMetadata(cm);
    }

    protected void createVideoFormatElement(Element elem, Namespace ns) throws XmlContentException {

        VideoFormat vfmt = new VideoFormat("videoFormat");

        String id = elem.getAttribute("id").getValue();
        VideoTrack vt = new VideoTrack();
        vt.setTrackId(id);
        vfmt.setVideoTrack(vt);

        for (VideoFormatElements videoElem : VideoFormatElements.values()) {

            String fitsName = videoElem.getName();
            Element dataElement = elem.getChild(fitsName, ns);
            if (dataElement == null)
                continue;
            String dataValue = dataElement.getText().trim();
            if (StringUtils.isEmpty(dataValue))
                continue;
            switch (videoElem) {

            case width:
                dataValue = StringUtils.deleteWhitespace(dataElement.getText().replace(" pixels", ""));
                WidthIdentifier width = new WidthIdentifier(dataValue, videoElem.getName());
                width.setUnit("pixel");
                vfmt.setWidthIdentifier(width);
                break;
            case height:
                dataValue = StringUtils.deleteWhitespace(dataElement.getText().replace(" pixels", ""));
                HeightIdentifier height = new HeightIdentifier(dataValue, videoElem.getName());
                height.setUnit("pixel");
                vfmt.setHeightIdentifier(height);
                break;
            case frameRate:
                EbuCoreFrameRateRatio frRatio = new EbuCoreFrameRateRatio(dataValue);

                FrameRate frameRate = new FrameRate(frRatio.getValue(), videoElem.getName());
                frameRate.setFactorNumerator(frRatio.getNumerator());
                frameRate.setFactorDenominator(frRatio.getDenominator());
                vfmt.setFrameRate(frameRate);
                break;
            case bitRate:
                vfmt.setBitRate(Integer.parseInt(dataValue));
                break;
            case bitRateMax:
                vfmt.setBitRateMax(Integer.parseInt(dataValue));
                break;
            case bitRateMode:
                vfmt.setBitRateMode(dataValue.toLowerCase());
                break;
            case scanningFormat:
                if (dataValue.equals("MBAFF"))
                    vfmt.setScanningFormat("interlaced");
                else
                    vfmt.setScanningFormat(dataValue.toLowerCase());
                break;
            case videoDataEncoding:
                VideoEncoding ve = new VideoEncoding();
                ve.setTypeLabel(dataValue);
                vfmt.setVideoEncoding(ve);
                break;
            case aspectRatio:
                String[] splitValues = dataValue.split(":");
                // TODO: throw exception if there are not 2 pieces
                if (splitValues != null && splitValues.length == 2) {
                    AspectRatio ar = new AspectRatio(videoElem.getName());

                    // Normalize the ratio
                    EbuCoreNormalizedRatio ratio = new EbuCoreNormalizedRatio(splitValues[0], splitValues[1]);

                    ar.setFactorNumerator(ratio.getNormalizedNumerator());
                    ar.setFactorDenominator(ratio.getNormalizedDenominator());
                    ar.setTypeLabel("display");
                    vfmt.setAspectRatio(ar);
                }
                break;

            // Technical Attribute Strings
            case colorspace:
                TechnicalAttributeString tas = new TechnicalAttributeString(dataValue);
                tas.setTypeLabel(videoElem.getName());
                vfmt.addTechnicalAttributeString(tas);
                break;

            case chromaSubsampling:
            case frameRateMode:
            case byteOrder:
            case delay:
            case compression:
                TechnicalAttributeString tasLc = new TechnicalAttributeString(dataValue.toLowerCase());
                tasLc.setTypeLabel(videoElem.getName());
                vfmt.addTechnicalAttributeString(tasLc);
                break;

            // Technical Attribute Integers   
            case streamSize:
            case frameCount:
            case bitDepth:
            case duration:
                // For bitDepth, the string might have "bits" at the tail, so 
                // we need to remove it
                if (videoElem.getName().equals("bitDepth")) {
                    String[] parts = dataValue.split(" ");
                    dataValue = parts[0];
                }
                TechnicalAttributeInteger tai = new TechnicalAttributeInteger(Integer.parseInt(dataValue));
                tai.setTypeLabel(videoElem.getName());
                vfmt.addTechnicalAttributeInteger(tai);
                break;

            default:
                break;
            }
        }

        // TODO: break this out to enum code
        // Codec element
        Element dataElement = elem.getChild("codecId", ns);
        if (dataElement != null) {
            String dataValue = dataElement.getText().trim();
            CodecIdentifier ci = new CodecIdentifier("codecIdentifier");
            ci.setIdentifier(dataValue);

            Codec codec = new Codec("codec");
            codec.setCodecIdentifier(ci);

            Element codecElement = elem.getChild("codecInfo", ns);
            if (codecElement != null) {
                dataValue = codecElement.getText().trim();
                codec.setInfo(dataValue);
            }
            codecElement = elem.getChild("codecFamily", ns);
            if (codecElement != null) {
                dataValue = codecElement.getText().trim();
                codec.setFamily(dataValue);
            }
            vfmt.setCodec(codec);
        }

        // Add the audio format object to the list
        this.format.addVideoFormat(vfmt);
    }

    protected void createAudioFormatElement(Element elem, Namespace ns) throws XmlContentException {

        AudioFormat afmt = new AudioFormat("audioFormat");

        Element encodingDataElement = elem.getChild("audioDataEncoding", ns);
        if (encodingDataElement != null) {
            String dataValue = encodingDataElement.getText().trim();
            AudioEncoding ae = new AudioEncoding();
            ae.setTypeLabel(dataValue);
            // Type Link NOT in AVPreserve example, so don't expose
            // ae.setTypeLink("http://www.ebu.ch/metadata/cs/ebu_AudioCompressionCodeCS.xml#11");
            afmt.setAudioEncoding(ae);

            //afmt.setAudioFormatName(dataValue);
        }

        String id = elem.getAttribute("id").getValue();
        AudioTrack at = new AudioTrack();
        at.setTrackId(id);
        afmt.setAudioTrack(at);

        for (AudioFormatElements audioElem : AudioFormatElements.values()) {

            // NOTE: use the .name(), not .getName(), so we can use the correct
            // value to set the typeLabel
            String fitsName = audioElem.name();
            Element dataElement = elem.getChild(fitsName, ns);
            if (dataElement == null)
                continue;
            String dataValue = dataElement.getText().trim();
            if (StringUtils.isEmpty(dataValue))
                continue;

            switch (audioElem) {

            case soundField:
                AudioTrackConfiguration atc = new AudioTrackConfiguration();
                atc.setTypeLabel(dataValue);
                afmt.setAudioTrackConfiguration(atc);

                // Convert the text to x/y coordinates
                if (dataValue != null && dataValue.length() != 0) {
                    ChannelPositionParser cpp = new ChannelPositionParser();
                    List<ChannelPositionWrapper> positions = cpp.getChannelsFromString(dataValue);

                    for (ChannelPositionWrapper positionWrapper : positions) {
                        Position positionX = new Position(new Integer(positionWrapper.getXpos()));
                        positionX.setCoordinate("x");

                        Position positionY = new Position(new Integer(positionWrapper.getYpos()));
                        positionY.setCoordinate("y");

                        AudioBlockFormat abf = new AudioBlockFormat();
                        abf.addPosition(positionX);
                        abf.addPosition(positionY);

                        AudioChannelFormat acf = new AudioChannelFormat();
                        acf.setAudioBlockFormat(abf);

                        audioFmtExt.addAudioChannelFormat(acf);
                    }
                }
                break;

            case bitRate:
                afmt.setBitRate(Integer.parseInt(dataValue));
                break;
            case bitRateMode:
                afmt.setBitRateMode(dataValue.toLowerCase());
                break;
            case samplingRate:
                afmt.setSamplingRate(Integer.parseInt(dataValue));
                break;
            case sampleSize:
                afmt.setSampleSize(dataValue);
                break;
            case channels:
                afmt.setChannels(Integer.parseInt(dataValue));
                break;

            // Technical Attribute Strings
            case byteOrder:
            case delay:
            case compression:
                TechnicalAttributeString tas = new TechnicalAttributeString(dataValue.toLowerCase());
                tas.setTypeLabel(audioElem.getEbucoreName());
                afmt.addTechnicalAttributeString(tas);
                break;

            // Technical Attribute Integers   
            case trackSize:
            case numSamples:
            case duration:
                TechnicalAttributeInteger tai = new TechnicalAttributeInteger(Integer.parseInt(dataValue));
                tai.setTypeLabel(audioElem.getEbucoreName());
                afmt.addTechnicalAttributeInteger(tai);
                break;

            default:
                break;
            }
        }

        // TODO: break this out to enum code
        // Codec element
        Element dataElement = elem.getChild("codecId", ns);
        if (dataElement != null) {
            String dataValue = dataElement.getText().trim();
            CodecIdentifier ci = new CodecIdentifier("codecIdentifier");
            ci.setIdentifier(dataValue);

            Codec codec = new Codec("codec");
            codec.setCodecIdentifier(ci);

            Element codecElement = elem.getChild("codecInfo", ns);
            if (codecElement != null) {
                dataValue = codecElement.getText().trim();
                codec.setInfo(dataValue);
            }
            //codecElement = elem.getChild ("codecFamily",ns);
            //if(codecElement != null) {
            //   dataValue = codecElement.getText().trim();
            //   codec.setFamily(dataValue);
            //}
            afmt.setCodec(codec);
        }
        //        
        //        //
        //        // Channel Positions
        //        //
        //         dataElement = elem.getChild ("soundField",ns);
        //        if(dataElement != null) {
        //           String dataValue = dataElement.getText().trim();
        //           
        //           //if(StringUtilts.)
        //           if(dataValue != null) {
        //              
        //           }
        //        }

        // Add the audio format object to the list
        this.format.addAudioFormat(afmt);
    }

    protected void createFormatElement(String fitsName, Element elem) throws XmlContentException {

        String dataValue = elem.getText().trim();
        if (StringUtils.isEmpty(dataValue)) {
            // TODO: Log and throw Error
            return;
        }

        FormatElements formatElem = FormatElements.lookup(fitsName);
        if (formatElem == null) {
            // TODO: Log and throw Error
            return;
        }

        switch (formatElem) {
        // Note: size may be filtered off by the consolidator
        case size:
            this.format.setFileSize(dataValue);
            break;
        // Note: filename may be filtered off by the consolidator
        case filename:
            this.format.setFileName(dataValue);
            break;
        case mimeType:
            MimeType mimeType = new MimeType();
            mimeType.setTypeLabel(dataValue);
            this.format.setMimeType(mimeType);
            break;
        case location:
            this.format.setLocator(dataValue);
            break;
        case bitRate:
            TechnicalAttributeString tas = new TechnicalAttributeString(dataValue);
            tas.setTypeLabel("overallBitRate");
            this.format.setTechnicalAttributeString(tas);
            break;
        case dateCreated:
        case dateModified:
            String parts[] = dataValue.replace(UTC_TEXT, "").split(" ");
            DateTime dateTime = new DateTime(formatElem.getEbucoreName());
            dateTime.setStartDate(parts[0]);
            dateTime.setStartTime(parts[1] + "Z");
            this.format.setDateCreated(dateTime);
            break;
        case formatProfile:
        case format:
            Comment comment = new Comment(dataValue);
            this.containerFormat.addComment(comment);
            break;
        case duration:
            //Integer intValue = new Integer(dataValue);
            // Sometimes MediaInfo returns a value with a decimal place
            Double d = new Double(dataValue);
            Integer intValue = Integer.valueOf((int) Math.round(d));
            EditUnitNumber eun = new EditUnitNumber(intValue, "editUnitNumber");
            eun.setEditRate(1000);
            eun.setFactorNumerator(1);
            eun.setFactorDenominator(1);
            this.duration.setDuration(eun);
            break;

        default:
            break;
        }

    }

    protected void createStart(String timecode, String framerate) throws XmlContentException {

        if (timecode.equals("NOT_SET") || framerate.equals("NOT_SET"))
            return;

        int hours = Integer.parseInt(timecode.substring(0, 2));
        int minutes = Integer.parseInt(timecode.substring(3, 5));
        int seconds = Integer.parseInt(timecode.substring(6, 8));
        int framesFromTc = Integer.parseInt(timecode.substring(9, 11));

        EbuCoreFrameRateRatio ratio = new EbuCoreFrameRateRatio(framerate);
        int fps = new Integer(ratio.getValue());

        // hours
        int frames = (int) ((double) hours * 3600 * fps);

        // minutes
        frames += (double) minutes * 60 * fps;

        // seconds
        double tmpFrame = (double) seconds * fps;
        // Not necessary, as normalization is already done in the
        // EbuCoreFrameRateRatio class
        //if (tmpFrame > Math.floor(tmpFrame)) 
        //   tmpFrame = Math.floor(tmpFrame) + 1;
        frames += tmpFrame;

        // frames
        frames += framesFromTc;

        EditUnitNumber eun = new EditUnitNumber(new Integer(frames), "editUnitNumber");
        eun.setEditRate(fps);
        eun.setFactorNumerator(new Integer(ratio.getNumerator()));
        eun.setFactorDenominator(new Integer(ratio.getDenominator()));

        Start start = new Start("start");
        start.setTimecode(eun);
        this.format.setStart(start);

    }

    //    public static void main(String[] args) throws XmlContentException {
    //       
    //       String timecode = "00:00:01:00";
    //       String framerate = "29.97";
    //       
    //       EbuCoreModel test = new EbuCoreModel();
    //       
    //       test.createStart(timecode, framerate);
    //    }

}