FileDocCategorySizeDatePackage
FlatPackageWriterImpl.javaAPI Docmp4parser 1.0-RC-178285Wed Dec 19 20:10:37 GMT 2012com.googlecode.mp4parser.authoring.adaptivestreaming

FlatPackageWriterImpl

public class FlatPackageWriterImpl extends Object implements PackageWriter

Fields Summary
private static Logger
LOG
long
timeScale
private File
outputDirectory
private boolean
debugOutput
private FragmentedMp4Builder
ismvBuilder
ManifestWriter
manifestWriter
Constructors Summary
public FlatPackageWriterImpl()


      
        ismvBuilder = new FragmentedMp4Builder();
        FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl();
        ismvBuilder.setIntersectionFinder(intersectionFinder);
        manifestWriter = new FlatManifestWriterImpl(intersectionFinder);
    
public FlatPackageWriterImpl(int minFragmentDuration)
Creates a factory for a smooth streaming package. A smooth streaming package is a collection of files that can be served by a webserver as a smooth streaming stream.

param
minFragmentDuration the smallest allowable duration of a fragment (0 == no restriction).

        ismvBuilder = new FragmentedMp4Builder();
        FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl(minFragmentDuration);
        ismvBuilder.setIntersectionFinder(intersectionFinder);
        manifestWriter = new FlatManifestWriterImpl(intersectionFinder);
    
Methods Summary
public com.googlecode.mp4parser.authoring.MoviecorrectTimescale(com.googlecode.mp4parser.authoring.Movie movie)
Returns a new Movie in that all tracks have the timescale 10000000. CTS & DTS are modified in a way that even with more than one framerate the fragments exactly begin at the same time.

param
movie
return
a movie with timescales suitable for smooth streaming manifests

        Movie nuMovie = new Movie();
        for (Track track : movie.getTracks()) {
            nuMovie.addTrack(new ChangeTimeScaleTrack(track, timeScale, ismvBuilder.getFragmentIntersectionFinder().sampleNumbers(track, movie)));
        }
        return nuMovie;

    
private com.googlecode.mp4parser.authoring.MovieremoveUnknownTracks(com.googlecode.mp4parser.authoring.Movie source)

        Movie nuMovie = new Movie();
        for (Track track : source.getTracks()) {
            if ("vide".equals(track.getHandler()) || "soun".equals(track.getHandler())) {
                nuMovie.addTrack(track);
            } else {
                LOG.fine("Removed track " + track);
            }
        }
        return nuMovie;
    
public voidsetDebugOutput(boolean debugOutput)

        this.debugOutput = debugOutput;
    
public voidsetIsmvBuilder(FragmentedMp4Builder ismvBuilder)

        this.ismvBuilder = ismvBuilder;
        this.manifestWriter = new FlatManifestWriterImpl(ismvBuilder.getFragmentIntersectionFinder());
    
public voidsetManifestWriter(ManifestWriter manifestWriter)

        this.manifestWriter = manifestWriter;
    
public voidsetOutputDirectory(java.io.File outputDirectory)

        assert outputDirectory.isDirectory();
        this.outputDirectory = outputDirectory;

    
public voidwrite(com.googlecode.mp4parser.authoring.Movie source)
Writes the movie given as qualities flattened into the outputDirectory.

param
source the source movie with all qualities
throws
IOException


        if (debugOutput) {
            outputDirectory.mkdirs();
            DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder();
            IsoFile muxed = defaultMp4Builder.build(source);
            File muxedFile = new File(outputDirectory, "debug_1_muxed.mp4");
            FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile);
            muxed.getBox(muxedFileOutputStream.getChannel());
            muxedFileOutputStream.close();
        }
        Movie cleanedSource = removeUnknownTracks(source);
        Movie movieWithAdjustedTimescale = correctTimescale(cleanedSource);

        if (debugOutput) {
            DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder();
            IsoFile muxed = defaultMp4Builder.build(movieWithAdjustedTimescale);
            File muxedFile = new File(outputDirectory, "debug_2_timescale.mp4");
            FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile);
            muxed.getBox(muxedFileOutputStream.getChannel());
            muxedFileOutputStream.close();
        }
        IsoFile isoFile = ismvBuilder.build(movieWithAdjustedTimescale);
        if (debugOutput) {
            File allQualities = new File(outputDirectory, "debug_3_fragmented.mp4");
            FileOutputStream allQualis = new FileOutputStream(allQualities);
            isoFile.getBox(allQualis.getChannel());
            allQualis.close();
        }


        for (Track track : movieWithAdjustedTimescale.getTracks()) {
            String bitrate = Long.toString(manifestWriter.getBitrate(track));
            long trackId = track.getTrackMetaData().getTrackId();
            Iterator<Box> boxIt = isoFile.getBoxes().iterator();
            File mediaOutDir;
            if (track.getMediaHeaderBox() instanceof SoundMediaHeaderBox) {
                mediaOutDir = new File(outputDirectory, "audio");

            } else if (track.getMediaHeaderBox() instanceof VideoMediaHeaderBox) {
                mediaOutDir = new File(outputDirectory, "video");
            } else {
                System.err.println("Skipping Track with handler " + track.getHandler() + " and " + track.getMediaHeaderBox().getClass().getSimpleName());
                continue;
            }
            File bitRateOutputDir = new File(mediaOutDir, bitrate);
            bitRateOutputDir.mkdirs();
            LOG.finer("Created : " + bitRateOutputDir.getCanonicalPath());

            long[] fragmentTimes = manifestWriter.calculateFragmentDurations(track, movieWithAdjustedTimescale);
            long startTime = 0;
            int currentFragment = 0;
            while (boxIt.hasNext()) {
                Box b = boxIt.next();
                if (b instanceof MovieFragmentBox) {
                    assert ((MovieFragmentBox) b).getTrackCount() == 1;
                    if (((MovieFragmentBox) b).getTrackNumbers()[0] == trackId) {
                        FileOutputStream fos = new FileOutputStream(new File(bitRateOutputDir, Long.toString(startTime)));
                        startTime += fragmentTimes[currentFragment++];
                        FileChannel fc = fos.getChannel();
                        Box mdat = boxIt.next();
                        assert mdat.getType().equals("mdat");
                        b.getBox(fc); // moof
                        mdat.getBox(fc); // mdat
                        fc.truncate(fc.position());
                        fc.close();
                    }
                }

            }
        }
        FileWriter fw = new FileWriter(new File(outputDirectory, "Manifest"));
        fw.write(manifestWriter.getManifest(movieWithAdjustedTimescale));
        fw.close();