@SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); if (bytesLoaded == 0) { extractorWrapper.init(null); } // Load and decode the initialization data. try { Extractor extractor = extractorWrapper.extractor; int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { result = extractor.read(input, null); } Assertions.checkState(result != Extractor.RESULT_SEEK); } finally { bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { Util.closeQuietly(dataSource); } }
public MediaPeriodHolder(Renderer[] renderers, RendererCapabilities[] rendererCapabilities, long rendererPositionOffsetUs, TrackSelector trackSelector, LoadControl loadControl, MediaSource mediaSource, Object periodUid, int periodIndex, boolean isLastPeriod, long startPositionUs) { this.renderers = renderers; this.rendererCapabilities = rendererCapabilities; this.rendererPositionOffsetUs = rendererPositionOffsetUs; this.trackSelector = trackSelector; this.loadControl = loadControl; this.mediaSource = mediaSource; this.uid = Assertions.checkNotNull(periodUid); this.index = periodIndex; this.isLast = isLastPeriod; this.startPositionUs = startPositionUs; sampleStreams = new SampleStream[renderers.length]; mayRetainStreamFlags = new boolean[renderers.length]; mediaPeriod = mediaSource.createPeriod(periodIndex, loadControl.getAllocator(), startPositionUs); }
/** * Constructs an instance with some {@link Allocation}s created up front. * <p> * Note: {@link Allocation}s created up front will never be discarded by {@link #trim()}. * * @param trimOnReset Whether memory is freed when the allocator is reset. Should be true unless * the allocator will be re-used by multiple player instances. * @param individualAllocationSize The length of each individual {@link Allocation}. * @param initialAllocationCount The number of allocations to create up front. */ public DefaultAllocator(boolean trimOnReset, int individualAllocationSize, int initialAllocationCount) { Assertions.checkArgument(individualAllocationSize > 0); Assertions.checkArgument(initialAllocationCount >= 0); this.trimOnReset = trimOnReset; this.individualAllocationSize = individualAllocationSize; this.availableCount = initialAllocationCount; this.availableAllocations = new Allocation[initialAllocationCount + AVAILABLE_EXTRA_CAPACITY]; if (initialAllocationCount > 0) { initialAllocationBlock = new byte[initialAllocationCount * individualAllocationSize]; for (int i = 0; i < initialAllocationCount; i++) { int allocationOffset = i * individualAllocationSize; availableAllocations[i] = new Allocation(initialAllocationBlock, allocationOffset); } } else { initialAllocationBlock = null; } singleAllocationReleaseHolder = new Allocation[1]; }
@Override public synchronized void release(Allocation[] allocations) { if (availableCount + allocations.length >= availableAllocations.length) { availableAllocations = Arrays.copyOf(availableAllocations, Math.max(availableAllocations.length * 2, availableCount + allocations.length)); } for (Allocation allocation : allocations) { // Weak sanity check that the allocation probably originated from this pool. Assertions.checkArgument(allocation.data == initialAllocationBlock || allocation.data.length == individualAllocationSize); availableAllocations[availableCount++] = allocation; } allocatedCount -= allocations.length; // Wake up threads waiting for the allocated size to drop. notifyAll(); }
public ConcatenatedTimeline(Timeline[] timelines) { int[] sourcePeriodOffsets = new int[timelines.length]; int[] sourceWindowOffsets = new int[timelines.length]; long periodCount = 0; int windowCount = 0; for (int i = 0; i < timelines.length; i++) { Timeline timeline = timelines[i]; periodCount += timeline.getPeriodCount(); Assertions.checkState(periodCount <= Integer.MAX_VALUE, "ConcatenatingMediaSource children contain too many periods"); sourcePeriodOffsets[i] = (int) periodCount; windowCount += timeline.getWindowCount(); sourceWindowOffsets[i] = windowCount; } this.timelines = timelines; this.sourcePeriodOffsets = sourcePeriodOffsets; this.sourceWindowOffsets = sourceWindowOffsets; }
@Override public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) { if (streamState == STREAM_STATE_END_OF_STREAM) { buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM); return C.RESULT_BUFFER_READ; } else if (requireFormat || streamState == STREAM_STATE_SEND_FORMAT) { formatHolder.format = format; streamState = STREAM_STATE_SEND_SAMPLE; return C.RESULT_FORMAT_READ; } Assertions.checkState(streamState == STREAM_STATE_SEND_SAMPLE); if (!loadingFinished) { return C.RESULT_NOTHING_READ; } else { buffer.timeUs = 0; buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME); buffer.ensureSpaceForWrite(sampleSize); buffer.data.put(sampleData, 0, sampleSize); streamState = STREAM_STATE_END_OF_STREAM; return C.RESULT_BUFFER_READ; } }
/** * Returns the remaining license and playback durations in seconds, for an offline license. * * @param offlineLicenseKeySetId The key set id of the license. * @return The remaining license and playback durations, in seconds. * @throws DrmSessionException Thrown when a DRM session error occurs. */ public synchronized Pair<Long, Long> getLicenseDurationRemainingSec(byte[] offlineLicenseKeySetId) throws DrmSessionException { Assertions.checkNotNull(offlineLicenseKeySetId); DrmSession<T> drmSession = openBlockingKeyRequest(DefaultDrmSessionManager.MODE_QUERY, offlineLicenseKeySetId, null); DrmSessionException error = drmSession.getError(); Pair<Long, Long> licenseDurationRemainingSec = WidevineUtil.getLicenseDurationRemainingSec(drmSession); drmSessionManager.releaseSession(drmSession); if (error != null) { if (error.getCause() instanceof KeysExpiredException) { return Pair.create(0L, 0L); } throw error; } return licenseDurationRemainingSec; }
/** * Parses encryption data from an audio/video sample entry, populating {@code out} and returning * the unencrypted atom type, or 0 if no common encryption sinf atom was present. */ private static int parseSampleEntryEncryptionData(ParsableByteArray parent, int position, int size, StsdData out, int entryIndex) { int childPosition = parent.getPosition(); while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_sinf) { Pair<Integer, TrackEncryptionBox> result = parseSinfFromParent(parent, childPosition, childAtomSize); if (result != null) { out.trackEncryptionBoxes[entryIndex] = result.second; return result.first; } } childPosition += childAtomSize; } // This enca/encv box does not have a data format so return an invalid atom type. return 0; }
@Override public synchronized void onTransferEnd(Object source) { Assertions.checkState(streamCount > 0); long nowMs = SystemClock.elapsedRealtime(); int sampleElapsedTimeMs = (int) (nowMs - sampleStartTimeMs); totalElapsedTimeMs += sampleElapsedTimeMs; totalBytesTransferred += sampleBytesTransferred; if (sampleElapsedTimeMs > 0) { float bitsPerSecond = (sampleBytesTransferred * 8000) / sampleElapsedTimeMs; slidingPercentile.addSample((int) Math.sqrt(sampleBytesTransferred), bitsPerSecond); if (totalElapsedTimeMs >= ELAPSED_MILLIS_FOR_ESTIMATE || totalBytesTransferred >= BYTES_TRANSFERRED_FOR_ESTIMATE) { float bitrateEstimateFloat = slidingPercentile.getPercentile(0.5f); bitrateEstimate = Float.isNaN(bitrateEstimateFloat) ? NO_ESTIMATE : (long) bitrateEstimateFloat; } } notifyBandwidthSample(sampleElapsedTimeMs, sampleBytesTransferred, bitrateEstimate); if (--streamCount > 0) { sampleStartTimeMs = nowMs; } sampleBytesTransferred = 0; }
@Override public void onTimelineChanged(Timeline timeline, Object manifest) { if (timeline.isEmpty()) { // The player is being re-prepared and this source will be released. return; } Assertions.checkArgument(timeline.getPeriodCount() == 1); this.timeline = timeline; long contentDurationUs = timeline.getPeriod(0, period).durationUs; contentDurationMs = C.usToMs(contentDurationUs); if (contentDurationUs != C.TIME_UNSET) { adPlaybackState.contentDurationUs = contentDurationUs; } updateImaStateForPlayerState(); }
private void stopAdInternal() { Assertions.checkState(imaAdState != IMA_AD_STATE_NONE); imaAdState = IMA_AD_STATE_NONE; adPlaybackState.playedAd(adGroupIndex); updateAdPlaybackState(); if (!playingAd) { adGroupIndex = C.INDEX_UNSET; } }
@Override public void onPrepared(MediaPeriod mediaPeriod) { Assertions.checkState(startUs != C.TIME_UNSET && endUs != C.TIME_UNSET); // If the clipping start position is non-zero, the clipping sample streams will adjust // timestamps on buffers they read from the unclipped sample streams. These adjusted buffer // timestamps can be negative, because sample streams provide buffers starting at a key-frame, // which may be before the clipping start point. When the renderer reads a buffer with a // negative timestamp, its offset timestamp can jump backwards compared to the last timestamp // read in the previous period. Renderer implementations may not allow this, so we signal a // discontinuity which resets the renderers before they read the clipping sample stream. pendingInitialDiscontinuity = startUs != 0; callback.onPrepared(this); }
@Override public void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, @Nullable boolean[] playedAdGroups, int adGroupCount) { Assertions.checkArgument(adGroupCount == 0 || (adGroupTimesMs != null && playedAdGroups != null)); this.adGroupCount = adGroupCount; this.adGroupTimesMs = adGroupTimesMs; this.playedAdGroups = playedAdGroups; update(); }
/** * Constructs an instance. Must be called from a thread that has an associated {@link Looper}. * * @param renderers The {@link Renderer}s that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance. */ @SuppressLint("HandlerLeak") public ExoPlayerImpl(Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl) { Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION_SLASHY + " [" + Util.DEVICE_DEBUG_INFO + "]"); Assertions.checkState(renderers.length > 0); this.renderers = Assertions.checkNotNull(renderers); this.trackSelector = Assertions.checkNotNull(trackSelector); this.playWhenReady = false; this.playbackState = STATE_IDLE; this.listeners = new CopyOnWriteArraySet<>(); emptyTrackSelections = new TrackSelectionArray(new TrackSelection[renderers.length]); timeline = Timeline.EMPTY; window = new Timeline.Window(); period = new Timeline.Period(); trackGroups = TrackGroupArray.EMPTY; trackSelections = emptyTrackSelections; playbackParameters = PlaybackParameters.DEFAULT; Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper(); eventHandler = new Handler(eventLooper) { @Override public void handleMessage(Message msg) { ExoPlayerImpl.this.handleEvent(msg); } }; playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(0, 0); internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, loadControl, playWhenReady, eventHandler, playbackInfo, this); }
/** * Sets whether artwork is displayed if present in the media. * * @param useArtwork Whether artwork is displayed. */ public void setUseArtwork(boolean useArtwork) { Assertions.checkState(!useArtwork || artworkView != null); if (this.useArtwork != useArtwork) { this.useArtwork = useArtwork; updateForCurrentTrackSelections(); } }
/** * Sets whether the playback controls can be shown. If set to {@code false} the playback controls * are never visible and are disconnected from the player. * * @param useController Whether the playback controls can be shown. */ public void setUseController(boolean useController) { Assertions.checkState(!useController || controller != null); if (this.useController == useController) { return; } this.useController = useController; if (useController) { controller.setPlayer(player); } else if (controller != null) { controller.hide(); controller.setPlayer(null); } }
/** * Removes {@link CachedContent} with the given key from index. It shouldn't contain any spans. * * @throws IllegalStateException If {@link CachedContent} isn't empty. */ public void removeEmpty(String key) { CachedContent cachedContent = keyToContent.remove(key); if (cachedContent != null) { Assertions.checkState(cachedContent.isEmpty()); idToKey.remove(cachedContent.id); changed = true; } }
@Override public synchronized File startFile(String key, long position, long maxLength) throws CacheException { Assertions.checkState(lockedSpans.containsKey(key)); if (!cacheDir.exists()) { // For some reason the cache directory doesn't exist. Make a best effort to create it. removeStaleSpansAndCachedContents(); cacheDir.mkdirs(); } evictor.onStartFile(this, key, position, maxLength); return SimpleCacheSpan.getCacheFile(cacheDir, index.assignIdForKey(key), position, System.currentTimeMillis()); }
@Override public long open(DataSpec dataSpec) throws IOException { Assertions.checkState(dataSource == null); // Choose the correct source for the scheme. //选择正确的数据源方案 String scheme = dataSpec.uri.getScheme(); //如果URI是一个本地文件路径或本地文件的引用。 Timber.e("解密:000000," + scheme + ",path:" + dataSpec.uri.getPath()); if (Util.isLocalFileUri(dataSpec.uri)) { //如果路径尾包含aitrip的文件名,使用解密类 if (dataSpec.uri.getPath().endsWith(".aitrip")) { Aes128DataSource aes128DataSource = new Aes128DataSource(getFileDataSource(), Aikey.getBytes(), Aikey.getBytes()); dataSource = aes128DataSource; } else {//否则,正常解析mp3 if (dataSpec.uri.getPath().startsWith("/android_asset/")) { dataSource = getAssetDataSource(); } else { dataSource = getFileDataSource(); } } } else if (SCHEME_ASSET.equals(scheme)) { dataSource = getAssetDataSource(); } else if (SCHEME_CONTENT.equals(scheme)) { dataSource = getContentDataSource(); } else if (SCHEME_RTMP.equals(scheme)) { dataSource = getRtmpDataSource(); } else { dataSource = baseDataSource; } // Open the source and return. return dataSource.open(dataSpec); }
@Override public int read(byte[] buffer, int offset, int readLength) throws IOException { Assertions.checkState(cipherInputStream != null); int bytesRead = cipherInputStream.read(buffer, offset, readLength); if (bytesRead < 0) { return C.RESULT_END_OF_INPUT; } return bytesRead; }
public long updatePeriodTrackSelection(long positionUs, boolean forceRecreateStreams, boolean[] streamResetFlags) { TrackSelectionArray trackSelections = trackSelectorResult.selections; for (int i = 0; i < trackSelections.length; i++) { mayRetainStreamFlags[i] = !forceRecreateStreams && trackSelectorResult.isEquivalent(periodTrackSelectorResult, i); } // Disable streams on the period and get new streams for updated/newly-enabled tracks. positionUs = mediaPeriod.selectTracks(trackSelections.getAll(), mayRetainStreamFlags, sampleStreams, streamResetFlags, positionUs); periodTrackSelectorResult = trackSelectorResult; // Update whether we have enabled tracks and sanity check the expected streams are non-null. hasEnabledTracks = false; for (int i = 0; i < sampleStreams.length; i++) { if (sampleStreams[i] != null) { Assertions.checkState(trackSelections.get(i) != null); hasEnabledTracks = true; } else { Assertions.checkState(trackSelections.get(i) == null); } } // The track selection has changed. loadControl.onTracksSelected(renderers, trackSelectorResult.groups, trackSelections); return positionUs; }
@SuppressWarnings("ConstantConditions") protected void parseIntent() { String errorNoMediaMessage = getResources().getString(R.string.activity_tubi_player_no_media_error_message); Assertions.checkState(getIntent() != null && getIntent().getExtras() != null, errorNoMediaMessage); mediaModel = (MediaModel) getIntent().getExtras().getSerializable(TUBI_MEDIA_KEY); Assertions.checkState(mediaModel != null, errorNoMediaMessage); }
@Override public long open(DataSpec dataSpec) throws IOException { Assertions.checkState(!opened); // DataSpec requires a matching close call even if open fails. opened = true; uri = dataSpec.uri; openedDataSpecs.add(dataSpec); // If the source knows that the request is unsatisfiable then fail. if (dataSpec.position >= totalLength || (dataSpec.length != C.LENGTH_UNSET && (dataSpec.position + dataSpec.length > totalLength))) { throw new DataSourceException(DataSourceException.POSITION_OUT_OF_RANGE); } // Scan through the segments, configuring them for the current read. boolean findingCurrentSegmentIndex = true; currentSegmentIndex = 0; int scannedLength = 0; for (Segment segment : segments) { segment.bytesRead = (int) Math.min(Math.max(0, dataSpec.position - scannedLength), segment.length); scannedLength += segment.length; findingCurrentSegmentIndex &= segment.isErrorSegment() ? segment.exceptionCleared : segment.bytesRead == segment.length; if (findingCurrentSegmentIndex) { currentSegmentIndex++; } } // Configure bytesRemaining, and return. if (dataSpec.length == C.LENGTH_UNSET) { bytesRemaining = totalLength - dataSpec.position; return simulateUnknownLength ? C.LENGTH_UNSET : bytesRemaining; } else { bytesRemaining = dataSpec.length; return bytesRemaining; } }
@Override public int read(byte[] buffer, int offset, int readLength) throws IOException { Assertions.checkState(opened); while (true) { if (currentSegmentIndex == segments.size() || bytesRemaining == 0) { return C.RESULT_END_OF_INPUT; } Segment current = segments.get(currentSegmentIndex); if (current.isErrorSegment()) { if (!current.exceptionCleared) { current.exceptionThrown = true; throw (IOException) current.exception.fillInStackTrace(); } else { currentSegmentIndex++; } } else { // Read at most bytesRemaining. readLength = (int) Math.min(readLength, bytesRemaining); // Do not allow crossing of the segment boundary. readLength = Math.min(readLength, current.length - current.bytesRead); // Perform the read and return. System.arraycopy(current.data, current.bytesRead, buffer, offset, readLength); bytesRemaining -= readLength; current.bytesRead += readLength; if (current.bytesRead == current.length) { currentSegmentIndex++; } return readLength; } } }
/** * Converts an array of integers in the range [0, 255] into an equivalent byte array. * * @param intArray An array of integers, all of which must be in the range [0, 255]. * @return The equivalent byte array. */ public static byte[] createByteArray(int... intArray) { byte[] byteArray = new byte[intArray.length]; for (int i = 0; i < byteArray.length; i++) { Assertions.checkState(0x00 <= intArray[i] && intArray[i] <= 0xFF); byteArray[i] = (byte) intArray[i]; } return byteArray; }
/** * @param output The output. * @param outputLooper The looper associated with the thread on which the output should be called. * If the output makes use of standard Android UI components, then this should normally be the * looper associated with the application's main thread, which can be obtained using * {@link android.app.Activity#getMainLooper()}. Null may be passed if the output should be * called directly on the player's internal rendering thread. * @param decoderFactory A factory from which to obtain {@link MetadataDecoder} instances. */ public MetadataRenderer(Output output, Looper outputLooper, MetadataDecoderFactory decoderFactory) { super(C.TRACK_TYPE_METADATA); this.output = Assertions.checkNotNull(output); this.outputHandler = outputLooper == null ? null : new Handler(outputLooper, this); this.decoderFactory = Assertions.checkNotNull(decoderFactory); formatHolder = new FormatHolder(); buffer = new MetadataInputBuffer(); pendingMetadata = new Metadata[MAX_PENDING_METADATA_COUNT]; pendingMetadataTimestamps = new long[MAX_PENDING_METADATA_COUNT]; }
/** * Selects the embedded track, returning a new {@link EmbeddedSampleStream} from which the track's * samples can be consumed. {@link EmbeddedSampleStream#release()} must be called on the returned * stream when the track is no longer required, and before calling this method again to obtain * another stream for the same track. * * @param positionUs The current playback position in microseconds. * @param trackType The type of the embedded track to enable. * @return The {@link EmbeddedSampleStream} for the embedded track. */ public EmbeddedSampleStream selectEmbeddedTrack(long positionUs, int trackType) { for (int i = 0; i < embeddedSampleQueues.length; i++) { if (embeddedTrackTypes[i] == trackType) { Assertions.checkState(!embeddedTracksSelected[i]); embeddedTracksSelected[i] = true; embeddedSampleQueues[i].skipToKeyframeBefore(positionUs, true); return new EmbeddedSampleStream(this, embeddedSampleQueues[i], i); } } // Should never happen. throw new IllegalStateException(); }
/** * Clears a header for key requests made by the callback. * * @param name The name of the header field. */ public void clearKeyRequestProperty(String name) { Assertions.checkNotNull(name); synchronized (keyRequestProperties) { keyRequestProperties.remove(name); } }
/** * @param name The name of the decoder. * @param capabilities The capabilities of the decoder. */ private MediaCodecInfo(String name, String mimeType, CodecCapabilities capabilities) { this.name = Assertions.checkNotNull(name); this.mimeType = mimeType; this.capabilities = capabilities; adaptive = capabilities != null && isAdaptive(capabilities); tunneling = capabilities != null && isTunneling(capabilities); }
/** * Atomically sets the provided parameters for track selection. * * @param params The parameters for track selection. */ public void setParameters(Parameters params) { Assertions.checkNotNull(params); if (!paramsReference.getAndSet(params).equals(params)) { invalidate(); } }
/** * Called to indicate that a NAL unit has started. * * @param type The type of the NAL unit. */ public void startNalUnit(int type) { Assertions.checkState(!isFilling); isFilling = type == targetType; if (isFilling) { // Skip the three byte start code when writing data. nalLength = 3; isCompleted = false; } }
/** * Skips to the data in the given WAV input stream and returns its data size. After calling, the * input stream's position will point to the start of sample data in the WAV. * <p> * If an exception is thrown, the input position will be left pointing to a chunk header. * * @param input Input stream to skip to the data chunk in. Its peek position must be pointing to * a valid chunk header. * @param wavHeader WAV header to populate with data bounds. * @throws ParserException If an error occurs parsing chunks. * @throws IOException If reading from the input fails. * @throws InterruptedException If interrupted while reading from input. */ public static void skipToData(ExtractorInput input, WavHeader wavHeader) throws IOException, InterruptedException { Assertions.checkNotNull(input); Assertions.checkNotNull(wavHeader); // Make sure the peek position is set to the read position before we peek the first header. input.resetPeekPosition(); ParsableByteArray scratch = new ParsableByteArray(ChunkHeader.SIZE_IN_BYTES); // Skip all chunks until we hit the data header. ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); while (chunkHeader.id != Util.getIntegerCodeForString("data")) { Log.w(TAG, "Ignoring unknown WAV chunk: " + chunkHeader.id); long bytesToSkip = ChunkHeader.SIZE_IN_BYTES + chunkHeader.size; // Override size of RIFF chunk, since it describes its size as the entire file. if (chunkHeader.id == Util.getIntegerCodeForString("RIFF")) { bytesToSkip = ChunkHeader.SIZE_IN_BYTES + 4; } if (bytesToSkip > Integer.MAX_VALUE) { throw new ParserException("Chunk is too large (~2GB+) to skip; id: " + chunkHeader.id); } input.skipFully((int) bytesToSkip); chunkHeader = ChunkHeader.peek(input, scratch); } // Skip past the "data" header. input.skipFully(ChunkHeader.SIZE_IN_BYTES); wavHeader.setDataBounds(input.getPosition(), chunkHeader.size); }
/** * Skips {@code numberOfBits} bits. * * @param numberOfBits The number of bits to skip. */ public void skipBits(int numberOfBits) { Assertions.checkState(getPosition() + numberOfBits <= limit); byteOffset += numberOfBits / 8; bitOffset += numberOfBits % 8; if (bitOffset > 7) { byteOffset++; bitOffset -= 8; } }
@Override public final I dequeueInputBuffer() throws E { synchronized (lock) { maybeThrowException(); Assertions.checkState(dequeuedInputBuffer == null); dequeuedInputBuffer = availableInputBufferCount == 0 ? null : availableInputBuffers[--availableInputBufferCount]; return dequeuedInputBuffer; } }
@Override public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { Assertions.checkArgument(index == 0); return new ExtractorMediaPeriod(uri, dataSourceFactory.createDataSource(), extractorsFactory.createExtractors(), minLoadableRetryCount, eventHandler, eventListener, this, allocator, customCacheKey); }
public TrackSampleTable(long[] offsets, int[] sizes, int maximumSize, long[] timestampsUs, int[] flags) { Assertions.checkArgument(sizes.length == timestampsUs.length); Assertions.checkArgument(offsets.length == timestampsUs.length); Assertions.checkArgument(flags.length == timestampsUs.length); this.offsets = offsets; this.sizes = sizes; this.maximumSize = maximumSize; this.timestampsUs = timestampsUs; this.flags = flags; sampleCount = offsets.length; }
private static Pair<Integer, TrackEncryptionBox> parseSinfFromParent(ParsableByteArray parent, int position, int size) { int childPosition = position + Atom.HEADER_SIZE; boolean isCencScheme = false; TrackEncryptionBox trackEncryptionBox = null; Integer dataFormat = null; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_frma) { dataFormat = parent.readInt(); } else if (childAtomType == Atom.TYPE_schm) { parent.skipBytes(4); isCencScheme = parent.readInt() == TYPE_cenc; } else if (childAtomType == Atom.TYPE_schi) { trackEncryptionBox = parseSchiFromParent(parent, childPosition, childAtomSize); } childPosition += childAtomSize; } if (isCencScheme) { Assertions.checkArgument(dataFormat != null, "frma atom is mandatory"); Assertions.checkArgument(trackEncryptionBox != null, "schi->tenc atom is mandatory"); return Pair.create(dataFormat, trackEncryptionBox); } else { return null; } }
public ChunkIterator(ParsableByteArray stsc, ParsableByteArray chunkOffsets, boolean chunkOffsetsAreLongs) { this.stsc = stsc; this.chunkOffsets = chunkOffsets; this.chunkOffsetsAreLongs = chunkOffsetsAreLongs; chunkOffsets.setPosition(Atom.FULL_HEADER_SIZE); length = chunkOffsets.readUnsignedIntToInt(); stsc.setPosition(Atom.FULL_HEADER_SIZE); remainingSamplesPerChunkChanges = stsc.readUnsignedIntToInt(); Assertions.checkState(stsc.readInt() == 1, "first_chunk must be 1"); index = C.INDEX_UNSET; }