MediaMetadataRetriever.java revision faf09ba9405ff019b5ca7e2317debe4ff269d4f8
1/* 2 * Copyright (C) 2008 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.graphics.Bitmap; 23import android.net.Uri; 24 25import java.io.FileDescriptor; 26import java.io.FileNotFoundException; 27import java.io.IOException; 28 29/** 30 * MediaMetadataRetriever class provides a unified interface for retrieving 31 * frame and meta data from an input media file. 32 * {@hide} 33 */ 34public class MediaMetadataRetriever 35{ 36 static { 37 System.loadLibrary("media_jni"); 38 native_init(); 39 } 40 41 // The field below is accessed by native methods 42 @SuppressWarnings("unused") 43 private int mNativeContext; 44 45 public MediaMetadataRetriever() { 46 native_setup(); 47 } 48 49 /** 50 * Call this method before setDataSource() so that the mode becomes 51 * effective for subsequent operations. This method can be called only once 52 * at the beginning if the intended mode of operation for a 53 * MediaMetadataRetriever object remains the same for its whole lifetime, 54 * and thus it is unnecessary to call this method each time setDataSource() 55 * is called. If this is not never called (which is allowed), by default the 56 * intended mode of operation is to both capture frame and retrieve meta 57 * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). 58 * Often, this may not be what one wants, since doing this has negative 59 * performance impact on execution time of a call to setDataSource(), since 60 * both types of operations may be time consuming. 61 * 62 * @param mode The intended mode of operation. Can be any combination of 63 * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: 64 * 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: 65 * For neither frame capture nor meta data retrieval 66 * 2. MODE_GET_METADATA_ONLY: For meta data retrieval only 67 * 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only 68 * 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: 69 * For both frame capture and meta data retrieval 70 */ 71 public native void setMode(int mode); 72 73 /** 74 * Sets the data source (file pathname) to use. Call this 75 * method before the rest of the methods in this class. This method may be 76 * time-consuming. 77 * 78 * @param path The path of the input media file. 79 * @throws IllegalArgumentException If the path is invalid. 80 */ 81 public native void setDataSource(String path) throws IllegalArgumentException; 82 83 /** 84 * Sets the data source (FileDescriptor) to use. It is the caller's 85 * responsibility to close the file descriptor. It is safe to do so as soon 86 * as this call returns. Call this method before the rest of the methods in 87 * this class. This method may be time-consuming. 88 * 89 * @param fd the FileDescriptor for the file you want to play 90 * @param offset the offset into the file where the data to be played starts, 91 * in bytes. It must be non-negative 92 * @param length the length in bytes of the data to be played. It must be 93 * non-negative. 94 * @throws IllegalArgumentException if the arguments are invalid 95 */ 96 public native void setDataSource(FileDescriptor fd, long offset, long length) 97 throws IllegalArgumentException; 98 99 /** 100 * Sets the data source (FileDescriptor) to use. It is the caller's 101 * responsibility to close the file descriptor. It is safe to do so as soon 102 * as this call returns. Call this method before the rest of the methods in 103 * this class. This method may be time-consuming. 104 * 105 * @param fd the FileDescriptor for the file you want to play 106 * @throws IllegalArgumentException if the FileDescriptor is invalid 107 */ 108 public void setDataSource(FileDescriptor fd) 109 throws IllegalArgumentException { 110 // intentionally less than LONG_MAX 111 setDataSource(fd, 0, 0x7ffffffffffffffL); 112 } 113 114 /** 115 * Sets the data source as a content Uri. Call this method before 116 * the rest of the methods in this class. This method may be time-consuming. 117 * 118 * @param context the Context to use when resolving the Uri 119 * @param uri the Content URI of the data you want to play 120 * @throws IllegalArgumentException if the Uri is invalid 121 * @throws SecurityException if the Uri cannot be used due to lack of 122 * permission. 123 */ 124 public void setDataSource(Context context, Uri uri) 125 throws IllegalArgumentException, SecurityException { 126 if (uri == null) { 127 throw new IllegalArgumentException(); 128 } 129 130 String scheme = uri.getScheme(); 131 if(scheme == null || scheme.equals("file")) { 132 setDataSource(uri.getPath()); 133 return; 134 } 135 136 AssetFileDescriptor fd = null; 137 try { 138 ContentResolver resolver = context.getContentResolver(); 139 try { 140 fd = resolver.openAssetFileDescriptor(uri, "r"); 141 } catch(FileNotFoundException e) { 142 throw new IllegalArgumentException(); 143 } 144 if (fd == null) { 145 throw new IllegalArgumentException(); 146 } 147 FileDescriptor descriptor = fd.getFileDescriptor(); 148 if (!descriptor.valid()) { 149 throw new IllegalArgumentException(); 150 } 151 // Note: using getDeclaredLength so that our behavior is the same 152 // as previous versions when the content provider is returning 153 // a full file. 154 if (fd.getDeclaredLength() < 0) { 155 setDataSource(descriptor); 156 } else { 157 setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength()); 158 } 159 return; 160 } catch (SecurityException ex) { 161 } finally { 162 try { 163 if (fd != null) { 164 fd.close(); 165 } 166 } catch(IOException ioEx) { 167 } 168 } 169 setDataSource(uri.toString()); 170 } 171 172 /** 173 * Call this method after setDataSource(). This method retrieves the 174 * meta data value associated with the keyCode. 175 * 176 * The keyCode currently supported is listed below as METADATA_XXX 177 * constants. With any other value, it returns a null pointer. 178 * 179 * @param keyCode One of the constants listed below at the end of the class. 180 * @return The meta data value associate with the given keyCode on success; 181 * null on failure. 182 */ 183 public native String extractMetadata(int keyCode); 184 185 /** 186 * Call this method after setDataSource(). This method finds a 187 * representative frame close to the given time position by considering 188 * the given option if possible, and returns it as a bitmap. This is 189 * useful for generating a thumbnail for an input data source or just 190 * obtain and display a frame at the given time position. 191 * 192 * @param timeUs The time position where the frame will be retrieved. 193 * When retrieving the frame at the given time position, there is no 194 * guarantee that the data source has a frame located at the position. 195 * When this happens, a frame nearby will be returned. If timeUs is 196 * negative, time position and option will ignored, and any frame 197 * that the implementation considers as representative may be returned. 198 * 199 * @param option a hint on how the frame is found. Use 200 * {@link OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame 201 * that has a timestamp earlier than or the same as timeUs. Use 202 * {@link OPTION_NEXT_SYNC} if one wants to retrieve a sync frame 203 * that has a timestamp later than or the same as timeUs. Use 204 * {@link OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame 205 * that has a timestamp closest to or the same as timeUs. Use 206 * {@link OPTION_CLOSEST} if one wants to retrieve a frame that may 207 * or may not be a sync frame but is closest to or the same as timeUs. 208 * {@link OPTION_CLOSEST} often has larger performance overhead compared 209 * to the other options if there is no sync frame located at timeUs. 210 * 211 * @return A Bitmap containing a representative video frame, which 212 * can be null, if such a frame cannot be retrieved. 213 */ 214 public Bitmap getFrameAtTime(long timeUs, int option) { 215 if (option < OPTION_PREVIOUS_SYNC || 216 option > OPTION_CLOSEST) { 217 throw new IllegalArgumentException("Unsupported option: " + option); 218 } 219 220 return _getFrameAtTime(timeUs, option); 221 } 222 223 /** 224 * Call this method after setDataSource(). This method finds a 225 * representative frame close to the given time position if possible, 226 * and returns it as a bitmap. This is useful for generating a thumbnail 227 * for an input data source. Call this method if one does not care 228 * how the frame is found as long as it is close to the given time; 229 * otherwise, please call {@link getFrameAtTime(long, int)}. 230 * 231 * @param timeUs The time position where the frame will be retrieved. 232 * When retrieving the frame at the given time position, there is no 233 * guarentee that the data source has a frame located at the position. 234 * When this happens, a frame nearby will be returned. If timeUs is 235 * negative, time position and option will ignored, and any frame 236 * that the implementation considers as representative may be returned. 237 * 238 * @return A Bitmap containing a representative video frame, which 239 * can be null, if such a frame cannot be retrieved. 240 * 241 * @see #getFrameAtTime(long, int) 242 */ 243 public Bitmap getFrameAtTime(long timeUs) { 244 return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC); 245 } 246 247 /** 248 * Call this method after setDataSource(). This method finds a 249 * representative frame at any time position if possible, 250 * and returns it as a bitmap. This is useful for generating a thumbnail 251 * for an input data source. Call this method if one does not 252 * care about where the frame is located; otherwise, please call 253 * {@link getFrameAtTime(long)} or {@link getFrameAtTime(long, int)} 254 * 255 * @return A Bitmap containing a representative video frame, which 256 * can be null, if such a frame cannot be retrieved. 257 * 258 * @see #getFrameAtTime(long) 259 * @see #getFrameAtTime(long, int) 260 */ 261 public Bitmap getFrameAtTime() { 262 return getFrameAtTime(-1, OPTION_CLOSEST_SYNC); 263 } 264 265 /** 266 * FIXME 267 * To be removed and replaced by getFrameAt(). 268 */ 269 public Bitmap captureFrame() { 270 return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC); 271 } 272 273 private native Bitmap _getFrameAtTime(long timeUs, int option); 274 275 276 /** 277 * Call this method after setDataSource(). This method finds the optional 278 * graphic or album art associated (embedded or external url linked) the 279 * related data source. 280 * 281 * @return null if no such graphic is found. 282 */ 283 public native byte[] extractAlbumArt(); 284 285 /** 286 * Call it when one is done with the object. This method releases the memory 287 * allocated internally. 288 */ 289 public native void release(); 290 private native void native_setup(); 291 private static native void native_init(); 292 293 private native final void native_finalize(); 294 295 @Override 296 protected void finalize() throws Throwable { 297 try { 298 native_finalize(); 299 } finally { 300 super.finalize(); 301 } 302 } 303 304 public static final int MODE_GET_METADATA_ONLY = 0x01; 305 public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; 306 307 /** 308 * Option used in method {@link getFrameAtTime(long, int)} to get a 309 * frame at a specified location. 310 * 311 * @see #getFrameAtTime(long, int) 312 */ 313 /* Do not change these values without updating their counterparts 314 * in include/media/stagefright/MediaSource.h! 315 */ 316 public static final int OPTION_PREVIOUS_SYNC = 0x00; 317 public static final int OPTION_NEXT_SYNC = 0x01; 318 public static final int OPTION_CLOSEST_SYNC = 0x02; 319 public static final int OPTION_CLOSEST = 0x03; 320 321 /* 322 * Do not change these values without updating their counterparts 323 * in include/media/mediametadataretriever.h! 324 */ 325 public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; 326 public static final int METADATA_KEY_ALBUM = 1; 327 public static final int METADATA_KEY_ARTIST = 2; 328 public static final int METADATA_KEY_AUTHOR = 3; 329 public static final int METADATA_KEY_COMPOSER = 4; 330 public static final int METADATA_KEY_DATE = 5; 331 public static final int METADATA_KEY_GENRE = 6; 332 public static final int METADATA_KEY_TITLE = 7; 333 public static final int METADATA_KEY_YEAR = 8; 334 public static final int METADATA_KEY_DURATION = 9; 335 public static final int METADATA_KEY_NUM_TRACKS = 10; 336 public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11; 337 public static final int METADATA_KEY_CODEC = 12; 338 public static final int METADATA_KEY_RATING = 13; 339 public static final int METADATA_KEY_COMMENT = 14; 340 public static final int METADATA_KEY_COPYRIGHT = 15; 341 public static final int METADATA_KEY_BIT_RATE = 16; 342 public static final int METADATA_KEY_FRAME_RATE = 17; 343 public static final int METADATA_KEY_VIDEO_FORMAT = 18; 344 public static final int METADATA_KEY_VIDEO_HEIGHT = 19; 345 public static final int METADATA_KEY_VIDEO_WIDTH = 20; 346 public static final int METADATA_KEY_WRITER = 21; 347 public static final int METADATA_KEY_MIMETYPE = 22; 348 public static final int METADATA_KEY_DISCNUMBER = 23; 349 public static final int METADATA_KEY_ALBUMARTIST = 24; 350 // Add more here... 351} 352