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