188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber/*
288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Copyright (C) 2012 The Android Open Source Project
388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * you may not use this file except in compliance with the License.
688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * You may obtain a copy of the License at
788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
1088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Unless required by applicable law or agreed to in writing, software
1188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * See the License for the specific language governing permissions and
1488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * limitations under the License.
1588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber */
1688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
1788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberpackage android.media;
1888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
1907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huberimport android.content.ContentResolver;
2007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huberimport android.content.Context;
2107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huberimport android.content.res.AssetFileDescriptor;
2291befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huberimport android.media.MediaCodec;
2360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huberimport android.media.MediaFormat;
24d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.media.MediaHTTPService;
2507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huberimport android.net.Uri;
26d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.os.IBinder;
27c209a06cfdcf633f12a299245312e3ac32bff27cMarco Nelissen
2807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huberimport java.io.FileDescriptor;
2907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huberimport java.io.IOException;
3088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberimport java.nio.ByteBuffer;
31e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissenimport java.nio.ByteOrder;
32e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissenimport java.util.HashMap;
3388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberimport java.util.Map;
34e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissenimport java.util.UUID;
3588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber/**
3707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * MediaExtractor facilitates extraction of demuxed, typically encoded,  media data
3807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * from a data source.
3907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * <p>It is generally used like this:
4007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * <pre>
4107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * MediaExtractor extractor = new MediaExtractor();
4207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * extractor.setDataSource(...);
4360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber * int numTracks = extractor.getTrackCount();
4407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * for (int i = 0; i &lt; numTracks; ++i) {
452ac3f2e285159300c62c797bb2123604773ccac7Andreas Huber *   MediaFormat format = extractor.getTrackFormat(i);
462ac3f2e285159300c62c797bb2123604773ccac7Andreas Huber *   String mime = format.getString(MediaFormat.KEY_MIME);
4707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber *   if (weAreInterestedInThisTrack) {
4807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber *     extractor.selectTrack(i);
4907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber *   }
5007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * }
5107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * ByteBuffer inputBuffer = ByteBuffer.allocate(...)
5207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * while (extractor.readSampleData(inputBuffer, ...) &gt;= 0) {
53a242deb1de365f0ed0032a87565df1971cb6bbe2Teng-Hui Zhu *   int trackIndex = extractor.getSampleTrackIndex();
5407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber *   long presentationTimeUs = extractor.getSampleTime();
5507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber *   ...
5607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber *   extractor.advance();
5707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * }
5807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber *
5907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * extractor.release();
6007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * extractor = null;
6107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber * </pre>
6260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber */
638240d9239d9aabed75c49f9d4d69fd8a5fe4c899Andreas Huberfinal public class MediaExtractor {
6407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    public MediaExtractor() {
6507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        native_setup();
6607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    }
6707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
6807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    /**
69c209a06cfdcf633f12a299245312e3ac32bff27cMarco Nelissen     * Sets the DataSource object to be used as the data source for this extractor
70c209a06cfdcf633f12a299245312e3ac32bff27cMarco Nelissen     * {@hide}
71c209a06cfdcf633f12a299245312e3ac32bff27cMarco Nelissen     */
72a57da0dc5a5b863cdb12287699ba58f34529bd62Andreas Huber    public native final void setDataSource(DataSource source) throws IOException;
73c209a06cfdcf633f12a299245312e3ac32bff27cMarco Nelissen
74c209a06cfdcf633f12a299245312e3ac32bff27cMarco Nelissen    /**
7507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * Sets the data source as a content Uri.
7607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     *
7707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param context the Context to use when resolving the Uri
7807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param uri the Content URI of the data you want to extract from.
7907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param headers the headers to be sent together with the request for the data
8007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     */
8107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    public final void setDataSource(
8207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            Context context, Uri uri, Map<String, String> headers)
8307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        throws IOException {
8407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        String scheme = uri.getScheme();
8507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        if(scheme == null || scheme.equals("file")) {
8607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            setDataSource(uri.getPath());
8707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            return;
8807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        }
8907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
9007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        AssetFileDescriptor fd = null;
9107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        try {
9207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            ContentResolver resolver = context.getContentResolver();
9307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            fd = resolver.openAssetFileDescriptor(uri, "r");
9407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            if (fd == null) {
9507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                return;
9607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            }
9707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            // Note: using getDeclaredLength so that our behavior is the same
9807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            // as previous versions when the content provider is returning
9907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            // a full file.
10007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            if (fd.getDeclaredLength() < 0) {
10107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                setDataSource(fd.getFileDescriptor());
10207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            } else {
10307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                setDataSource(
10407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                        fd.getFileDescriptor(),
10507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                        fd.getStartOffset(),
10607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                        fd.getDeclaredLength());
10707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            }
10807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            return;
10907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        } catch (SecurityException ex) {
11007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        } catch (IOException ex) {
11107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        } finally {
11207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            if (fd != null) {
11307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                fd.close();
11407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            }
11507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        }
11607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
11707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        setDataSource(uri.toString(), headers);
11807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    }
11907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
12007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    /**
12107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * Sets the data source (file-path or http URL) to use.
12207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     *
12307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param path the path of the file, or the http URL
12407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param headers the headers associated with the http request for the stream you want to play
12507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     */
126a57da0dc5a5b863cdb12287699ba58f34529bd62Andreas Huber    public final void setDataSource(String path, Map<String, String> headers)
127a57da0dc5a5b863cdb12287699ba58f34529bd62Andreas Huber        throws IOException {
12807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        String[] keys = null;
12907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        String[] values = null;
13007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
13107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        if (headers != null) {
13207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            keys = new String[headers.size()];
13307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            values = new String[headers.size()];
13407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
13507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            int i = 0;
13607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            for (Map.Entry<String, String> entry: headers.entrySet()) {
13707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                keys[i] = entry.getKey();
13807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                values[i] = entry.getValue();
13907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber                ++i;
14007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            }
14107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        }
142d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber
143d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber        nativeSetDataSource(
144d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
145d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                path,
146d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                keys,
147d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                values);
14807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    }
14907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
150d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber    private native final void nativeSetDataSource(
151d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber            IBinder httpServiceBinder,
152d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber            String path,
153d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber            String[] keys,
154d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber            String[] values) throws IOException;
15507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
15607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    /**
15707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * Sets the data source (file-path or http URL) to use.
15807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     *
15907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param path the path of the file, or the http URL of the stream
16007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     *
16107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
16207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * process other than the calling application.  This implies that the pathname
16307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * should be an absolute path (as any other process runs with unspecified current working
16407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * directory), and that the pathname should reference a world-readable file.
16507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * As an alternative, the application could first open the file for reading,
16607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
16707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     */
168a57da0dc5a5b863cdb12287699ba58f34529bd62Andreas Huber    public final void setDataSource(String path) throws IOException {
169d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber        nativeSetDataSource(
170d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
171d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                path,
172d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                null,
173d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber                null);
17407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    }
17507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
17607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    /**
17707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
17807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * to close the file descriptor. It is safe to do so as soon as this call returns.
17907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     *
18007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param fd the FileDescriptor for the file you want to extract from.
18107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     */
182a57da0dc5a5b863cdb12287699ba58f34529bd62Andreas Huber    public final void setDataSource(FileDescriptor fd) throws IOException {
18307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        setDataSource(fd, 0, 0x7ffffffffffffffL);
18488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
18588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
18607ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    /**
18707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * Sets the data source (FileDescriptor) to use.  The FileDescriptor must be
18807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
18907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * to close the file descriptor. It is safe to do so as soon as this call returns.
19007ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     *
19107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param fd the FileDescriptor for the file you want to extract from.
19207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param offset the offset into the file where the data to be extracted starts, in bytes
19307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     * @param length the length in bytes of the data to be extracted
19407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     */
19507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    public native final void setDataSource(
196a57da0dc5a5b863cdb12287699ba58f34529bd62Andreas Huber            FileDescriptor fd, long offset, long length) throws IOException;
19707ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
19888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    @Override
19988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    protected void finalize() {
20088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        native_finalize();
20188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
20288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
20360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
20460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Make sure you call this when you're done to free up any resources
20560d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * instead of relying on the garbage collector to do this for you at
20660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * some point in the future.
20760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
20888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    public native final void release();
20988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
21060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
21160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Count the number of tracks found in the data source.
21260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
21360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    public native final int getTrackCount();
21460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber
21560d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
216ecba2e4b953e9480b5084c04ec0cb5a8ba574b03Marco Nelissen     * Get the PSSH info if present.
217ecba2e4b953e9480b5084c04ec0cb5a8ba574b03Marco Nelissen     * @return a map of uuid-to-bytes, with the uuid specifying
218e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen     * the crypto scheme, and the bytes being the data specific to that scheme.
219e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen     */
220e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen    public Map<UUID, byte[]> getPsshInfo() {
221e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen        Map<UUID, byte[]> psshMap = null;
222e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen        Map<String, Object> formatMap = getFileFormatNative();
223e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen        if (formatMap != null && formatMap.containsKey("pssh")) {
224e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            ByteBuffer rawpssh = (ByteBuffer) formatMap.get("pssh");
225e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            rawpssh.order(ByteOrder.nativeOrder());
226e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            rawpssh.rewind();
227e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            formatMap.remove("pssh");
228e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            // parse the flat pssh bytebuffer into something more manageable
229e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            psshMap = new HashMap<UUID, byte[]>();
230e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            while (rawpssh.remaining() > 0) {
231e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                rawpssh.order(ByteOrder.BIG_ENDIAN);
232e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                long msb = rawpssh.getLong();
233e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                long lsb = rawpssh.getLong();
234e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                UUID uuid = new UUID(msb, lsb);
235e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                rawpssh.order(ByteOrder.nativeOrder());
236e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                int datalen = rawpssh.getInt();
237e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                byte [] psshdata = new byte[datalen];
238e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                rawpssh.get(psshdata);
239e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen                psshMap.put(uuid, psshdata);
240e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen            }
241e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen        }
242e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen        return psshMap;
243e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen    }
244e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen
245e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen    private native Map<String, Object> getFileFormatNative();
246e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen
247e20a6d5c479909f37af748a81a6e5a5deb7b6e2cMarco Nelissen    /**
24860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Get the track format at the specified index.
24960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * More detail on the representation can be found at {@link android.media.MediaCodec}
25060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
25160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    public MediaFormat getTrackFormat(int index) {
25260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber        return new MediaFormat(getTrackFormatNative(index));
25360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    }
25460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber
25560d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    private native Map<String, Object> getTrackFormatNative(int index);
25660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber
25760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
25860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
25960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * {@link #getSampleTime} only retrieve information for the subset of tracks
26060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * selected.
26160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Selecting the same track multiple times has no effect, the track is
26260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * only selected once.
26307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     */
26488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    public native void selectTrack(int index);
26588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
26660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
26760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
26860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * {@link #getSampleTime} only retrieve information for the subset of tracks
26960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * selected.
27060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
271f2855b3df5994e165b29025c4c49d8e7d634c034Andreas Huber    public native void unselectTrack(int index);
272f2855b3df5994e165b29025c4c49d8e7d634c034Andreas Huber
27360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
27460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * If possible, seek to a sync sample at or before the specified time
27560d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
276f2855b3df5994e165b29025c4c49d8e7d634c034Andreas Huber    public static final int SEEK_TO_PREVIOUS_SYNC       = 0;
27760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
27860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * If possible, seek to a sync sample at or after the specified time
27960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
280f2855b3df5994e165b29025c4c49d8e7d634c034Andreas Huber    public static final int SEEK_TO_NEXT_SYNC           = 1;
28160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
28260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * If possible, seek to the sync sample closest to the specified time
28360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
284f2855b3df5994e165b29025c4c49d8e7d634c034Andreas Huber    public static final int SEEK_TO_CLOSEST_SYNC        = 2;
285f2855b3df5994e165b29025c4c49d8e7d634c034Andreas Huber
28660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
28760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * All selected tracks seek near the requested time according to the
28860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * specified mode.
28960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
290f2855b3df5994e165b29025c4c49d8e7d634c034Andreas Huber    public native void seekTo(long timeUs, int mode);
29188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
29260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
29360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Advance to the next sample. Returns false if no more sample data
29460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * is available (end of stream).
29507ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber     */
29688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    public native boolean advance();
29788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
29860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
29960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Retrieve the current encoded sample and store it in the byte buffer
3007be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * starting at the given offset.
3017be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * <p>
3027be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * <b>Note:</b>As of API 21, on success the position and limit of
3037be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * {@code byteBuf} is updated to point to the data just read.
3047be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * @param byteBuf the destination byte buffer
3057be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * @return the sample size (or -1 if no more samples are available).
30660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
30788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    public native int readSampleData(ByteBuffer byteBuf, int offset);
30888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
30960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
31060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Returns the track index the current sample originates from (or -1
31160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * if no more samples are available)
31260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
31388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    public native int getSampleTrackIndex();
31488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
31560d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
31660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Returns the current sample's presentation time in microseconds.
31760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * or -1 if no more samples are available.
31860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
31988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    public native long getSampleTime();
32088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3219b8e496f4d143280deff137c5f30ca8907bc28dbAndreas Huber    // Keep these in sync with their equivalents in NuMediaExtractor.h
32260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
3237be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * The sample is a sync sample (or in {@link MediaCodec}'s terminology
3247be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * it is a key frame.)
3257be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     *
3267be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar     * @see MediaCodec#BUFFER_FLAG_KEY_FRAME
32760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
3289b8e496f4d143280deff137c5f30ca8907bc28dbAndreas Huber    public static final int SAMPLE_FLAG_SYNC      = 1;
32907ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber
33060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
33160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * The sample is (at least partially) encrypted, see also the documentation
33260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * for {@link android.media.MediaCodec#queueSecureInputBuffer}
33360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
3349b8e496f4d143280deff137c5f30ca8907bc28dbAndreas Huber    public static final int SAMPLE_FLAG_ENCRYPTED = 2;
3359b8e496f4d143280deff137c5f30ca8907bc28dbAndreas Huber
33660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
33760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Returns the current sample's flags.
33860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
3399b8e496f4d143280deff137c5f30ca8907bc28dbAndreas Huber    public native int getSampleFlags();
3409b8e496f4d143280deff137c5f30ca8907bc28dbAndreas Huber
34160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
34260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * If the sample flags indicate that the current sample is at least
34360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * partially encrypted, this call returns relevant information about
34460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * the structure of the sample data required for decryption.
34560d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * @param info The android.media.MediaCodec.CryptoInfo structure
34660d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     *             to be filled in.
34760d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * @return true iff the sample flags contain {@link #SAMPLE_FLAG_ENCRYPTED}
34860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
34991befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber    public native boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info);
35091befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber
35160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
35260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Returns an estimate of how much data is presently cached in memory
35360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * expressed in microseconds. Returns -1 if that information is unavailable
35460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * or not applicable (no cache).
35574a78b0f6e8c07cfc7da8f043987f6de0648bc05Andreas Huber     */
35674a78b0f6e8c07cfc7da8f043987f6de0648bc05Andreas Huber    public native long getCachedDuration();
35774a78b0f6e8c07cfc7da8f043987f6de0648bc05Andreas Huber
35860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    /**
35960d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * Returns true iff we are caching data and the cache has reached the
36060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * end of the data stream (for now, a future seek may of course restart
36160d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * the fetching of data).
362a45746efadd11bb7dfab026fb3c81a25fae74ca4Jeff Smith     * This API only returns a meaningful result if {@link #getCachedDuration}
36360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     * indicates the presence of a cache, i.e. does NOT return -1.
36460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber     */
36574a78b0f6e8c07cfc7da8f043987f6de0648bc05Andreas Huber    public native boolean hasCacheReachedEndOfStream();
36674a78b0f6e8c07cfc7da8f043987f6de0648bc05Andreas Huber
36788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    private static native final void native_init();
36807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber    private native final void native_setup();
36988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    private native final void native_finalize();
37088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
37188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    static {
37288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        System.loadLibrary("media_jni");
37388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        native_init();
37488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
37588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
376075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    private long mNativeContext;
37788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
378