diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java index 52e4c63213..327f4808b6 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaExtractorCompat.java @@ -22,6 +22,7 @@ import static androidx.media3.exoplayer.source.SampleStream.FLAG_PEEK; import static androidx.media3.exoplayer.source.SampleStream.FLAG_REQUIRE_FORMAT; import android.content.Context; +import android.content.res.AssetFileDescriptor; import android.media.MediaExtractor; import android.media.MediaFormat; import android.net.Uri; @@ -41,6 +42,7 @@ import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSourceUtil; import androidx.media3.datasource.DataSpec; import androidx.media3.datasource.DefaultDataSource; +import androidx.media3.datasource.FileDescriptorDataSource; import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; import androidx.media3.exoplayer.source.SampleQueue; @@ -67,6 +69,7 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import java.io.EOFException; +import java.io.FileDescriptor; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -136,9 +139,18 @@ public final class MediaExtractorCompat { } /** - * Creates a new instance using the given {@link ExtractorsFactory extractorsFactory} to create - * the {@link Extractor extractors} to use for obtaining media samples from a DataSource generated - * by the given {@link DataSource.Factory dataSourceFactory}. + * Creates a new instance using the given {@link ExtractorsFactory} to create the {@linkplain + * Extractor extractors} to use for obtaining media samples from a {@link DataSource} generated by + * the given {@link DataSource.Factory}. + * + *

Note: The {@link DataSource.Factory} provided will not be used to generate {@link + * DataSource} when setting data source using methods: + * + *

*/ public MediaExtractorCompat( ExtractorsFactory extractorsFactory, DataSource.Factory dataSourceFactory) { @@ -156,8 +168,8 @@ public final class MediaExtractorCompat { } /** - * Initializes the internal state with the media stream obtained from the given {@code uri} at the - * given {@code offset}. + * Sets the data source using the media stream obtained from the given {@link Uri} at the given + * {@code offset}. * * @param uri The content {@link Uri} to extract from. * @param offset The offset into the file where the data to be extracted starts, in bytes. @@ -167,13 +179,75 @@ public final class MediaExtractorCompat { * @throws IllegalStateException If this method is called twice on the same instance. */ public void setDataSource(Uri uri, long offset) throws IOException { + prepareDataSource( + dataSourceFactory.createDataSource(), buildDataSpec(uri, /* position= */ offset)); + } + + /** + * Sets the data source using the media stream obtained from the provided {@link + * AssetFileDescriptor}. + * + *

Note: The caller is responsible for closing the {@link AssetFileDescriptor}. It is safe to + * do so immediately after this method returns. + * + * @param assetFileDescriptor The {@link AssetFileDescriptor} for the file to extract from. + * @throws IOException If an error occurs while extracting the media. + * @throws UnrecognizedInputFormatException If none of the available extractors successfully + * sniffs the input. + * @throws IllegalStateException If this method is called twice on the same instance. + */ + public void setDataSource(AssetFileDescriptor assetFileDescriptor) throws IOException { + if (assetFileDescriptor.getLength() == AssetFileDescriptor.UNKNOWN_LENGTH) { + setDataSource(assetFileDescriptor.getFileDescriptor()); + } else { + setDataSource( + assetFileDescriptor.getFileDescriptor(), + assetFileDescriptor.getStartOffset(), + assetFileDescriptor.getLength()); + } + } + + /** + * Sets the data source using the media stream obtained from the provided {@link FileDescriptor}. + * + * @param fileDescriptor The {@link FileDescriptor} for the file to extract from. + * @throws IOException If an error occurs while extracting the media. + * @throws UnrecognizedInputFormatException If none of the available extractors successfully + * sniffs the input. + * @throws IllegalStateException If this method is called twice on the same instance. + */ + public void setDataSource(FileDescriptor fileDescriptor) throws IOException { + setDataSource(fileDescriptor, /* offset= */ 0, /* length= */ C.LENGTH_UNSET); + } + + /** + * Sets the data source using the media stream obtained from the provided {@link FileDescriptor}, + * with a specified {@code offset} and {@code length}. + * + * @param fileDescriptor The {@link FileDescriptor} for the file to extract from. + * @param offset The offset into the file where the data to be extracted starts, in bytes. + * @param length The length of the data to be extracted, in bytes, or {@link C#LENGTH_UNSET} if it + * is unknown. + * @throws IOException If an error occurs while extracting the media. + * @throws UnrecognizedInputFormatException If none of the available extractors successfully + * sniffs the input. + * @throws IllegalStateException If this method is called twice on the same instance. + */ + public void setDataSource(FileDescriptor fileDescriptor, long offset, long length) + throws IOException { + FileDescriptorDataSource fileDescriptorDataSource = + new FileDescriptorDataSource(fileDescriptor, offset, length); + DataSpec dataSpec = new DataSpec(Uri.EMPTY); + prepareDataSource(fileDescriptorDataSource, dataSpec); + } + + private void prepareDataSource(DataSource dataSource, DataSpec dataSpec) throws IOException { // Assert that this instance is not being re-prepared, which is not currently supported. Assertions.checkState(!hasBeenPrepared); hasBeenPrepared = true; - offsetInCurrentFile = offset; - DataSpec dataSpec = buildDataSpec(uri, /* position= */ offsetInCurrentFile); + offsetInCurrentFile = dataSpec.position; + currentDataSource = dataSource; - currentDataSource = dataSourceFactory.createDataSource(); long length = currentDataSource.open(dataSpec); ExtractorInput currentExtractorInput = new DefaultExtractorInput(currentDataSource, /* position= */ 0, length);