1 /*
2  * Copyright (C) 2016 The Android Open Source Project
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.google.android.exoplayer2.extractor.mp4;
17 
18 import androidx.annotation.Nullable;
19 import com.google.android.exoplayer2.extractor.ExtractorInput;
20 import com.google.android.exoplayer2.util.ParsableByteArray;
21 import java.io.IOException;
22 import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
23 
24 /**
25  * A holder for information corresponding to a single fragment of an mp4 file.
26  */
27 /* package */ final class TrackFragment {
28 
29   /** The default values for samples from the track fragment header. */
30   public @MonotonicNonNull DefaultSampleValues header;
31   /**
32    * The position (byte offset) of the start of fragment.
33    */
34   public long atomPosition;
35   /**
36    * The position (byte offset) of the start of data contained in the fragment.
37    */
38   public long dataPosition;
39   /**
40    * The position (byte offset) of the start of auxiliary data.
41    */
42   public long auxiliaryDataPosition;
43   /**
44    * The number of track runs of the fragment.
45    */
46   public int trunCount;
47   /**
48    * The total number of samples in the fragment.
49    */
50   public int sampleCount;
51   /**
52    * The position (byte offset) of the start of sample data of each track run in the fragment.
53    */
54   public long[] trunDataPosition;
55   /**
56    * The number of samples contained by each track run in the fragment.
57    */
58   public int[] trunLength;
59   /**
60    * The size of each sample in the fragment.
61    */
62   public int[] sampleSizeTable;
63   /** The composition time offset of each sample in the fragment, in microseconds. */
64   public int[] sampleCompositionTimeOffsetUsTable;
65   /** The decoding time of each sample in the fragment, in microseconds. */
66   public long[] sampleDecodingTimeUsTable;
67   /**
68    * Indicates which samples are sync frames.
69    */
70   public boolean[] sampleIsSyncFrameTable;
71   /**
72    * Whether the fragment defines encryption data.
73    */
74   public boolean definesEncryptionData;
75   /**
76    * If {@link #definesEncryptionData} is true, indicates which samples use sub-sample encryption.
77    * Undefined otherwise.
78    */
79   public boolean[] sampleHasSubsampleEncryptionTable;
80   /** Fragment specific track encryption. May be null. */
81   @Nullable public TrackEncryptionBox trackEncryptionBox;
82   /**
83    * If {@link #definesEncryptionData} is true, contains binary sample encryption data. Undefined
84    * otherwise.
85    */
86   public final ParsableByteArray sampleEncryptionData;
87   /**
88    * Whether {@link #sampleEncryptionData} needs populating with the actual encryption data.
89    */
90   public boolean sampleEncryptionDataNeedsFill;
91   /**
92    * The absolute decode time of the start of the next fragment.
93    */
94   public long nextFragmentDecodeTime;
95 
TrackFragment()96   public TrackFragment() {
97     trunDataPosition = new long[0];
98     trunLength = new int[0];
99     sampleSizeTable = new int[0];
100     sampleCompositionTimeOffsetUsTable = new int[0];
101     sampleDecodingTimeUsTable = new long[0];
102     sampleIsSyncFrameTable = new boolean[0];
103     sampleHasSubsampleEncryptionTable = new boolean[0];
104     sampleEncryptionData = new ParsableByteArray();
105   }
106 
107   /**
108    * Resets the fragment.
109    * <p>
110    * {@link #sampleCount} and {@link #nextFragmentDecodeTime} are set to 0, and both
111    * {@link #definesEncryptionData} and {@link #sampleEncryptionDataNeedsFill} is set to false,
112    * and {@link #trackEncryptionBox} is set to null.
113    */
reset()114   public void reset() {
115     trunCount = 0;
116     nextFragmentDecodeTime = 0;
117     definesEncryptionData = false;
118     sampleEncryptionDataNeedsFill = false;
119     trackEncryptionBox = null;
120   }
121 
122   /**
123    * Configures the fragment for the specified number of samples.
124    * <p>
125    * The {@link #sampleCount} of the fragment is set to the specified sample count, and the
126    * contained tables are resized if necessary such that they are at least this length.
127    *
128    * @param sampleCount The number of samples in the new run.
129    */
initTables(int trunCount, int sampleCount)130   public void initTables(int trunCount, int sampleCount) {
131     this.trunCount = trunCount;
132     this.sampleCount = sampleCount;
133     if (trunLength.length < trunCount) {
134       trunDataPosition = new long[trunCount];
135       trunLength = new int[trunCount];
136     }
137     if (sampleSizeTable.length < sampleCount) {
138       // Size the tables 25% larger than needed, so as to make future resize operations less
139       // likely. The choice of 25% is relatively arbitrary.
140       int tableSize = (sampleCount * 125) / 100;
141       sampleSizeTable = new int[tableSize];
142       sampleCompositionTimeOffsetUsTable = new int[tableSize];
143       sampleDecodingTimeUsTable = new long[tableSize];
144       sampleIsSyncFrameTable = new boolean[tableSize];
145       sampleHasSubsampleEncryptionTable = new boolean[tableSize];
146     }
147   }
148 
149   /**
150    * Configures the fragment to be one that defines encryption data of the specified length.
151    *
152    * <p>{@link #definesEncryptionData} is set to true, and the {@link ParsableByteArray#limit()
153    * limit} of {@link #sampleEncryptionData} is set to the specified length.
154    *
155    * @param length The length in bytes of the encryption data.
156    */
initEncryptionData(int length)157   public void initEncryptionData(int length) {
158     sampleEncryptionData.reset(length);
159     definesEncryptionData = true;
160     sampleEncryptionDataNeedsFill = true;
161   }
162 
163   /**
164    * Fills {@link #sampleEncryptionData} from the provided input.
165    *
166    * @param input An {@link ExtractorInput} from which to read the encryption data.
167    */
fillEncryptionData(ExtractorInput input)168   public void fillEncryptionData(ExtractorInput input) throws IOException {
169     input.readFully(sampleEncryptionData.data, 0, sampleEncryptionData.limit());
170     sampleEncryptionData.setPosition(0);
171     sampleEncryptionDataNeedsFill = false;
172   }
173 
174   /**
175    * Fills {@link #sampleEncryptionData} from the provided source.
176    *
177    * @param source A source from which to read the encryption data.
178    */
fillEncryptionData(ParsableByteArray source)179   public void fillEncryptionData(ParsableByteArray source) {
180     source.readBytes(sampleEncryptionData.data, 0, sampleEncryptionData.limit());
181     sampleEncryptionData.setPosition(0);
182     sampleEncryptionDataNeedsFill = false;
183   }
184 
185   /**
186    * Returns the sample presentation timestamp in microseconds.
187    *
188    * @param index The sample index.
189    * @return The presentation timestamps of this sample in microseconds.
190    */
getSamplePresentationTimeUs(int index)191   public long getSamplePresentationTimeUs(int index) {
192     return sampleDecodingTimeUsTable[index] + sampleCompositionTimeOffsetUsTable[index];
193   }
194 
195   /** Returns whether the sample at the given index has a subsample encryption table. */
sampleHasSubsampleEncryptionTable(int index)196   public boolean sampleHasSubsampleEncryptionTable(int index) {
197     return definesEncryptionData && sampleHasSubsampleEncryptionTable[index];
198   }
199 }
200