Home | History | Annotate | Download | only in authoring
      1 /*
      2  * Copyright 2012 Sebastian Annies, Hamburg
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the License);
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an AS IS BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.googlecode.mp4parser.authoring;
     17 
     18 import com.coremedia.iso.boxes.*;
     19 import com.coremedia.iso.boxes.fragment.*;
     20 import com.coremedia.iso.boxes.mdat.SampleList;
     21 
     22 import java.nio.ByteBuffer;
     23 import java.util.Iterator;
     24 import java.util.LinkedList;
     25 import java.util.List;
     26 
     27 import static com.googlecode.mp4parser.util.CastUtils.l2i;
     28 
     29 /**
     30  * Represents a single track of an MP4 file.
     31  */
     32 public class Mp4TrackImpl extends AbstractTrack {
     33     private List<ByteBuffer> samples;
     34     private SampleDescriptionBox sampleDescriptionBox;
     35     private List<TimeToSampleBox.Entry> decodingTimeEntries;
     36     private List<CompositionTimeToSample.Entry> compositionTimeEntries;
     37     private long[] syncSamples = new long[0];
     38     private List<SampleDependencyTypeBox.Entry> sampleDependencies;
     39     private TrackMetaData trackMetaData = new TrackMetaData();
     40     private String handler;
     41     private AbstractMediaHeaderBox mihd;
     42 
     43     public Mp4TrackImpl(TrackBox trackBox) {
     44         final long trackId = trackBox.getTrackHeaderBox().getTrackId();
     45         samples = new SampleList(trackBox);
     46         SampleTableBox stbl = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox();
     47         handler = trackBox.getMediaBox().getHandlerBox().getHandlerType();
     48 
     49         mihd = trackBox.getMediaBox().getMediaInformationBox().getMediaHeaderBox();
     50         decodingTimeEntries = new LinkedList<TimeToSampleBox.Entry>();
     51         compositionTimeEntries = new LinkedList<CompositionTimeToSample.Entry>();
     52         sampleDependencies = new LinkedList<SampleDependencyTypeBox.Entry>();
     53 
     54         decodingTimeEntries.addAll(stbl.getTimeToSampleBox().getEntries());
     55         if (stbl.getCompositionTimeToSample() != null) {
     56             compositionTimeEntries.addAll(stbl.getCompositionTimeToSample().getEntries());
     57         }
     58         if (stbl.getSampleDependencyTypeBox() != null) {
     59             sampleDependencies.addAll(stbl.getSampleDependencyTypeBox().getEntries());
     60         }
     61         if (stbl.getSyncSampleBox() != null) {
     62             syncSamples = stbl.getSyncSampleBox().getSampleNumber();
     63         }
     64 
     65 
     66         sampleDescriptionBox = stbl.getSampleDescriptionBox();
     67         final List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class);
     68         if (movieExtendsBoxes.size() > 0) {
     69             for (MovieExtendsBox mvex : movieExtendsBoxes) {
     70                 final List<TrackExtendsBox> trackExtendsBoxes = mvex.getBoxes(TrackExtendsBox.class);
     71                 for (TrackExtendsBox trex : trackExtendsBoxes) {
     72                     if (trex.getTrackId() == trackId) {
     73                         List<Long> syncSampleList = new LinkedList<Long>();
     74 
     75                         long sampleNumber = 1;
     76                         for (MovieFragmentBox movieFragmentBox : trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) {
     77                             List<TrackFragmentBox> trafs = movieFragmentBox.getBoxes(TrackFragmentBox.class);
     78                             for (TrackFragmentBox traf : trafs) {
     79                                 if (traf.getTrackFragmentHeaderBox().getTrackId() == trackId) {
     80                                     List<TrackRunBox> truns = traf.getBoxes(TrackRunBox.class);
     81                                     for (TrackRunBox trun : truns) {
     82                                         final TrackFragmentHeaderBox tfhd = ((TrackFragmentBox) trun.getParent()).getTrackFragmentHeaderBox();
     83                                         boolean first = true;
     84                                         for (TrackRunBox.Entry entry : trun.getEntries()) {
     85                                             if (trun.isSampleDurationPresent()) {
     86                                                 if (decodingTimeEntries.size() == 0 ||
     87                                                         decodingTimeEntries.get(decodingTimeEntries.size() - 1).getDelta() != entry.getSampleDuration()) {
     88                                                     decodingTimeEntries.add(new TimeToSampleBox.Entry(1, entry.getSampleDuration()));
     89                                                 } else {
     90                                                     TimeToSampleBox.Entry e = decodingTimeEntries.get(decodingTimeEntries.size() - 1);
     91                                                     e.setCount(e.getCount() + 1);
     92                                                 }
     93                                             } else {
     94                                                 if (tfhd.hasDefaultSampleDuration()) {
     95                                                     decodingTimeEntries.add(new TimeToSampleBox.Entry(1, tfhd.getDefaultSampleDuration()));
     96                                                 } else {
     97                                                     decodingTimeEntries.add(new TimeToSampleBox.Entry(1, trex.getDefaultSampleDuration()));
     98                                                 }
     99                                             }
    100 
    101                                             if (trun.isSampleCompositionTimeOffsetPresent()) {
    102                                                 if (compositionTimeEntries.size() == 0 ||
    103                                                         compositionTimeEntries.get(compositionTimeEntries.size() - 1).getOffset() != entry.getSampleCompositionTimeOffset()) {
    104                                                     compositionTimeEntries.add(new CompositionTimeToSample.Entry(1, l2i(entry.getSampleCompositionTimeOffset())));
    105                                                 } else {
    106                                                     CompositionTimeToSample.Entry e = compositionTimeEntries.get(compositionTimeEntries.size() - 1);
    107                                                     e.setCount(e.getCount() + 1);
    108                                                 }
    109                                             }
    110                                             final SampleFlags sampleFlags;
    111                                             if (trun.isSampleFlagsPresent()) {
    112                                                 sampleFlags = entry.getSampleFlags();
    113                                             } else {
    114                                                 if (first && trun.isFirstSampleFlagsPresent()) {
    115                                                     sampleFlags = trun.getFirstSampleFlags();
    116                                                 } else {
    117                                                     if (tfhd.hasDefaultSampleFlags()) {
    118                                                         sampleFlags = tfhd.getDefaultSampleFlags();
    119                                                     } else {
    120                                                         sampleFlags = trex.getDefaultSampleFlags();
    121                                                     }
    122                                                 }
    123                                             }
    124                                             if (sampleFlags != null && !sampleFlags.isSampleIsDifferenceSample()) {
    125                                                 //iframe
    126                                                 syncSampleList.add(sampleNumber);
    127                                             }
    128                                             sampleNumber++;
    129                                             first = false;
    130                                         }
    131                                     }
    132                                 }
    133                             }
    134                         }
    135                         // Warning: Crappy code
    136                         long[] oldSS = syncSamples;
    137                         syncSamples = new long[syncSamples.length + syncSampleList.size()];
    138                         System.arraycopy(oldSS, 0, syncSamples, 0, oldSS.length);
    139                         final Iterator<Long> iterator = syncSampleList.iterator();
    140                         int i = oldSS.length;
    141                         while (iterator.hasNext()) {
    142                             Long syncSampleNumber = iterator.next();
    143                             syncSamples[i++] = syncSampleNumber;
    144                         }
    145                     }
    146                 }
    147             }
    148         }
    149         MediaHeaderBox mdhd = trackBox.getMediaBox().getMediaHeaderBox();
    150         TrackHeaderBox tkhd = trackBox.getTrackHeaderBox();
    151 
    152         setEnabled(tkhd.isEnabled());
    153         setInMovie(tkhd.isInMovie());
    154         setInPoster(tkhd.isInPoster());
    155         setInPreview(tkhd.isInPreview());
    156 
    157         trackMetaData.setTrackId(tkhd.getTrackId());
    158         trackMetaData.setCreationTime(DateHelper.convert(mdhd.getCreationTime()));
    159         trackMetaData.setLanguage(mdhd.getLanguage());
    160 /*        System.err.println(mdhd.getModificationTime());
    161         System.err.println(DateHelper.convert(mdhd.getModificationTime()));
    162         System.err.println(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime())));
    163         System.err.println(DateHelper.convert(DateHelper.convert(DateHelper.convert(mdhd.getModificationTime()))));*/
    164 
    165         trackMetaData.setModificationTime(DateHelper.convert(mdhd.getModificationTime()));
    166         trackMetaData.setTimescale(mdhd.getTimescale());
    167         trackMetaData.setHeight(tkhd.getHeight());
    168         trackMetaData.setWidth(tkhd.getWidth());
    169         trackMetaData.setLayer(tkhd.getLayer());
    170         trackMetaData.setMatrix(tkhd.getMatrix());
    171     }
    172 
    173     public List<ByteBuffer> getSamples() {
    174         return samples;
    175     }
    176 
    177 
    178     public SampleDescriptionBox getSampleDescriptionBox() {
    179         return sampleDescriptionBox;
    180     }
    181 
    182     public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
    183         return decodingTimeEntries;
    184     }
    185 
    186     public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
    187         return compositionTimeEntries;
    188     }
    189 
    190     public long[] getSyncSamples() {
    191         return syncSamples;
    192     }
    193 
    194     public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
    195         return sampleDependencies;
    196     }
    197 
    198     public TrackMetaData getTrackMetaData() {
    199         return trackMetaData;
    200     }
    201 
    202     public String getHandler() {
    203         return handler;
    204     }
    205 
    206     public AbstractMediaHeaderBox getMediaHeaderBox() {
    207         return mihd;
    208     }
    209 
    210     public SubSampleInformationBox getSubsampleInformationBox() {
    211         return null;
    212     }
    213 
    214     @Override
    215     public String toString() {
    216         return "Mp4TrackImpl{" +
    217                 "handler='" + handler + '\'' +
    218                 '}';
    219     }
    220 }
    221