From 365812e820603b2229064724ad751b80e59ba371 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 14 Jun 2016 10:00:31 -0700 Subject: [PATCH] Remove FrameworkSampleSource. ExtractorSampleSource covers almost all use cases (except for AMR, AVI and legacy Widevine). The FLAC extension must be compiled for support for FLAC extraction. FrameworkSampleSource has device-specific issues, makes blocking calls to the underlying MediaExtractor, and does not provide much control over buffering. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=124850102 --- .../google/android/exoplayer/CryptoInfo.java | 17 - .../com/google/android/exoplayer/Format.java | 12 - .../exoplayer/FrameworkSampleSource.java | 386 ------------------ 3 files changed, 415 deletions(-) delete mode 100644 library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java diff --git a/library/src/main/java/com/google/android/exoplayer/CryptoInfo.java b/library/src/main/java/com/google/android/exoplayer/CryptoInfo.java index 4be481259c..6f484a9eb7 100644 --- a/library/src/main/java/com/google/android/exoplayer/CryptoInfo.java +++ b/library/src/main/java/com/google/android/exoplayer/CryptoInfo.java @@ -18,7 +18,6 @@ package com.google.android.exoplayer; import com.google.android.exoplayer.util.Util; import android.annotation.TargetApi; -import android.media.MediaExtractor; /** * Compatibility wrapper around {@link android.media.MediaCodec.CryptoInfo}. @@ -72,22 +71,6 @@ public final class CryptoInfo { } } - /** - * Equivalent to {@link MediaExtractor#getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo)}. - * - * @param extractor The extractor from which to retrieve the crypto information. - */ - @TargetApi(16) - public void setFromExtractorV16(MediaExtractor extractor) { - extractor.getSampleCryptoInfo(frameworkCryptoInfo); - numSubSamples = frameworkCryptoInfo.numSubSamples; - numBytesOfClearData = frameworkCryptoInfo.numBytesOfClearData; - numBytesOfEncryptedData = frameworkCryptoInfo.numBytesOfEncryptedData; - key = frameworkCryptoInfo.key; - iv = frameworkCryptoInfo.iv; - mode = frameworkCryptoInfo.mode; - } - /** * Returns an equivalent {@link android.media.MediaCodec.CryptoInfo} instance. *

diff --git a/library/src/main/java/com/google/android/exoplayer/Format.java b/library/src/main/java/com/google/android/exoplayer/Format.java index 6b1d9cc62f..f4ec857c25 100644 --- a/library/src/main/java/com/google/android/exoplayer/Format.java +++ b/library/src/main/java/com/google/android/exoplayer/Format.java @@ -442,18 +442,6 @@ public final class Format implements Parcelable { return frameworkMediaFormat; } - /** - * Sets the {@link MediaFormat} returned by {@link #getFrameworkMediaFormatV16()}. - * - * @deprecated This method only exists for FrameworkSampleSource, which is itself deprecated. - * @param frameworkSampleFormat The format. - */ - @Deprecated - @TargetApi(16) - /* package */ final void setFrameworkMediaFormatV16(MediaFormat frameworkSampleFormat) { - this.frameworkMediaFormat = frameworkSampleFormat; - } - @Override public String toString() { return "Format(" + id + ", " + containerMimeType + ", " + sampleMimeType + ", " + bitrate + ", " diff --git a/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java b/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java deleted file mode 100644 index 744b669ccb..0000000000 --- a/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * 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; - -import com.google.android.exoplayer.drm.DrmInitData; -import com.google.android.exoplayer.drm.DrmInitData.SchemeData; -import com.google.android.exoplayer.extractor.ExtractorSampleSource; -import com.google.android.exoplayer.extractor.mp4.PsshAtomUtil; -import com.google.android.exoplayer.util.Assertions; -import com.google.android.exoplayer.util.MimeTypes; -import com.google.android.exoplayer.util.Util; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.Context; -import android.media.MediaExtractor; -import android.media.MediaFormat; -import android.net.Uri; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -/** - * Extracts samples from a stream using Android's {@link MediaExtractor}. - *

- * Warning - This class is marked as deprecated because there are known device specific issues - * associated with its use, including playbacks not starting, playbacks stuttering and other - * miscellaneous failures. For mp4, m4a, mp3, webm, mkv, mpeg-ts, ogg, wav and aac playbacks it is - * strongly recommended to use {@link ExtractorSampleSource} instead. Where this is not possible - * this class can still be used, but please be aware of the associated risks. Playing container - * formats for which an ExoPlayer extractor does not yet exist (e.g. avi) is a valid use case of - * this class. - *

- * Over time we hope to enhance {@link ExtractorSampleSource} to support more formats, and hence - * make use of this class unnecessary. - */ -// TODO: This implementation needs to be fixed so that its methods are non-blocking (either -// through use of a background thread, or through changes to the framework's MediaExtractor API). -@Deprecated -@TargetApi(16) -public final class FrameworkSampleSource implements SampleSource { - - private static final int TRACK_STATE_DISABLED = 0; - private static final int TRACK_STATE_ENABLED = 1; - private static final int TRACK_STATE_FORMAT_SENT = 2; - - // Parameters for a Uri data source. - private final Context context; - private final Uri uri; - private final Map headers; - - // Parameters for a FileDescriptor data source. - private final FileDescriptor fileDescriptor; - private final long fileDescriptorOffset; - private final long fileDescriptorLength; - - private boolean prepared; - private boolean notifyReset; - private long durationUs; - private MediaExtractor extractor; - private TrackGroupArray tracks; - private int[] trackStates; - - private int enabledTrackCount; - private long lastSeekPositionUs; - private long pendingSeekPositionUs; - - /** - * Instantiates a new sample extractor reading from the specified {@code uri}. - * - * @param context Context for resolving {@code uri}. - * @param uri The content URI from which to extract data. - * @param headers Headers to send with requests for data. - */ - public FrameworkSampleSource(Context context, Uri uri, Map headers) { - Assertions.checkState(Util.SDK_INT >= 16); - this.context = Assertions.checkNotNull(context); - this.uri = Assertions.checkNotNull(uri); - this.headers = headers; - fileDescriptor = null; - fileDescriptorOffset = 0; - fileDescriptorLength = 0; - durationUs = C.UNSET_TIME_US; - } - - /** - * Instantiates a new sample extractor reading from the specified seekable {@code fileDescriptor}. - * The caller is responsible for releasing the file descriptor. - * - * @param fileDescriptor File descriptor from which to read. - * @param fileDescriptorOffset The offset in bytes where the data to be extracted starts. - * @param fileDescriptorLength The length in bytes of the data to be extracted. - */ - public FrameworkSampleSource(FileDescriptor fileDescriptor, long fileDescriptorOffset, - long fileDescriptorLength) { - Assertions.checkState(Util.SDK_INT >= 16); - this.fileDescriptor = Assertions.checkNotNull(fileDescriptor); - this.fileDescriptorOffset = fileDescriptorOffset; - this.fileDescriptorLength = fileDescriptorLength; - context = null; - uri = null; - headers = null; - durationUs = C.UNSET_TIME_US; - } - - // SampleSource implementation. - - @Override - public boolean prepare(long positionUs) throws IOException { - if (prepared) { - return true; - } - extractor = new MediaExtractor(); - if (context != null) { - extractor.setDataSource(context, uri, headers); - } else { - extractor.setDataSource(fileDescriptor, fileDescriptorOffset, fileDescriptorLength); - } - trackStates = new int[extractor.getTrackCount()]; - TrackGroup[] trackArray = new TrackGroup[trackStates.length]; - DrmInitData drmInitData = Util.SDK_INT >= 18 ? getDrmInitDataV18() : null; - for (int i = 0; i < trackStates.length; i++) { - MediaFormat format = extractor.getTrackFormat(i); - if (format.containsKey(MediaFormat.KEY_DURATION)) { - durationUs = Math.max(durationUs, format.getLong(MediaFormat.KEY_DURATION)); - } - trackArray[i] = new TrackGroup(createFormat(i, format, drmInitData)); - } - tracks = new TrackGroupArray(trackArray); - prepared = true; - return true; - } - - @Override - public long getDurationUs() { - return durationUs; - } - - @Override - public TrackGroupArray getTrackGroups() { - return tracks; - } - - @Override - public TrackStream[] selectTracks(List oldStreams, - List newSelections, long positionUs) { - Assertions.checkState(prepared); - // Unselect old tracks. - for (int i = 0; i < oldStreams.size(); i++) { - int track = ((TrackStreamImpl) oldStreams.get(i)).track; - Assertions.checkState(trackStates[track] != TRACK_STATE_DISABLED); - enabledTrackCount--; - trackStates[track] = TRACK_STATE_DISABLED; - extractor.unselectTrack(track); - } - // Select new tracks. - TrackStream[] newStreams = new TrackStream[newSelections.size()]; - for (int i = 0; i < newStreams.length; i++) { - TrackSelection selection = newSelections.get(i); - Assertions.checkState(selection.length == 1); - Assertions.checkState(selection.getTrack(0) == 0); - int track = selection.group; - Assertions.checkState(trackStates[track] == TRACK_STATE_DISABLED); - enabledTrackCount++; - trackStates[track] = TRACK_STATE_ENABLED; - extractor.selectTrack(track); - newStreams[i] = new TrackStreamImpl(track); - } - // Seek if necessary. - if (enabledTrackCount > 0) { - seekToUsInternal(positionUs, positionUs != 0); - } - return newStreams; - } - - @Override - public void continueBuffering(long positionUs) { - // MediaExtractor takes care of buffering. Do nothing. - } - - @Override - public long readReset() { - if (notifyReset) { - notifyReset = false; - return lastSeekPositionUs; - } - return C.UNSET_TIME_US; - } - - @Override - public void seekToUs(long positionUs) { - if (enabledTrackCount == 0) { - return; - } - seekToUsInternal(positionUs, false); - } - - @Override - public long getBufferedPositionUs() { - if (enabledTrackCount == 0) { - return C.END_OF_SOURCE_US; - } - - long bufferedDurationUs = extractor.getCachedDuration(); - if (bufferedDurationUs == -1) { - return C.UNSET_TIME_US; - } - - long sampleTime = extractor.getSampleTime(); - return sampleTime == -1 ? C.END_OF_SOURCE_US : sampleTime + bufferedDurationUs; - } - - @Override - public void release() { - if (extractor != null) { - extractor.release(); - extractor = null; - } - } - - // TrackStream methods. - - /* package */ int readData(int track, FormatHolder formatHolder, DecoderInputBuffer buffer) { - Assertions.checkState(trackStates[track] != TRACK_STATE_DISABLED); - if (notifyReset) { - return TrackStream.NOTHING_READ; - } - if (trackStates[track] != TRACK_STATE_FORMAT_SENT) { - formatHolder.format = tracks.get(track).getFormat(0); - trackStates[track] = TRACK_STATE_FORMAT_SENT; - return TrackStream.FORMAT_READ; - } - int extractorTrackIndex = extractor.getSampleTrackIndex(); - if (extractorTrackIndex == track) { - ByteBuffer bufferData = buffer.data; - int offset = bufferData.position(); - int size = extractor.readSampleData(bufferData, offset); - bufferData.position(offset + size); - buffer.timeUs = extractor.getSampleTime(); - int flags = extractor.getSampleFlags(); - if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) { - buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME); - } - if ((flags & MediaExtractor.SAMPLE_FLAG_ENCRYPTED) != 0) { - buffer.addFlag(C.BUFFER_FLAG_ENCRYPTED); - buffer.cryptoInfo.setFromExtractorV16(extractor); - } - pendingSeekPositionUs = C.UNSET_TIME_US; - extractor.advance(); - return TrackStream.BUFFER_READ; - } else if (extractorTrackIndex < 0) { - buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM); - return TrackStream.BUFFER_READ; - } else { - return TrackStream.NOTHING_READ; - } - } - - // Internal methods. - - @TargetApi(18) - private DrmInitData getDrmInitDataV18() { - // MediaExtractor only supports psshInfo for MP4, so it's ok to hard code the mimeType here. - Map psshInfo = extractor.getPsshInfo(); - if (psshInfo == null || psshInfo.isEmpty()) { - return null; - } - SchemeData[] schemeDatas = new SchemeData[psshInfo.size()]; - int count = 0; - for (UUID uuid : psshInfo.keySet()) { - byte[] psshAtom = PsshAtomUtil.buildPsshAtom(uuid, psshInfo.get(uuid)); - schemeDatas[count++] = new SchemeData(uuid, MimeTypes.VIDEO_MP4, psshAtom); - } - return new DrmInitData(schemeDatas); - } - - private void seekToUsInternal(long positionUs, boolean force) { - // Unless forced, avoid duplicate calls to the underlying extractor's seek method in the case - // that there have been no interleaving calls to readSample. - if (force || pendingSeekPositionUs != positionUs) { - lastSeekPositionUs = positionUs; - pendingSeekPositionUs = positionUs; - extractor.seekTo(positionUs, MediaExtractor.SEEK_TO_PREVIOUS_SYNC); - notifyReset = true; - } - } - - @SuppressLint("InlinedApi") - private static Format createFormat(int index, MediaFormat mediaFormat, DrmInitData drmInitData) { - String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME); - String language = getOptionalStringV16(mediaFormat, MediaFormat.KEY_LANGUAGE); - int maxInputSize = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE); - int width = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_WIDTH); - int height = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_HEIGHT); - float frameRate; - try { - frameRate = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_FRAME_RATE); - } catch (ClassCastException e) { - // There's an entry for KEY_FRAME_RATE but it's not a integer. It must be a float. - frameRate = getOptionalFloatV16(mediaFormat, MediaFormat.KEY_FRAME_RATE); - } - int rotationDegrees = getOptionalIntegerV16(mediaFormat, "rotation-degrees"); - int channelCount = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_CHANNEL_COUNT); - int sampleRate = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_SAMPLE_RATE); - int encoderDelay = getOptionalIntegerV16(mediaFormat, "encoder-delay"); - int encoderPadding = getOptionalIntegerV16(mediaFormat, "encoder-padding"); - ArrayList initializationData = new ArrayList<>(); - for (int i = 0; mediaFormat.containsKey("csd-" + i); i++) { - ByteBuffer buffer = mediaFormat.getByteBuffer("csd-" + i); - byte[] data = new byte[buffer.limit()]; - buffer.get(data); - initializationData.add(data); - buffer.flip(); - } - int pcmEncoding = MimeTypes.AUDIO_RAW.equals(mimeType) ? C.ENCODING_PCM_16BIT : Format.NO_VALUE; - Format format = new Format(Integer.toString(index), null, mimeType, null, Format.NO_VALUE, - maxInputSize, width, height, frameRate, rotationDegrees, Format.NO_VALUE, channelCount, - sampleRate, pcmEncoding, encoderDelay, encoderPadding, 0, language, - Format.OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, false); - format.setFrameworkMediaFormatV16(mediaFormat); - return format; - } - - @TargetApi(16) - private static String getOptionalStringV16(MediaFormat format, String key) { - return format.containsKey(key) ? format.getString(key) : null; - } - - @TargetApi(16) - private static int getOptionalIntegerV16(MediaFormat format, String key) { - return format.containsKey(key) ? format.getInteger(key) : Format.NO_VALUE; - } - - @TargetApi(16) - private static float getOptionalFloatV16(MediaFormat format, String key) { - return format.containsKey(key) ? format.getFloat(key) : Format.NO_VALUE; - } - - private final class TrackStreamImpl implements TrackStream { - - private final int track; - - public TrackStreamImpl(int track) { - this.track = track; - } - - @Override - public boolean isReady() { - // MediaExtractor takes care of buffering and blocks until it has samples, so we can always - // return true here. Although note that the blocking behavior is itself as bug, as per the - // TODO further up this file. This method will need to return something else as part of fixing - // the TODO. - return true; - } - - @Override - public void maybeThrowError() throws IOException { - // Do nothing. - } - - @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { - return FrameworkSampleSource.this.readData(track, formatHolder, buffer); - } - - } - -}