/* * Copyright (C) 2014 The Android Open Source Project * * 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.google.android.exoplayer.parser.mp4; import com.google.android.exoplayer.upstream.NonBlockingInputStream; /** * A holder for information corresponding to a single fragment of an mp4 file. */ /* package */ final class TrackFragment { public int sampleDescriptionIndex; /** * The number of samples contained by the fragment. */ public int length; /** * The size of each sample in the run. */ public int[] sampleSizeTable; /** * The decoding time of each sample in the run. */ public int[] sampleDecodingTimeTable; /** * The composition time offset of each sample in the run. */ public int[] sampleCompositionTimeOffsetTable; /** * Indicates which samples are sync frames. */ public boolean[] sampleIsSyncFrameTable; /** * True if the fragment defines encryption data. False otherwise. */ public boolean definesEncryptionData; /** * If {@link #definesEncryptionData} is true, indicates which samples use sub-sample encryption. * Undefined otherwise. */ public boolean[] sampleHasSubsampleEncryptionTable; /** * If {@link #definesEncryptionData} is true, indicates the length of the sample encryption data. * Undefined otherwise. */ public int sampleEncryptionDataLength; /** * If {@link #definesEncryptionData} is true, contains binary sample encryption data. Undefined * otherwise. */ public ParsableByteArray sampleEncryptionData; /** * Whether {@link #sampleEncryptionData} needs populating with the actual encryption data. */ public boolean sampleEncryptionDataNeedsFill; /** * Resets the fragment. * <p> * The {@link #length} is set to 0, and both {@link #definesEncryptionData} and * {@link #sampleEncryptionDataNeedsFill} is set to false. */ public void reset() { length = 0; definesEncryptionData = false; sampleEncryptionDataNeedsFill = false; } /** * Configures the fragment for the specified number of samples. * <p> * The {@link #length} of the fragment is set to the specified sample count, and the contained * tables are resized if necessary such that they are at least this length. * * @param sampleCount The number of samples in the new run. */ public void initTables(int sampleCount) { length = sampleCount; if (sampleSizeTable == null || sampleSizeTable.length < length) { // Size the tables 25% larger than needed, so as to make future resize operations less // likely. The choice of 25% is relatively arbitrary. int tableSize = (sampleCount * 125) / 100; sampleSizeTable = new int[tableSize]; sampleDecodingTimeTable = new int[tableSize]; sampleCompositionTimeOffsetTable = new int[tableSize]; sampleIsSyncFrameTable = new boolean[tableSize]; sampleHasSubsampleEncryptionTable = new boolean[tableSize]; } } /** * Configures the fragment to be one that defines encryption data of the specified length. * <p> * {@link #definesEncryptionData} is set to true, {@link #sampleEncryptionDataLength} is set to * the specified length, and {@link #sampleEncryptionData} is resized if necessary such that it * is at least this length. * * @param length The length in bytes of the encryption data. */ public void initEncryptionData(int length) { if (sampleEncryptionData == null || sampleEncryptionData.length() < length) { sampleEncryptionData = new ParsableByteArray(length); } sampleEncryptionDataLength = length; definesEncryptionData = true; sampleEncryptionDataNeedsFill = true; } /** * Fills {@link #sampleEncryptionData} from the provided source. * * @param source A source from which to read the encryption data. */ public void fillEncryptionData(ParsableByteArray source) { source.readBytes(sampleEncryptionData.data, 0, sampleEncryptionDataLength); sampleEncryptionData.setPosition(0); sampleEncryptionDataNeedsFill = false; } /** * Fills {@link #sampleEncryptionData} for the current run from the provided source. * * @param source A source from which to read the encryption data. * @return True if the encryption data was filled. False if the source had insufficient data. */ public boolean fillEncryptionData(NonBlockingInputStream source) { if (source.getAvailableByteCount() < sampleEncryptionDataLength) { return false; } source.read(sampleEncryptionData.data, 0, sampleEncryptionDataLength); sampleEncryptionData.setPosition(0); sampleEncryptionDataNeedsFill = false; return true; } public int getSamplePresentationTime(int index) { return sampleDecodingTimeTable[index] + sampleCompositionTimeOffsetTable[index]; } }