diff options
Diffstat (limited to 'isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base')
-rw-r--r-- | isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base | 742 |
1 files changed, 0 insertions, 742 deletions
diff --git a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base b/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base deleted file mode 100644 index c65ff1c..0000000 --- a/isoparser/src/main/java/com/googlecode/mp4parser/authoring/builder/.svn/text-base/FragmentedMp4Builder.java.svn-base +++ /dev/null @@ -1,742 +0,0 @@ -/* - * 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.builder; - -import com.coremedia.iso.BoxParser; -import com.coremedia.iso.IsoFile; -import com.coremedia.iso.IsoTypeWriter; -import com.coremedia.iso.boxes.*; -import com.coremedia.iso.boxes.fragment.*; -import com.googlecode.mp4parser.authoring.DateHelper; -import com.googlecode.mp4parser.authoring.Movie; -import com.googlecode.mp4parser.authoring.Track; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.GatheringByteChannel; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; -import java.util.*; -import java.util.logging.Logger; - -import static com.googlecode.mp4parser.util.CastUtils.l2i; - -/** - * Creates a fragmented MP4 file. - */ -public class FragmentedMp4Builder implements Mp4Builder { - private static final Logger LOG = Logger.getLogger(FragmentedMp4Builder.class.getName()); - - protected FragmentIntersectionFinder intersectionFinder; - - public FragmentedMp4Builder() { - this.intersectionFinder = new SyncSampleIntersectFinderImpl(); - } - - public List<String> getAllowedHandlers() { - return Arrays.asList("soun", "vide"); - } - - public Box createFtyp(Movie movie) { - List<String> minorBrands = new LinkedList<String>(); - minorBrands.add("isom"); - minorBrands.add("iso2"); - minorBrands.add("avc1"); - return new FileTypeBox("isom", 0, minorBrands); - } - - /** - * Some formats require sorting of the fragments. E.g. Ultraviolet CFF files are required - * to contain the fragments size sort: - * <ul> - * <li>video[1].getBytes().length < audio[1].getBytes().length < subs[1].getBytes().length</li> - * <li> audio[2].getBytes().length < video[2].getBytes().length < subs[2].getBytes().length</li> - * </ul> - * - * make this fragment: - * - * <ol> - * <li>video[1]</li> - * <li>audio[1]</li> - * <li>subs[1]</li> - * <li>audio[2]</li> - * <li>video[2]</li> - * <li>subs[2]</li> - * </ol> - * - * @param tracks the list of tracks to returned sorted - * @param cycle current fragment (sorting may vary between the fragments) - * @param intersectionMap a map from tracks to their fragments' first samples. - * @return the list of tracks in order of appearance in the fragment - */ - protected List<Track> sortTracksInSequence(List<Track> tracks, final int cycle, final Map<Track, long[]> intersectionMap) { - tracks = new LinkedList<Track>(tracks); - Collections.sort(tracks, new Comparator<Track>() { - public int compare(Track o1, Track o2) { - long[] startSamples1 = intersectionMap.get(o1); - long startSample1 = startSamples1[cycle]; - // one based sample numbers - the first sample is 1 - long endSample1 = cycle + 1 < startSamples1.length ? startSamples1[cycle + 1] : o1.getSamples().size() + 1; - long[] startSamples2 = intersectionMap.get(o2); - long startSample2 = startSamples2[cycle]; - // one based sample numbers - the first sample is 1 - long endSample2 = cycle + 1 < startSamples2.length ? startSamples2[cycle + 1] : o2.getSamples().size() + 1; - List<ByteBuffer> samples1 = o1.getSamples().subList(l2i(startSample1) - 1, l2i(endSample1) - 1); - List<ByteBuffer> samples2 = o2.getSamples().subList(l2i(startSample2) - 1, l2i(endSample2) - 1); - int size1 = 0; - for (ByteBuffer byteBuffer : samples1) { - size1 += byteBuffer.limit(); - } - int size2 = 0; - for (ByteBuffer byteBuffer : samples2) { - size2 += byteBuffer.limit(); - } - return size1 - size2; - } - }); - return tracks; - } - - protected List<Box> createMoofMdat(final Movie movie) { - List<Box> boxes = new LinkedList<Box>(); - HashMap<Track, long[]> intersectionMap = new HashMap<Track, long[]>(); - int maxNumberOfFragments = 0; - for (Track track : movie.getTracks()) { - long[] intersects = intersectionFinder.sampleNumbers(track, movie); - intersectionMap.put(track, intersects); - maxNumberOfFragments = Math.max(maxNumberOfFragments, intersects.length); - } - - - int sequence = 1; - // this loop has two indices: - - for (int cycle = 0; cycle < maxNumberOfFragments; cycle++) { - - final List<Track> sortedTracks = sortTracksInSequence(movie.getTracks(), cycle, intersectionMap); - - for (Track track : sortedTracks) { - if (getAllowedHandlers().isEmpty() || getAllowedHandlers().contains(track.getHandler())) { - long[] startSamples = intersectionMap.get(track); - //some tracks may have less fragments -> skip them - if (cycle < startSamples.length) { - - long startSample = startSamples[cycle]; - // one based sample numbers - the first sample is 1 - long endSample = cycle + 1 < startSamples.length ? startSamples[cycle + 1] : track.getSamples().size() + 1; - - // if startSample == endSample the cycle is empty! - if (startSample != endSample) { - boxes.add(createMoof(startSample, endSample, track, sequence)); - boxes.add(createMdat(startSample, endSample, track, sequence++)); - } - } - } - } - } - return boxes; - } - - /** - * {@inheritDoc} - */ - public IsoFile build(Movie movie) { - LOG.fine("Creating movie " + movie); - IsoFile isoFile = new IsoFile(); - - - isoFile.addBox(createFtyp(movie)); - isoFile.addBox(createMoov(movie)); - - for (Box box : createMoofMdat(movie)) { - isoFile.addBox(box); - } - isoFile.addBox(createMfra(movie, isoFile)); - - return isoFile; - } - - protected Box createMdat(final long startSample, final long endSample, final Track track, final int i) { - - class Mdat implements Box { - ContainerBox parent; - - public ContainerBox getParent() { - return parent; - } - - public void setParent(ContainerBox parent) { - this.parent = parent; - } - - public long getSize() { - long size = 8; // I don't expect 2gig fragments - for (ByteBuffer sample : getSamples(startSample, endSample, track, i)) { - size += sample.limit(); - } - return size; - } - - public String getType() { - return "mdat"; - } - - public void getBox(WritableByteChannel writableByteChannel) throws IOException { - List<ByteBuffer> bbs = getSamples(startSample, endSample, track, i); - final List<ByteBuffer> samples = ByteBufferHelper.mergeAdjacentBuffers(bbs); - ByteBuffer header = ByteBuffer.allocate(8); - IsoTypeWriter.writeUInt32(header, l2i(getSize())); - header.put(IsoFile.fourCCtoBytes(getType())); - header.rewind(); - writableByteChannel.write(header); - if (writableByteChannel instanceof GatheringByteChannel) { - - int STEPSIZE = 1024; - // This is required to prevent android from crashing - // it seems that {@link GatheringByteChannel#write(java.nio.ByteBuffer[])} - // just handles up to 1024 buffers - for (int i = 0; i < Math.ceil((double) samples.size() / STEPSIZE); i++) { - List<ByteBuffer> sublist = samples.subList( - i * STEPSIZE, // start - (i + 1) * STEPSIZE < samples.size() ? (i + 1) * STEPSIZE : samples.size()); // end - ByteBuffer sampleArray[] = sublist.toArray(new ByteBuffer[sublist.size()]); - do { - ((GatheringByteChannel) writableByteChannel).write(sampleArray); - } while (sampleArray[sampleArray.length - 1].remaining() > 0); - } - //System.err.println(bytesWritten); - } else { - for (ByteBuffer sample : samples) { - sample.rewind(); - writableByteChannel.write(sample); - } - } - - } - - public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { - - } - } - - return new Mdat(); - } - - protected Box createTfhd(long startSample, long endSample, Track track, int sequenceNumber) { - TrackFragmentHeaderBox tfhd = new TrackFragmentHeaderBox(); - SampleFlags sf = new SampleFlags(); - - tfhd.setDefaultSampleFlags(sf); - tfhd.setBaseDataOffset(-1); - tfhd.setTrackId(track.getTrackMetaData().getTrackId()); - return tfhd; - } - - protected Box createMfhd(long startSample, long endSample, Track track, int sequenceNumber) { - MovieFragmentHeaderBox mfhd = new MovieFragmentHeaderBox(); - mfhd.setSequenceNumber(sequenceNumber); - return mfhd; - } - - protected Box createTraf(long startSample, long endSample, Track track, int sequenceNumber) { - TrackFragmentBox traf = new TrackFragmentBox(); - traf.addBox(createTfhd(startSample, endSample, track, sequenceNumber)); - for (Box trun : createTruns(startSample, endSample, track, sequenceNumber)) { - traf.addBox(trun); - } - - return traf; - } - - - /** - * Gets the all samples starting with <code>startSample</code> (one based -> one is the first) and - * ending with <code>endSample</code> (exclusive). - * - * @param startSample low endpoint (inclusive) of the sample sequence - * @param endSample high endpoint (exclusive) of the sample sequence - * @param track source of the samples - * @param sequenceNumber the fragment index of the requested list of samples - * @return a <code>List<ByteBuffer></code> of raw samples - */ - protected List<ByteBuffer> getSamples(long startSample, long endSample, Track track, int sequenceNumber) { - // since startSample and endSample are one-based substract 1 before addressing list elements - return track.getSamples().subList(l2i(startSample) - 1, l2i(endSample) - 1); - } - - /** - * Gets the sizes of a sequence of samples- - * - * @param startSample low endpoint (inclusive) of the sample sequence - * @param endSample high endpoint (exclusive) of the sample sequence - * @param track source of the samples - * @param sequenceNumber the fragment index of the requested list of samples - * @return - */ - protected long[] getSampleSizes(long startSample, long endSample, Track track, int sequenceNumber) { - List<ByteBuffer> samples = getSamples(startSample, endSample, track, sequenceNumber); - - long[] sampleSizes = new long[samples.size()]; - for (int i = 0; i < sampleSizes.length; i++) { - sampleSizes[i] = samples.get(i).limit(); - } - return sampleSizes; - } - - /** - * Creates one or more track run boxes for a given sequence. - * - * @param startSample low endpoint (inclusive) of the sample sequence - * @param endSample high endpoint (exclusive) of the sample sequence - * @param track source of the samples - * @param sequenceNumber the fragment index of the requested list of samples - * @return the list of TrackRun boxes. - */ - protected List<? extends Box> createTruns(long startSample, long endSample, Track track, int sequenceNumber) { - TrackRunBox trun = new TrackRunBox(); - long[] sampleSizes = getSampleSizes(startSample, endSample, track, sequenceNumber); - - trun.setSampleDurationPresent(true); - trun.setSampleSizePresent(true); - List<TrackRunBox.Entry> entries = new ArrayList<TrackRunBox.Entry>(l2i(endSample - startSample)); - - - Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries()); - long left = startSample - 1; - long curEntryLeft = timeQueue.peek().getCount(); - while (left > curEntryLeft) { - left -= curEntryLeft; - timeQueue.remove(); - curEntryLeft = timeQueue.peek().getCount(); - } - curEntryLeft -= left; - - - Queue<CompositionTimeToSample.Entry> compositionTimeQueue = - track.getCompositionTimeEntries() != null && track.getCompositionTimeEntries().size() > 0 ? - new LinkedList<CompositionTimeToSample.Entry>(track.getCompositionTimeEntries()) : null; - long compositionTimeEntriesLeft = compositionTimeQueue != null ? compositionTimeQueue.peek().getCount() : -1; - - - trun.setSampleCompositionTimeOffsetPresent(compositionTimeEntriesLeft > 0); - - // fast forward composition stuff - for (long i = 1; i < startSample; i++) { - if (compositionTimeQueue != null) { - //trun.setSampleCompositionTimeOffsetPresent(true); - if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) { - compositionTimeQueue.remove(); - compositionTimeEntriesLeft = compositionTimeQueue.element().getCount(); - } - } - } - - boolean sampleFlagsRequired = (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty() || - track.getSyncSamples() != null && track.getSyncSamples().length != 0); - - trun.setSampleFlagsPresent(sampleFlagsRequired); - - for (int i = 0; i < sampleSizes.length; i++) { - TrackRunBox.Entry entry = new TrackRunBox.Entry(); - entry.setSampleSize(sampleSizes[i]); - if (sampleFlagsRequired) { - //if (false) { - SampleFlags sflags = new SampleFlags(); - - if (track.getSampleDependencies() != null && !track.getSampleDependencies().isEmpty()) { - SampleDependencyTypeBox.Entry e = track.getSampleDependencies().get(i); - sflags.setSampleDependsOn(e.getSampleDependsOn()); - sflags.setSampleIsDependedOn(e.getSampleIsDependentOn()); - sflags.setSampleHasRedundancy(e.getSampleHasRedundancy()); - } - if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { - // we have to mark non-sync samples! - if (Arrays.binarySearch(track.getSyncSamples(), startSample + i) >= 0) { - sflags.setSampleIsDifferenceSample(false); - sflags.setSampleDependsOn(2); - } else { - sflags.setSampleIsDifferenceSample(true); - sflags.setSampleDependsOn(1); - } - } - // i don't have sample degradation - entry.setSampleFlags(sflags); - - } - - entry.setSampleDuration(timeQueue.peek().getDelta()); - if (--curEntryLeft == 0 && timeQueue.size() > 1) { - timeQueue.remove(); - curEntryLeft = timeQueue.peek().getCount(); - } - - if (compositionTimeQueue != null) { - entry.setSampleCompositionTimeOffset(compositionTimeQueue.peek().getOffset()); - if (--compositionTimeEntriesLeft == 0 && compositionTimeQueue.size() > 1) { - compositionTimeQueue.remove(); - compositionTimeEntriesLeft = compositionTimeQueue.element().getCount(); - } - } - entries.add(entry); - } - - trun.setEntries(entries); - - return Collections.singletonList(trun); - } - - /** - * Creates a 'moof' box for a given sequence of samples. - * - * @param startSample low endpoint (inclusive) of the sample sequence - * @param endSample high endpoint (exclusive) of the sample sequence - * @param track source of the samples - * @param sequenceNumber the fragment index of the requested list of samples - * @return the list of TrackRun boxes. - */ - protected Box createMoof(long startSample, long endSample, Track track, int sequenceNumber) { - MovieFragmentBox moof = new MovieFragmentBox(); - moof.addBox(createMfhd(startSample, endSample, track, sequenceNumber)); - moof.addBox(createTraf(startSample, endSample, track, sequenceNumber)); - - TrackRunBox firstTrun = moof.getTrackRunBoxes().get(0); - firstTrun.setDataOffset(1); // dummy to make size correct - firstTrun.setDataOffset((int) (8 + moof.getSize())); // mdat header + moof size - - return moof; - } - - /** - * Creates a single 'mvhd' movie header box for a given movie. - * - * @param movie the concerned movie - * @return an 'mvhd' box - */ - protected Box createMvhd(Movie movie) { - MovieHeaderBox mvhd = new MovieHeaderBox(); - mvhd.setVersion(1); - mvhd.setCreationTime(DateHelper.convert(new Date())); - mvhd.setModificationTime(DateHelper.convert(new Date())); - long movieTimeScale = movie.getTimescale(); - long duration = 0; - - for (Track track : movie.getTracks()) { - long tracksDuration = getDuration(track) * movieTimeScale / track.getTrackMetaData().getTimescale(); - if (tracksDuration > duration) { - duration = tracksDuration; - } - - - } - - mvhd.setDuration(duration); - mvhd.setTimescale(movieTimeScale); - // find the next available trackId - long nextTrackId = 0; - for (Track track : movie.getTracks()) { - nextTrackId = nextTrackId < track.getTrackMetaData().getTrackId() ? track.getTrackMetaData().getTrackId() : nextTrackId; - } - mvhd.setNextTrackId(++nextTrackId); - return mvhd; - } - - /** - * Creates a fully populated 'moov' box with all child boxes. Child boxes are: - * <ul> - * <li>{@link #createMvhd(com.googlecode.mp4parser.authoring.Movie) mvhd}</li> - * <li>{@link #createMvex(com.googlecode.mp4parser.authoring.Movie) mvex}</li> - * <li>a {@link #createTrak(com.googlecode.mp4parser.authoring.Track, com.googlecode.mp4parser.authoring.Movie) trak} for every track</li> - * </ul> - * - * @param movie the concerned movie - * @return fully populated 'moov' - */ - protected Box createMoov(Movie movie) { - MovieBox movieBox = new MovieBox(); - - movieBox.addBox(createMvhd(movie)); - movieBox.addBox(createMvex(movie)); - - for (Track track : movie.getTracks()) { - movieBox.addBox(createTrak(track, movie)); - } - // metadata here - return movieBox; - - } - - /** - * Creates a 'tfra' - track fragment random access box for the given track with the isoFile. - * The tfra contains a map of random access points with time as key and offset within the isofile - * as value. - * - * @param track the concerned track - * @param isoFile the track is contained in - * @return a track fragment random access box. - */ - protected Box createTfra(Track track, IsoFile isoFile) { - TrackFragmentRandomAccessBox tfra = new TrackFragmentRandomAccessBox(); - tfra.setVersion(1); // use long offsets and times - List<TrackFragmentRandomAccessBox.Entry> offset2timeEntries = new LinkedList<TrackFragmentRandomAccessBox.Entry>(); - List<Box> boxes = isoFile.getBoxes(); - long offset = 0; - long duration = 0; - for (Box box : boxes) { - if (box instanceof MovieFragmentBox) { - List<TrackFragmentBox> trafs = ((MovieFragmentBox) box).getBoxes(TrackFragmentBox.class); - for (int i = 0; i < trafs.size(); i++) { - TrackFragmentBox traf = trafs.get(i); - if (traf.getTrackFragmentHeaderBox().getTrackId() == track.getTrackMetaData().getTrackId()) { - // here we are at the offset required for the current entry. - List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class); - for (int j = 0; j < truns.size(); j++) { - List<TrackFragmentRandomAccessBox.Entry> offset2timeEntriesThisTrun = new LinkedList<TrackFragmentRandomAccessBox.Entry>(); - TrackRunBox trun = truns.get(j); - for (int k = 0; k < trun.getEntries().size(); k++) { - TrackRunBox.Entry trunEntry = trun.getEntries().get(k); - SampleFlags sf = null; - if (k == 0 && trun.isFirstSampleFlagsPresent()) { - sf = trun.getFirstSampleFlags(); - } else if (trun.isSampleFlagsPresent()) { - sf = trunEntry.getSampleFlags(); - } else { - List<MovieExtendsBox> mvexs = isoFile.getMovieBox().getBoxes(MovieExtendsBox.class); - for (MovieExtendsBox mvex : mvexs) { - List<TrackExtendsBox> trexs = mvex.getBoxes(TrackExtendsBox.class); - for (TrackExtendsBox trex : trexs) { - if (trex.getTrackId() == track.getTrackMetaData().getTrackId()) { - sf = trex.getDefaultSampleFlags(); - } - } - } - - } - if (sf == null) { - throw new RuntimeException("Could not find any SampleFlags to indicate random access or not"); - } - if (sf.getSampleDependsOn() == 2) { - offset2timeEntriesThisTrun.add(new TrackFragmentRandomAccessBox.Entry( - duration, - offset, - i + 1, j + 1, k + 1)); - } - duration += trunEntry.getSampleDuration(); - } - if (offset2timeEntriesThisTrun.size() == trun.getEntries().size() && trun.getEntries().size() > 0) { - // Oooops every sample seems to be random access sample - // is this an audio track? I don't care. - // I just use the first for trun sample for tfra random access - offset2timeEntries.add(offset2timeEntriesThisTrun.get(0)); - } else { - offset2timeEntries.addAll(offset2timeEntriesThisTrun); - } - } - } - } - } - - - offset += box.getSize(); - } - tfra.setEntries(offset2timeEntries); - tfra.setTrackId(track.getTrackMetaData().getTrackId()); - return tfra; - } - - /** - * Creates a 'mfra' - movie fragment random access box for the given movie in the given - * isofile. Uses {@link #createTfra(com.googlecode.mp4parser.authoring.Track, com.coremedia.iso.IsoFile)} - * to generate the child boxes. - * - * @param movie concerned movie - * @param isoFile concerned isofile - * @return a complete 'mfra' box - */ - protected Box createMfra(Movie movie, IsoFile isoFile) { - MovieFragmentRandomAccessBox mfra = new MovieFragmentRandomAccessBox(); - for (Track track : movie.getTracks()) { - mfra.addBox(createTfra(track, isoFile)); - } - - MovieFragmentRandomAccessOffsetBox mfro = new MovieFragmentRandomAccessOffsetBox(); - mfra.addBox(mfro); - mfro.setMfraSize(mfra.getSize()); - return mfra; - } - - protected Box createTrex(Movie movie, Track track) { - TrackExtendsBox trex = new TrackExtendsBox(); - trex.setTrackId(track.getTrackMetaData().getTrackId()); - trex.setDefaultSampleDescriptionIndex(1); - trex.setDefaultSampleDuration(0); - trex.setDefaultSampleSize(0); - SampleFlags sf = new SampleFlags(); - if ("soun".equals(track.getHandler())) { - // as far as I know there is no audio encoding - // where the sample are not self contained. - sf.setSampleDependsOn(2); - sf.setSampleIsDependedOn(2); - } - trex.setDefaultSampleFlags(sf); - return trex; - } - - /** - * Creates a 'mvex' - movie extends box and populates it with 'trex' boxes - * by calling {@link #createTrex(com.googlecode.mp4parser.authoring.Movie, com.googlecode.mp4parser.authoring.Track)} - * for each track to generate them - * - * @param movie the source movie - * @return a complete 'mvex' - */ - protected Box createMvex(Movie movie) { - MovieExtendsBox mvex = new MovieExtendsBox(); - final MovieExtendsHeaderBox mved = new MovieExtendsHeaderBox(); - for (Track track : movie.getTracks()) { - final long trackDuration = getTrackDuration(movie, track); - if (mved.getFragmentDuration() < trackDuration) { - mved.setFragmentDuration(trackDuration); - } - } - mvex.addBox(mved); - - for (Track track : movie.getTracks()) { - mvex.addBox(createTrex(movie, track)); - } - return mvex; - } - - protected Box createTkhd(Movie movie, Track track) { - TrackHeaderBox tkhd = new TrackHeaderBox(); - tkhd.setVersion(1); - int flags = 0; - if (track.isEnabled()) { - flags += 1; - } - - if (track.isInMovie()) { - flags += 2; - } - - if (track.isInPreview()) { - flags += 4; - } - - if (track.isInPoster()) { - flags += 8; - } - tkhd.setFlags(flags); - - tkhd.setAlternateGroup(track.getTrackMetaData().getGroup()); - tkhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime())); - // We need to take edit list box into account in trackheader duration - // but as long as I don't support edit list boxes it is sufficient to - // just translate media duration to movie timescale - tkhd.setDuration(getTrackDuration(movie, track)); - tkhd.setHeight(track.getTrackMetaData().getHeight()); - tkhd.setWidth(track.getTrackMetaData().getWidth()); - tkhd.setLayer(track.getTrackMetaData().getLayer()); - tkhd.setModificationTime(DateHelper.convert(new Date())); - tkhd.setTrackId(track.getTrackMetaData().getTrackId()); - tkhd.setVolume(track.getTrackMetaData().getVolume()); - return tkhd; - } - - private long getTrackDuration(Movie movie, Track track) { - return getDuration(track) * movie.getTimescale() / track.getTrackMetaData().getTimescale(); - } - - protected Box createMdhd(Movie movie, Track track) { - MediaHeaderBox mdhd = new MediaHeaderBox(); - mdhd.setCreationTime(DateHelper.convert(track.getTrackMetaData().getCreationTime())); - mdhd.setDuration(getDuration(track)); - mdhd.setTimescale(track.getTrackMetaData().getTimescale()); - mdhd.setLanguage(track.getTrackMetaData().getLanguage()); - return mdhd; - } - - protected Box createStbl(Movie movie, Track track) { - SampleTableBox stbl = new SampleTableBox(); - - stbl.addBox(track.getSampleDescriptionBox()); - stbl.addBox(new TimeToSampleBox()); - //stbl.addBox(new SampleToChunkBox()); - stbl.addBox(new StaticChunkOffsetBox()); - return stbl; - } - - protected Box createMinf(Track track, Movie movie) { - MediaInformationBox minf = new MediaInformationBox(); - minf.addBox(track.getMediaHeaderBox()); - minf.addBox(createDinf(movie, track)); - minf.addBox(createStbl(movie, track)); - return minf; - } - - protected Box createMdiaHdlr(Track track, Movie movie) { - HandlerBox hdlr = new HandlerBox(); - hdlr.setHandlerType(track.getHandler()); - return hdlr; - } - - protected Box createMdia(Track track, Movie movie) { - MediaBox mdia = new MediaBox(); - mdia.addBox(createMdhd(movie, track)); - - - mdia.addBox(createMdiaHdlr(track, movie)); - - - mdia.addBox(createMinf(track, movie)); - return mdia; - } - - protected Box createTrak(Track track, Movie movie) { - LOG.fine("Creating Track " + track); - TrackBox trackBox = new TrackBox(); - trackBox.addBox(createTkhd(movie, track)); - trackBox.addBox(createMdia(track, movie)); - return trackBox; - } - - protected DataInformationBox createDinf(Movie movie, Track track) { - DataInformationBox dinf = new DataInformationBox(); - DataReferenceBox dref = new DataReferenceBox(); - dinf.addBox(dref); - DataEntryUrlBox url = new DataEntryUrlBox(); - url.setFlags(1); - dref.addBox(url); - return dinf; - } - - public FragmentIntersectionFinder getFragmentIntersectionFinder() { - return intersectionFinder; - } - - public void setIntersectionFinder(FragmentIntersectionFinder intersectionFinder) { - this.intersectionFinder = intersectionFinder; - } - - protected long getDuration(Track track) { - long duration = 0; - for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) { - duration += entry.getCount() * entry.getDelta(); - } - return duration; - } - - -} |