com.liferay.portlet.documentlibrary.util.JQTFastStart.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.portlet.documentlibrary.util.JQTFastStart.java

Source

/**
 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
 *
 * This library 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 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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.
 */

package com.liferay.portlet.documentlibrary.util;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.FileUtil;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * This class updates an MP4 to be a "fast start" movie. This allows the MP4 to
 * be more quickly read by a client player without needing to completely
 * download the file. It is achieved by moving the movie's MOOV atom to the
 * front of the file. This code is based on the public domain code of <a
 * href="http://www.wired-space.de/media/JQTFaststart.java">JQTFaststat</a>.
 *
 * @author Juan Gonzlez
 */
public class JQTFastStart {

    public static void convert(File inputFile, File outputFile) throws IOException {

        _instance.doConvert(inputFile, outputFile);
    }

    protected void doConvert(File inputFile, File outputFile) throws IOException {

        validate(inputFile, outputFile);

        RandomAccessFile randomAccessInputFile = null;
        RandomAccessFile randomAccessOutputFile = null;

        try {
            randomAccessInputFile = new RandomAccessFile(inputFile, "r");

            Atom atom = null;
            Atom ftypAtom = null;

            boolean ftypFound = false;
            boolean mdatFound = false;
            boolean isFastStart = false;

            while (randomAccessInputFile.getFilePointer() < randomAccessInputFile.length()) {

                atom = new Atom(randomAccessInputFile);

                if (!atom.isTopLevelAtom()) {
                    throw new IOException("Non top level atom was found " + atom.getType());
                }

                if (ftypFound && !mdatFound && atom.isMOOV()) {
                    isFastStart = true;

                    break;
                }

                if (atom.isFTYP()) {
                    ftypAtom = atom;

                    ftypAtom.fillBuffer(randomAccessInputFile);

                    ftypFound = true;
                } else if (atom.isMDAT()) {
                    mdatFound = true;

                    randomAccessInputFile.skipBytes((int) atom.getSize());
                } else {
                    randomAccessInputFile.skipBytes((int) atom.getSize());
                }
            }

            if (isFastStart) {
                if (_log.isInfoEnabled()) {
                    _log.info("The movie is already a fast start MP4");
                }

                FileUtil.move(inputFile, outputFile);

                return;
            }

            if (!atom.isMOOV()) {
                throw new IOException("Last atom was not of type MOOV");
            }

            randomAccessInputFile.seek(atom.getOffset());

            Atom moovAtom = atom;

            moovAtom.fillBuffer(randomAccessInputFile);

            if (moovAtom.hasCompressedMoovAtom()) {
                throw new IOException("Compressed MOOV atoms are unsupported");
            }

            moovAtom.patchAtom();

            randomAccessInputFile.seek(ftypAtom.getOffset() + ftypAtom.getSize());

            randomAccessOutputFile = new RandomAccessFile(outputFile, "rw");

            randomAccessOutputFile.setLength(0);

            randomAccessOutputFile.write(ftypAtom.getBuffer());
            randomAccessOutputFile.write(moovAtom.getBuffer());

            byte[] buffer = new byte[1024 * 1024];

            while ((randomAccessInputFile.getFilePointer() + buffer.length) < moovAtom.getOffset()) {

                int read = randomAccessInputFile.read(buffer);

                randomAccessOutputFile.write(buffer, 0, read);
            }

            int bufferSize = (int) (moovAtom.getOffset() - randomAccessInputFile.getFilePointer());

            buffer = new byte[bufferSize];

            randomAccessInputFile.readFully(buffer);

            randomAccessOutputFile.write(buffer);
        } finally {
            if (randomAccessInputFile != null) {
                randomAccessInputFile.close();
            }

            if (randomAccessOutputFile != null) {
                randomAccessOutputFile.close();
            }
        }
    }

    protected void validate(File inputFile, File outputFile) throws IOException {

        if (!inputFile.exists() || !inputFile.canRead()) {
            throw new IOException("Input file cannot be read " + inputFile);
        }

        if (outputFile.exists()) {
            throw new IOException("Output file alread exists " + outputFile);
        }

        if (inputFile.getAbsolutePath().equals(outputFile.getAbsolutePath())) {
            throw new IOException("Input file and output file cannot be the same " + inputFile);
        }
    }

    private static Log _log = LogFactoryUtil.getLog(JQTFastStart.class);

    private static JQTFastStart _instance = new JQTFastStart();

}