Add initial stubs for MediaParser
Bug: 132153067
Bug: 134057371
Test: Only stubs submitted.
Change-Id: I1107492445126127a92649abf97268c817cedf1b
diff --git a/media/Android.bp b/media/Android.bp
index 2f75e44..022fa9b 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -34,6 +34,11 @@
"android_system_stubs_current",
],
+ static_libs: [
+ "exoplayer2-core"
+ ],
+ jarjar_rules: "jarjar_rules.txt",
+
plugins: ["java_api_finder"],
}
@@ -41,6 +46,7 @@
name: "updatable-media-srcs",
srcs: [
":mediasession2-srcs",
+ ":mediaparser-srcs",
],
}
@@ -63,6 +69,13 @@
path: "apex/java",
}
+filegroup {
+ name: "mediaparser-srcs",
+ srcs: [
+ "apex/java/android/media/MediaParser.java"
+ ]
+}
+
metalava_updatable_media_args = " --error UnhiddenSystemApi " +
"--hide RequiresPermission " +
"--hide MissingPermission --hide BroadcastBehavior " +
diff --git a/media/apex/java/android/media/MediaParser.java b/media/apex/java/android/media/MediaParser.java
new file mode 100644
index 0000000..c06e283
--- /dev/null
+++ b/media/apex/java/android/media/MediaParser.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2019 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 android.media;
+
+import android.util.Pair;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Parses media container formats and extracts contained media samples and metadata.
+ *
+ * <p>This class provides access to a battery of low-level media container parsers. Each instance of
+ * this class is associated to a specific media parser implementation which is suitable for
+ * extraction from a specific media container format. The media parser implementation assignment
+ * depends on the factory method (see {@link #create} and {@link #createByName}) used to create the
+ * instance.
+ *
+ * <p>Users must implement the following to use this class.
+ *
+ * <ul>
+ * <li>{@link Input}: Provides the media containers bytes to parse.
+ * <li>{@link OutputCallback}: Provides a sink for all extracted data and metadata.
+ * </ul>
+ *
+ * TODO: Add usage example here.
+ */
+// @HiddenApi
+public final class MediaParser {
+
+ /** Maps seek positions to corresponding positions in the stream. */
+ public interface SeekMap {
+
+ /** Returned by {@link #getDurationUs()} when the duration is unknown. */
+ int UNKNOWN_DURATION = Integer.MIN_VALUE;
+
+ /** Returns whether seeking is supported. */
+ boolean isSeekable();
+
+ /**
+ * Returns the duration of the stream in microseconds or {@link #UNKNOWN_DURATION} if the
+ * duration is unknown.
+ */
+ long getDurationUs();
+
+ /**
+ * Obtains {@link SeekPoint SeekPoints} for the specified seek time in microseconds.
+ *
+ * <p>{@code getSeekPoints(timeUs).first} contains the latest seek point for samples with
+ * timestamp equal to or smaller than {@code timeUs}.
+ *
+ * <p>{@code getSeekPoints(timeUs).second} contains the earlies seek point for samples with
+ * timestamp equal to or greater than {@code timeUs}. If a seek point exists for {@code
+ * timeUs}, the returned pair will contain the same {@link SeekPoint} twice.
+ *
+ * @param timeUs A seek time in microseconds.
+ * @return The corresponding {@link SeekPoint SeekPoints}.
+ */
+ Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs);
+ }
+
+ /** Defines a seek point in a media stream. */
+ public static final class SeekPoint {
+
+ /** A {@link SeekPoint} whose time and byte offset are both set to 0. */
+ public static final SeekPoint START = new SeekPoint(0, 0);
+
+ /** The time of the seek point, in microseconds. */
+ public final long mTimeUs;
+
+ /** The byte offset of the seek point. */
+ public final long mPosition;
+
+ /**
+ * @param timeUs The time of the seek point, in microseconds.
+ * @param position The byte offset of the seek point.
+ */
+ public SeekPoint(long timeUs, long position) {
+ this.mTimeUs = timeUs;
+ this.mPosition = position;
+ }
+
+ @Override
+ public String toString() {
+ return "[timeUs=" + mTimeUs + ", position=" + mPosition + "]";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ SeekPoint other = (SeekPoint) obj;
+ return mTimeUs == other.mTimeUs && mPosition == other.mPosition;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) mTimeUs;
+ result = 31 * result + (int) mPosition;
+ return result;
+ }
+ }
+
+ /** Provides input data to {@link MediaParser}. */
+ public interface Input {
+
+ /**
+ * Reads up to {@code readLength} bytes of data and stores them into {@code buffer},
+ * starting at index {@code offset}.
+ *
+ * <p>The call will block until at least one byte of data has been read.
+ *
+ * @param buffer The buffer into which the read data should be stored.
+ * @param offset The start offset into {@code buffer} at which data should be written.
+ * @param readLength The maximum number of bytes to read.
+ * @return The non-zero number of bytes read, or -1 if no data is available because the end
+ * of the input has been reached.
+ * @throws java.io.IOException If an error occurs reading from the source.
+ */
+ int read(byte[] buffer, int offset, int readLength)
+ throws IOException, InterruptedException;
+
+ /** Returns the current read position (byte offset) in the stream. */
+ long getPosition();
+
+ /** Returns the length of the input in bytes, or -1 if the length is unknown. */
+ long getLength();
+ }
+
+ /** Receives extracted media sample data and metadata from {@link MediaParser}. */
+ public interface OutputCallback {
+
+ /**
+ * Called when the number of tracks is defined.
+ *
+ * @param numberOfTracks The number of tracks in the stream.
+ */
+ void onTracksFound(int numberOfTracks);
+
+ /**
+ * Called when a {@link SeekMap} has been extracted from the stream.
+ *
+ * @param seekMap The extracted {@link SeekMap}.
+ */
+ void onSeekMap(SeekMap seekMap);
+
+ /**
+ * Called when the {@link MediaFormat} of the track is extracted from the stream.
+ *
+ * @param trackIndex The index of the track for which the {@link MediaFormat} was found.
+ * @param format The extracted {@link MediaFormat}.
+ */
+ void onFormat(int trackIndex, MediaFormat format);
+
+ /**
+ * Called to write sample data to the output.
+ *
+ * <p>Implementers must attempt to consume the entirety of the input, but should surface any
+ * thrown {@link IOException} caused by reading from {@code input}.
+ *
+ * @param trackIndex The index of the track to which the sample data corresponds.
+ * @param input The {@link Input} from which to read the data.
+ * @return
+ */
+ int onSampleData(int trackIndex, Input input) throws IOException, InterruptedException;
+
+ /**
+ * Defines the boundaries and metadata of an extracted sample.
+ *
+ * <p>The corresponding sample data will have already been passed to the output via calls to
+ * {@link #onSampleData}.
+ *
+ * @param trackIndex The index of the track to which the sample corresponds.
+ * @param timeUs The media timestamp associated with the sample, in microseconds.
+ * @param flags Flags associated with the sample. See {@link MediaCodec
+ * MediaCodec.BUFFER_FLAG_*}.
+ * @param size The size of the sample data, in bytes.
+ * @param offset The number of bytes that have been passed to {@link #onSampleData} since
+ * the last byte belonging to the sample whose metadata is being passed.
+ * @param cryptoData Encryption data required to decrypt the sample. May be null for
+ * unencrypted samples.
+ */
+ void onSampleCompleted(
+ int trackIndex,
+ long timeUs,
+ int flags,
+ int size,
+ int offset,
+ MediaCodec.CryptoInfo cryptoData);
+ }
+
+ /**
+ * Controls the behavior of extractors' implementations.
+ *
+ * <p>DESIGN NOTE: For setting flags like workarounds and special behaviors for adaptive
+ * streaming.
+ */
+ public static final class Parameters {
+
+ // TODO: Implement.
+
+ }
+
+ /** Holds the result of an {@link #advance} invocation. */
+ public static final class ResultHolder {
+
+ /** Creates a new instance with {@link #result} holding {@link #ADVANCE_RESULT_CONTINUE}. */
+ public ResultHolder() {
+ result = ADVANCE_RESULT_CONTINUE;
+ }
+
+ /**
+ * May hold {@link #ADVANCE_RESULT_END_OF_INPUT}, {@link #ADVANCE_RESULT_CONTINUE}, {@link
+ * #ADVANCE_RESULT_SEEK}.
+ */
+ public int result;
+
+ /**
+ * If {@link #result} holds {@link #ADVANCE_RESULT_SEEK}, holds the stream position required
+ * from the passed {@link Input} to the next {@link #advance} call. If {@link #result} does
+ * not hold {@link #ADVANCE_RESULT_SEEK}, the value of this variable is undefined and should
+ * be ignored.
+ */
+ public long seekPosition;
+ }
+
+ /**
+ * Thrown if all extractors implementations provided to {@link #create} failed to sniff the
+ * input content.
+ */
+ // @HiddenApi
+ public static final class UnrecognizedInputFormatException extends IOException {
+
+ /**
+ * Creates a new instance which signals that the extractors with the given names failed to
+ * parse the input.
+ */
+ public static UnrecognizedInputFormatException createForExtractors(
+ String... extractorNames) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("None of the available extractors ( ");
+ builder.append(extractorNames[0]);
+ for (int i = 1; i < extractorNames.length; i++) {
+ builder.append(", ");
+ builder.append(extractorNames[i]);
+ }
+ builder.append(") could read the stream.");
+ return new UnrecognizedInputFormatException(builder.toString());
+ }
+
+ private UnrecognizedInputFormatException(String extractorNames) {
+ super(extractorNames);
+ }
+ }
+
+ // Public constants.
+
+ /**
+ * Returned by {@link #advance} if the {@link Input} passed to the next {@link #advance} is
+ * required to provide data continuing from the position in the stream reached by the returning
+ * call.
+ */
+ public static final int ADVANCE_RESULT_CONTINUE = -1;
+ /** Returned by {@link #advance} if the end of the {@link Input} was reached. */
+ public static final int ADVANCE_RESULT_END_OF_INPUT = -2;
+ /**
+ * Returned by {@link #advance} when its next call expects a specific stream position, which
+ * will be held by {@link ResultHolder#seekPosition}.
+ */
+ public static final int ADVANCE_RESULT_SEEK = -3;
+
+ // Instance creation methods.
+
+ /**
+ * Creates an instance backed by the extractor with the given {@code name}. The returned
+ * instance will attempt extraction without sniffing the content.
+ *
+ * @param name The name of the extractor that will be associated with the created instance.
+ * @param outputCallback The {@link OutputCallback} to which track data and samples are pushed.
+ * @param parameters Parameters that control specific aspects of the behavior of the extractors.
+ * @return A new instance.
+ */
+ public static MediaParser createByName(
+ String name, OutputCallback outputCallback, Parameters parameters) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Creates an instance whose backing extractor will be selected by sniffing the content during
+ * the first {@link #advance} call. Extractor implementations will sniff the content in order of
+ * appearance in {@code extractorNames}.
+ *
+ * @param outputCallback The {@link OutputCallback} to track data and samples are obtained.
+ * @param parameters Parameters that control specific aspects of the behavior of the extractors.
+ * @param extractorNames The names of the extractors to sniff the content with. If empty, a
+ * default array of names is used.
+ * @return A new instance.
+ */
+ public static MediaParser create(
+ OutputCallback outputCallback, Parameters parameters, String... extractorNames) {
+ throw new UnsupportedOperationException();
+ }
+
+ // Misc static methods.
+
+ /**
+ * Returns an immutable list with the names of the extractors that are suitable for container
+ * formats with the given {@code mimeTypes}. If an empty string is passed, all available
+ * extractors' names are returned.
+ *
+ * <p>TODO: Replace string with media type object.
+ */
+ public static List<String> getExtractorNames(String mimeTypes) {
+ throw new UnsupportedOperationException();
+ }
+
+ // Public methods.
+
+ /**
+ * Returns the name of the backing extractor implementation.
+ *
+ * <p>If this instance was creating using {@link #createByName}, the provided name is returned.
+ * If this instance was created using {@link #create}, this method will return null until the
+ * first call to {@link #advance}, after which the name of the backing extractor implementation
+ * is returned.
+ *
+ * @return The name of the backing extractor implementation, or null if the backing extractor
+ * implementation has not yet been selected.
+ */
+ public String getExtractorName() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Makes progress in the extraction of the input media stream, unless the end of the input has
+ * been reached.
+ *
+ * <p>This method will block until some progress has been made.
+ *
+ * <p>If this instance was created using {@link #create}. the first call to this method will
+ * sniff the content with the extractors with the provided names.
+ *
+ * @param input The {@link Input} from which to obtain the media container data.
+ * @param resultHolder The {@link ResultHolder} into which the result of the operation will be
+ * written.
+ * @throws UnrecognizedInputFormatException
+ */
+ public void advance(Input input, ResultHolder resultHolder)
+ throws IOException, InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Seeks within the media container being extracted.
+ *
+ * <p>Following a call to this method, the {@link Input} passed to the next invocation of {@link
+ * #advance} must provide data starting from {@link SeekPoint#mPosition} in the stream.
+ *
+ * @param seekPoint The {@link SeekPoint} to seek to.
+ */
+ public void seek(SeekPoint seekPoint) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Releases any acquired resources.
+ *
+ * <p>After calling this method, this instance becomes unusable and no other methods should be
+ * invoked. DESIGN NOTE: Should be removed. There shouldn't be any resource for releasing.
+ */
+ public void release() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/media/jarjar_rules.txt b/media/jarjar_rules.txt
new file mode 100644
index 0000000..d89d9d3
--- /dev/null
+++ b/media/jarjar_rules.txt
@@ -0,0 +1 @@
+rule com.google.android.exoplayer2.** android.media.internal.exo.@1