From dd9eb897ee7c7b507cbdcf80263bb4b5de6966bf Mon Sep 17 00:00:00 2001 From: Teng-Hui Zhu Date: Thu, 20 Sep 2012 16:00:17 -0700 Subject: Initial drop the compilable version of mp4parser, with least modification bug:7093055 Change-Id: Id9b1b4ec91e26ae6e9fd75d86696aa30f30897b3 --- .../text-base/FlatPackageWriterImpl.java.svn-base | 197 +++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base (limited to 'isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base') diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base new file mode 100644 index 0000000..3e3847c --- /dev/null +++ b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base @@ -0,0 +1,197 @@ +/* + * Copyright 2012 Sebastian Annies, Hamburg + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.mp4parser.authoring.adaptivestreaming; + +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.SoundMediaHeaderBox; +import com.coremedia.iso.boxes.VideoMediaHeaderBox; +import com.coremedia.iso.boxes.fragment.MovieFragmentBox; +import com.googlecode.mp4parser.authoring.Movie; +import com.googlecode.mp4parser.authoring.Track; +import com.googlecode.mp4parser.authoring.builder.*; +import com.googlecode.mp4parser.authoring.tracks.ChangeTimeScaleTrack; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.util.Iterator; +import java.util.logging.Logger; + +public class FlatPackageWriterImpl implements PackageWriter { + private static Logger LOG = Logger.getLogger(FlatPackageWriterImpl.class.getName()); + long timeScale = 10000000; + + private File outputDirectory; + private boolean debugOutput; + private FragmentedMp4Builder ismvBuilder; + ManifestWriter manifestWriter; + + public FlatPackageWriterImpl() { + ismvBuilder = new FragmentedMp4Builder(); + FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl(); + ismvBuilder.setIntersectionFinder(intersectionFinder); + manifestWriter = new FlatManifestWriterImpl(intersectionFinder); + } + + /** + * 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). + */ + public FlatPackageWriterImpl(int minFragmentDuration) { + ismvBuilder = new FragmentedMp4Builder(); + FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl(minFragmentDuration); + ismvBuilder.setIntersectionFinder(intersectionFinder); + manifestWriter = new FlatManifestWriterImpl(intersectionFinder); + } + + public void setOutputDirectory(File outputDirectory) { + assert outputDirectory.isDirectory(); + this.outputDirectory = outputDirectory; + + } + + public void setDebugOutput(boolean debugOutput) { + this.debugOutput = debugOutput; + } + + public void setIsmvBuilder(FragmentedMp4Builder ismvBuilder) { + this.ismvBuilder = ismvBuilder; + this.manifestWriter = new FlatManifestWriterImpl(ismvBuilder.getFragmentIntersectionFinder()); + } + + public void setManifestWriter(ManifestWriter manifestWriter) { + this.manifestWriter = manifestWriter; + } + + /** + * Writes the movie given as qualities flattened into the + * outputDirectory. + * + * @param source the source movie with all qualities + * @throws IOException + */ + public void write(Movie source) 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 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(); + + } + + private Movie removeUnknownTracks(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; + } + + + /** + * 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 + */ + public Movie correctTimescale(Movie movie) { + Movie nuMovie = new Movie(); + for (Track track : movie.getTracks()) { + nuMovie.addTrack(new ChangeTimeScaleTrack(track, timeScale, ismvBuilder.getFragmentIntersectionFinder().sampleNumbers(track, movie))); + } + return nuMovie; + + } + +} -- cgit v1.2.3