/* * 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; import com.coremedia.iso.boxes.*; import com.coremedia.iso.boxes.fragment.*; import com.coremedia.iso.boxes.mdat.SampleList; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import static com.googlecode.mp4parser.util.CastUtils.l2i; /** * Represents a single track of an MP4 file. */ public class Mp4TrackImpl extends AbstractTrack { private List samples; private SampleDescriptionBox sampleDescriptionBox; private List decodingTimeEntries; private List compositionTimeEntries; private long[] syncSamples = new long[0]; private List sampleDependencies; private TrackMetaData trackMetaData = new TrackMetaData(); private String handler; private AbstractMediaHeaderBox mihd; public Mp4TrackImpl(TrackBox trackBox) { final long trackId = trackBox.getTrackHeaderBox().getTrackId(); samples = new SampleList(trackBox); SampleTableBox stbl = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox(); handler = trackBox.getMediaBox().getHandlerBox().getHandlerType(); mihd = trackBox.getMediaBox().getMediaInformationBox().getMediaHeaderBox(); decodingTimeEntries = new LinkedList(); compositionTimeEntries = new LinkedList(); sampleDependencies = new LinkedList(); decodingTimeEntries.addAll(stbl.getTimeToSampleBox().getEntries()); if (stbl.getCompositionTimeToSample() != null) { compositionTimeEntries.addAll(stbl.getCompositionTimeToSample().getEntries()); } if (stbl.getSampleDependencyTypeBox() != null) { sampleDependencies.addAll(stbl.getSampleDependencyTypeBox().getEntries()); } if (stbl.getSyncSampleBox() != null) { syncSamples = stbl.getSyncSampleBox().getSampleNumber(); } sampleDescriptionBox = stbl.getSampleDescriptionBox(); final List movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class); if (movieExtendsBoxes.size() > 0) { for (MovieExtendsBox mvex : movieExtendsBoxes) { final List trackExtendsBoxes = mvex.getBoxes(TrackExtendsBox.class); for (TrackExtendsBox trex : trackExtendsBoxes) { if (trex.getTrackId() == trackId) { List syncSampleList = new LinkedList(); long sampleNumber = 1; for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) { List trafs = movieFragmentBox.getBoxes(TrackFragmentBox.class); for (TrackFragmentBox traf : trafs) { if (traf.getTrackFragmentHeaderBox().getTrackId() == trackId) { List truns = traf.getBoxes(TrackRunBox.class); for (TrackRunBox trun : truns) { final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox(); boolean first = true; for (TrackRunBox.Entry entry : trun.getEntries()) { if (trun.isSampleDurationPresent()) { if (decodingTimeEntries.size() == 0 || decodingTimeEntries.get(decodingTimeEntries.size() - 1).getDelta() != entry.getSampleDuration()) { decodingTimeEntries.add(new TimeToSampleBox.Entry(1, entry.getSampleDuration())); } else { TimeToSampleBox.Entry e = decodingTimeEntries.get(decodingTimeEntries.size() - 1); e.setCount(e.getCount() + 1); } } else { if (tfhd.hasDefaultSampleDuration()) { decodingTimeEntries.add(new TimeToSampleBox.Entry(1, tfhd.getDefaultSampleDuration())); } else { decodingTimeEntries.add(new TimeToSampleBox.Entry(1, trex.getDefaultSampleDuration())); } } if (trun.isSampleCompositionTimeOffsetPresent()) { if (compositionTimeEntries.size() == 0 || compositionTimeEntries.get(compositionTimeEntries.size() - 1).getOffset() != entry.getSampleCompositionTimeOffset()) { compositionTimeEntries.add(new CompositionTimeToSample.Entry(1, l2i(entry.getSampleCompositionTimeOffset()))); } else { CompositionTimeToSample.Entry e = compositionTimeEntries.get(compositionTimeEntries.size() - 1); e.setCount(e.getCount() + 1); } } final SampleFlags sampleFlags; if (trun.isSampleFlagsPresent()) { sampleFlags = entry.getSampleFlags(); } else { if (first && trun.isFirstSampleFlagsPresent()) { sampleFlags = trun.getFirstSampleFlags(); } else { if (tfhd.hasDefaultSampleFlags()) { sampleFlags = tfhd.getDefaultSampleFlags(); } else { sampleFlags = trex.getDefaultSampleFlags(); } } } if (sampleFlags != null && !sampleFlags.isSampleIsDifferenceSample()) { //iframe syncSampleList.add(sampleNumber); } sampleNumber++; first = false; } } } } } // Warning: Crappy code long[] oldSS = syncSamples; syncSamples = new long[syncSamples.length + syncSampleList.size()]; System.arraycopy(oldSS, 0, syncSamples, 0, oldSS.length); final Iterator iterator = syncSampleList.iterator(); int i = oldSS.length; while (iterator.hasNext()) { Long syncSampleNumber = iterator.next(); syncSamples[i++] = syncSampleNumber; } } } } } MediaHeaderBox mdhd = trackBox.getMediaBox().getMediaHeaderBox(); TrackHeaderBox tkhd = trackBox.getTrackHeaderBox(); setEnabled(tkhd.isEnabled()); setInMovie(tkhd.isInMovie()); setInPoster(tkhd.isInPoster()); setInPreview(tkhd.isInPreview()); trackMetaData.setTrackId(tkhd.getTrackId()); trackMetaData.setCreationTime(DateHelper.convert(mdhd.getCreationTime())); trackMetaData.setLanguage(mdhd.getLanguage()); /* System.err.println(mdhd.getModificationTime()); System.err.println(DateHelper.convert(mdhd.getModificationTime())); System.err.println(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime()))); System.err.println(DateHelper.convert(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime()))));*/ trackMetaData.setModificationTime(DateHelper.convert(mdhd.getModificationTime())); trackMetaData.setTimescale(mdhd.getTimescale()); trackMetaData.setHeight(tkhd.getHeight()); trackMetaData.setWidth(tkhd.getWidth()); trackMetaData.setLayer(tkhd.getLayer()); trackMetaData.setMatrix(tkhd.getMatrix()); } public List getSamples() { return samples; } public SampleDescriptionBox getSampleDescriptionBox() { return sampleDescriptionBox; } public List getDecodingTimeEntries() { return decodingTimeEntries; } public List getCompositionTimeEntries() { return compositionTimeEntries; } public long[] getSyncSamples() { return syncSamples; } public List getSampleDependencies() { return sampleDependencies; } public TrackMetaData getTrackMetaData() { return trackMetaData; } public String getHandler() { return handler; } public AbstractMediaHeaderBox getMediaHeaderBox() { return mihd; } public SubSampleInformationBox getSubsampleInformationBox() { return null; } @Override public String toString() { return "Mp4TrackImpl{" + "handler='" + handler + '\'' + '}'; } }