MediaExtractor.java revision 74a78b0f6e8c07cfc7da8f043987f6de0648bc05
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media; 18 19import android.content.ContentResolver; 20import android.content.Context; 21import android.content.res.AssetFileDescriptor; 22import android.media.MediaCodec; 23import android.net.Uri; 24import java.io.FileDescriptor; 25import java.io.IOException; 26import java.nio.ByteBuffer; 27import java.util.Map; 28 29/** 30 * MediaExtractor facilitates extraction of demuxed, typically encoded, media data 31 * from a data source. 32 * <p>It is generally used like this: 33 * <pre> 34 * MediaExtractor extractor = new MediaExtractor(); 35 * extractor.setDataSource(...); 36 * int numTracks = extractor.countTracks(); 37 * for (int i = 0; i < numTracks; ++i) { 38 * Map%lt;String, Object> format = extractor.getTrackFormat(i); 39 * String mime = (String)format.get("mime"); 40 * if (weAreInterestedInThisTrack) { 41 * extractor.selectTrack(i); 42 * } 43 * } 44 * ByteBuffer inputBuffer = ByteBuffer.allocate(...) 45 * while (extractor.readSampleData(inputBuffer, ...) >= 0) { 46 * int trackIndex = extractor.getTrackIndex(); 47 * long presentationTimeUs = extractor.getSampleTime(); 48 * ... 49 * extractor.advance(); 50 * } 51 * 52 * extractor.release(); 53 * extractor = null; 54 * </pre> 55*/ 56final public class MediaExtractor { 57 public MediaExtractor() { 58 native_setup(); 59 } 60 61 /** 62 * Sets the data source as a content Uri. 63 * 64 * @param context the Context to use when resolving the Uri 65 * @param uri the Content URI of the data you want to extract from. 66 * @param headers the headers to be sent together with the request for the data 67 */ 68 public final void setDataSource( 69 Context context, Uri uri, Map<String, String> headers) 70 throws IOException { 71 String scheme = uri.getScheme(); 72 if(scheme == null || scheme.equals("file")) { 73 setDataSource(uri.getPath()); 74 return; 75 } 76 77 AssetFileDescriptor fd = null; 78 try { 79 ContentResolver resolver = context.getContentResolver(); 80 fd = resolver.openAssetFileDescriptor(uri, "r"); 81 if (fd == null) { 82 return; 83 } 84 // Note: using getDeclaredLength so that our behavior is the same 85 // as previous versions when the content provider is returning 86 // a full file. 87 if (fd.getDeclaredLength() < 0) { 88 setDataSource(fd.getFileDescriptor()); 89 } else { 90 setDataSource( 91 fd.getFileDescriptor(), 92 fd.getStartOffset(), 93 fd.getDeclaredLength()); 94 } 95 return; 96 } catch (SecurityException ex) { 97 } catch (IOException ex) { 98 } finally { 99 if (fd != null) { 100 fd.close(); 101 } 102 } 103 104 setDataSource(uri.toString(), headers); 105 } 106 107 /** 108 * Sets the data source (file-path or http URL) to use. 109 * 110 * @param path the path of the file, or the http URL 111 * @param headers the headers associated with the http request for the stream you want to play 112 */ 113 public final void setDataSource(String path, Map<String, String> headers) { 114 String[] keys = null; 115 String[] values = null; 116 117 if (headers != null) { 118 keys = new String[headers.size()]; 119 values = new String[headers.size()]; 120 121 int i = 0; 122 for (Map.Entry<String, String> entry: headers.entrySet()) { 123 keys[i] = entry.getKey(); 124 values[i] = entry.getValue(); 125 ++i; 126 } 127 } 128 setDataSource(path, keys, values); 129 } 130 131 private native final void setDataSource( 132 String path, String[] keys, String[] values); 133 134 /** 135 * Sets the data source (file-path or http URL) to use. 136 * 137 * @param path the path of the file, or the http URL of the stream 138 * 139 * <p>When <code>path</code> refers to a local file, the file may actually be opened by a 140 * process other than the calling application. This implies that the pathname 141 * should be an absolute path (as any other process runs with unspecified current working 142 * directory), and that the pathname should reference a world-readable file. 143 * As an alternative, the application could first open the file for reading, 144 * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}. 145 */ 146 public final void setDataSource(String path) { 147 setDataSource(path, null, null); 148 } 149 150 /** 151 * Sets the data source (FileDescriptor) to use. It is the caller's responsibility 152 * to close the file descriptor. It is safe to do so as soon as this call returns. 153 * 154 * @param fd the FileDescriptor for the file you want to extract from. 155 */ 156 public final void setDataSource(FileDescriptor fd) { 157 setDataSource(fd, 0, 0x7ffffffffffffffL); 158 } 159 160 /** 161 * Sets the data source (FileDescriptor) to use. The FileDescriptor must be 162 * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility 163 * to close the file descriptor. It is safe to do so as soon as this call returns. 164 * 165 * @param fd the FileDescriptor for the file you want to extract from. 166 * @param offset the offset into the file where the data to be extracted starts, in bytes 167 * @param length the length in bytes of the data to be extracted 168 */ 169 public native final void setDataSource( 170 FileDescriptor fd, long offset, long length); 171 172 @Override 173 protected void finalize() { 174 native_finalize(); 175 } 176 177 /** Make sure you call this when you're done to free up any resources 178 * instead of relying on the garbage collector to do this for you at 179 * some point in the future. 180 */ 181 public native final void release(); 182 183 /** Count the number of tracks found in the data source. 184 */ 185 public native int countTracks(); 186 187 /** Get the track format at the specified index. 188 * More detail on the representation can be found at {@link android.media.MediaCodec} 189 */ 190 public native Map<String, Object> getTrackFormat(int index); 191 192 /** Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and 193 * {@link #getSampleTime} only retrieve information for the subset of tracks 194 * selected by the call below. 195 * Selecting the same track multiple times has no effect, the track 196 * only selected once. 197 * Media data will be returned in the order of their timestamps. 198 */ 199 public native void selectTrack(int index); 200 201 /** All selected tracks seek near the requested time. The next sample 202 * returned for each selected track will be a sync sample. 203 */ 204 public native void seekTo(long timeUs); 205 206 /** Advance to the next sample. Returns false if no more sample data 207 * is available (end of stream). 208 */ 209 public native boolean advance(); 210 211 /** Retrieve the current encoded sample and store it in the byte buffer 212 * starting at the given offset. Returns the sample size (or -1 if 213 * no more samples are available). 214 */ 215 public native int readSampleData(ByteBuffer byteBuf, int offset); 216 217 /** Returns the track index the current sample originates from (or -1 218 * if no more samples are available) 219 */ 220 public native int getSampleTrackIndex(); 221 222 /** Returns the current sample's presentation time in microseconds. 223 * or -1 if no more samples are available. 224 */ 225 public native long getSampleTime(); 226 227 // Keep these in sync with their equivalents in NuMediaExtractor.h 228 /** The sample is a sync sample */ 229 public static final int SAMPLE_FLAG_SYNC = 1; 230 231 /** The sample is (at least partially) encrypted, see also the documentation 232 * for {@link android.media.MediaCodec#queueSecureInputBuffer} 233 */ 234 public static final int SAMPLE_FLAG_ENCRYPTED = 2; 235 236 /** Returns the current sample's flags. */ 237 public native int getSampleFlags(); 238 239 /** If the sample flags indicate that the current sample is at least 240 * partially encrypted, this call returns relevant information about 241 * the structure of the sample data required for decryption. 242 * @param info The android.media.MediaCodec.CryptoInfo structure 243 * to be filled in. 244 * @return true iff the sample flags contain {@link #SAMPLE_FLAG_ENCRYPTED} 245 */ 246 public native boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info); 247 248 /** Returns an estimate of how much data is presently cached in memory 249 expressed in microseconds. Returns -1 if that information is unavailable 250 or not applicable (no cache). 251 */ 252 public native long getCachedDuration(); 253 254 /** Returns true iff we are caching data and the cache has reached the 255 * end of the data stream (for now, a future seek may of course restart 256 * the fetching of data). 257 * This API only returns a meaningful result if {link #getCachedDuration} 258 * indicates the presence of a cache, i.e. does NOT return -1. 259 */ 260 public native boolean hasCacheReachedEndOfStream(); 261 262 private static native final void native_init(); 263 private native final void native_setup(); 264 private native final void native_finalize(); 265 266 static { 267 System.loadLibrary("media_jni"); 268 native_init(); 269 } 270 271 private int mNativeContext; 272} 273