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