• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Mp4TrackImpl(TrackBox trackBox)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 
getSamples()173     public List<ByteBuffer> getSamples() {
174         return samples;
175     }
176 
177 
getSampleDescriptionBox()178     public SampleDescriptionBox getSampleDescriptionBox() {
179         return sampleDescriptionBox;
180     }
181 
getDecodingTimeEntries()182     public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
183         return decodingTimeEntries;
184     }
185 
getCompositionTimeEntries()186     public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
187         return compositionTimeEntries;
188     }
189 
getSyncSamples()190     public long[] getSyncSamples() {
191         return syncSamples;
192     }
193 
getSampleDependencies()194     public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
195         return sampleDependencies;
196     }
197 
getTrackMetaData()198     public TrackMetaData getTrackMetaData() {
199         return trackMetaData;
200     }
201 
getHandler()202     public String getHandler() {
203         return handler;
204     }
205 
getMediaHeaderBox()206     public AbstractMediaHeaderBox getMediaHeaderBox() {
207         return mihd;
208     }
209 
getSubsampleInformationBox()210     public SubSampleInformationBox getSubsampleInformationBox() {
211         return null;
212     }
213 
214     @Override
toString()215     public String toString() {
216         return "Mp4TrackImpl{" +
217                 "handler='" + handler + '\'' +
218                 '}';
219     }
220 }
221