Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 195d7c15 authored by Santiago Seifert's avatar Santiago Seifert Committed by Android (Google) Code Review
Browse files

Merge changes I11074924,Ieb6b114e

* changes:
  Add initial stubs for MediaParser
  Add ExoPlayer dependency to frameworks/base
parents 94558989 964f541d
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -390,7 +390,7 @@ java_defaults {

filegroup {
    name: "framework-jarjar-rules",
    srcs: ["jarjar_rules_hidl.txt"],
    srcs: ["framework_jarjar_rules.txt"],
}

filegroup {
@@ -467,6 +467,7 @@ java_library {
    srcs: [":framework-all-sources"],
    installable: false,
    libs: ["app-compat-annotations"],
    static_libs: ["exoplayer2-core"]
}

java_library {
@@ -479,6 +480,9 @@ java_library {
        "unsupportedappusage-annotation-processor",
        "compat-changeid-annotation-processor",
    ],
    static_libs: [
        "exoplayer2-core"
    ]
}

platform_compat_config {
+2 −0
Original line number Diff line number Diff line
rule android.hidl.** android.internal.hidl.@1
rule com.google.android.exoplayer2.** android.media.internal.exo.@1
+13 −0
Original line number Diff line number Diff line
@@ -34,6 +34,11 @@ java_library {
        "android_system_stubs_current",
    ],

    static_libs: [
        "exoplayer2-core"
    ],
    jarjar_rules: "jarjar_rules.txt",

    plugins: ["java_api_finder"],
}

@@ -41,6 +46,7 @@ filegroup {
    name: "updatable-media-srcs",
    srcs: [
        ":mediasession2-srcs",
        ":mediaparser-srcs",
    ],
}

@@ -63,6 +69,13 @@ filegroup {
    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 " +
+391 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}

media/jarjar_rules.txt

0 → 100644
+1 −0
Original line number Diff line number Diff line
rule com.google.android.exoplayer2.** android.media.internal.exo.@1
Loading