summaryrefslogtreecommitdiff
path: root/isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base
diff options
context:
space:
mode:
Diffstat (limited to 'isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base')
-rw-r--r--isoparser/src/main/java/com/googlecode/mp4parser/authoring/adaptivestreaming/.svn/text-base/FlatPackageWriterImpl.java.svn-base197
1 files changed, 197 insertions, 0 deletions
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 <code>qualities</code> flattened into the
+ * <code>outputDirectory</code>.
+ *
+ * @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<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();
+
+ }
+
+ 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 <code>Movie</code> 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;
+
+ }
+
+}