1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/* 2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Copyright 2012 Sebastian Annies, Hamburg 3dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 4dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Licensed under the Apache License, Version 2.0 (the License); 5dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * you may not use this file except in compliance with the License. 6dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * You may obtain a copy of the License at 7dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 8dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * http://www.apache.org/licenses/LICENSE-2.0 9dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 10dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Unless required by applicable law or agreed to in writing, software 11dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * distributed under the License is distributed on an AS IS BASIS, 12dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * See the License for the specific language governing permissions and 14dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * limitations under the License. 15dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 16dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupackage com.googlecode.mp4parser.authoring.adaptivestreaming; 17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoFile; 19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.Box; 20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.SoundMediaHeaderBox; 21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.VideoMediaHeaderBox; 22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.fragment.MovieFragmentBox; 23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.Movie; 24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.Track; 25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.builder.*; 26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.authoring.tracks.ChangeTimeScaleTrack; 27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.File; 29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.FileOutputStream; 30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.FileWriter; 31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.IOException; 32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.FileChannel; 33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.Iterator; 34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.logging.Logger; 35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic class FlatPackageWriterImpl implements PackageWriter { 37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private static Logger LOG = Logger.getLogger(FlatPackageWriterImpl.class.getName()); 38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long timeScale = 10000000; 39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private File outputDirectory; 41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private boolean debugOutput; 42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private FragmentedMp4Builder ismvBuilder; 43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ManifestWriter manifestWriter; 44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public FlatPackageWriterImpl() { 46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ismvBuilder = new FragmentedMp4Builder(); 47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl(); 48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ismvBuilder.setIntersectionFinder(intersectionFinder); 49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu manifestWriter = new FlatManifestWriterImpl(intersectionFinder); 50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Creates a factory for a smooth streaming package. A smooth streaming package is 54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * a collection of files that can be served by a webserver as a smooth streaming 55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * stream. 56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param minFragmentDuration the smallest allowable duration of a fragment (0 == no restriction). 57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public FlatPackageWriterImpl(int minFragmentDuration) { 59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ismvBuilder = new FragmentedMp4Builder(); 60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FragmentIntersectionFinder intersectionFinder = new SyncSampleIntersectFinderImpl(minFragmentDuration); 61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ismvBuilder.setIntersectionFinder(intersectionFinder); 62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu manifestWriter = new FlatManifestWriterImpl(intersectionFinder); 63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setOutputDirectory(File outputDirectory) { 66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert outputDirectory.isDirectory(); 67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.outputDirectory = outputDirectory; 68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setDebugOutput(boolean debugOutput) { 72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.debugOutput = debugOutput; 73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setIsmvBuilder(FragmentedMp4Builder ismvBuilder) { 76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.ismvBuilder = ismvBuilder; 77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.manifestWriter = new FlatManifestWriterImpl(ismvBuilder.getFragmentIntersectionFinder()); 78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setManifestWriter(ManifestWriter manifestWriter) { 81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.manifestWriter = manifestWriter; 82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Writes the movie given as <code>qualities</code> flattened into the 86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <code>outputDirectory</code>. 87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param source the source movie with all qualities 89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @throws IOException 90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void write(Movie source) throws IOException { 92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (debugOutput) { 94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu outputDirectory.mkdirs(); 95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder(); 96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoFile muxed = defaultMp4Builder.build(source); 97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu File muxedFile = new File(outputDirectory, "debug_1_muxed.mp4"); 98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile); 99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu muxed.getBox(muxedFileOutputStream.getChannel()); 100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu muxedFileOutputStream.close(); 101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Movie cleanedSource = removeUnknownTracks(source); 103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Movie movieWithAdjustedTimescale = correctTimescale(cleanedSource); 104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (debugOutput) { 106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu DefaultMp4Builder defaultMp4Builder = new DefaultMp4Builder(); 107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoFile muxed = defaultMp4Builder.build(movieWithAdjustedTimescale); 108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu File muxedFile = new File(outputDirectory, "debug_2_timescale.mp4"); 109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FileOutputStream muxedFileOutputStream = new FileOutputStream(muxedFile); 110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu muxed.getBox(muxedFileOutputStream.getChannel()); 111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu muxedFileOutputStream.close(); 112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoFile isoFile = ismvBuilder.build(movieWithAdjustedTimescale); 114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (debugOutput) { 115dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu File allQualities = new File(outputDirectory, "debug_3_fragmented.mp4"); 116dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FileOutputStream allQualis = new FileOutputStream(allQualities); 117dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu isoFile.getBox(allQualis.getChannel()); 118dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu allQualis.close(); 119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movieWithAdjustedTimescale.getTracks()) { 123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu String bitrate = Long.toString(manifestWriter.getBitrate(track)); 124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long trackId = track.getTrackMetaData().getTrackId(); 125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Iterator<Box> boxIt = isoFile.getBoxes().iterator(); 126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu File mediaOutDir; 127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (track.getMediaHeaderBox() instanceof SoundMediaHeaderBox) { 128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mediaOutDir = new File(outputDirectory, "audio"); 129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else if (track.getMediaHeaderBox() instanceof VideoMediaHeaderBox) { 131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mediaOutDir = new File(outputDirectory, "video"); 132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu System.err.println("Skipping Track with handler " + track.getHandler() + " and " + track.getMediaHeaderBox().getClass().getSimpleName()); 134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu continue; 135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu File bitRateOutputDir = new File(mediaOutDir, bitrate); 137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bitRateOutputDir.mkdirs(); 138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.finer("Created : " + bitRateOutputDir.getCanonicalPath()); 139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long[] fragmentTimes = manifestWriter.calculateFragmentDurations(track, movieWithAdjustedTimescale); 141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long startTime = 0; 142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int currentFragment = 0; 143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu while (boxIt.hasNext()) { 144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Box b = boxIt.next(); 145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (b instanceof MovieFragmentBox) { 146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert ((MovieFragmentBox) b).getTrackCount() == 1; 147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (((MovieFragmentBox) b).getTrackNumbers()[0] == trackId) { 148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FileOutputStream fos = new FileOutputStream(new File(bitRateOutputDir, Long.toString(startTime))); 149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu startTime += fragmentTimes[currentFragment++]; 150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FileChannel fc = fos.getChannel(); 151dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Box mdat = boxIt.next(); 152dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert mdat.getType().equals("mdat"); 153dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu b.getBox(fc); // moof 154dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu mdat.getBox(fc); // mdat 155dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu fc.truncate(fc.position()); 156dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu fc.close(); 157dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 158dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 159dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 160dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 161dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 162dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu FileWriter fw = new FileWriter(new File(outputDirectory, "Manifest")); 163dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu fw.write(manifestWriter.getManifest(movieWithAdjustedTimescale)); 164dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu fw.close(); 165dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 166dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 167dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 168dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private Movie removeUnknownTracks(Movie source) { 169dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Movie nuMovie = new Movie(); 170dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : source.getTracks()) { 171dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if ("vide".equals(track.getHandler()) || "soun".equals(track.getHandler())) { 172dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu nuMovie.addTrack(track); 173dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 174dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.fine("Removed track " + track); 175dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 176dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 177dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return nuMovie; 178dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 179dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 180dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 181dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 182dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Returns a new <code>Movie</code> in that all tracks have the timescale 10000000. CTS & DTS are modified 183dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * in a way that even with more than one framerate the fragments exactly begin at the same time. 184dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 185dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param movie 186dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return a movie with timescales suitable for smooth streaming manifests 187dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 188dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public Movie correctTimescale(Movie movie) { 189dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu Movie nuMovie = new Movie(); 190dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (Track track : movie.getTracks()) { 191dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu nuMovie.addTrack(new ChangeTimeScaleTrack(track, timeScale, ismvBuilder.getFragmentIntersectionFinder().sampleNumbers(track, movie))); 192dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 193dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return nuMovie; 194dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 195dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 196dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 197dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu} 198