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 < 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, ...) >= 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