diff options
-rw-r--r-- | cmds/stagefright/stagefright.cpp | 8 | ||||
-rw-r--r-- | include/media/IMediaMetadataRetriever.h | 3 | ||||
-rw-r--r-- | include/media/MediaMetadataRetrieverInterface.h | 5 | ||||
-rw-r--r-- | include/media/mediametadataretriever.h | 3 | ||||
-rw-r--r-- | media/java/android/media/MediaMetadataRetriever.java | 109 | ||||
-rw-r--r-- | media/jni/android_media_MediaMetadataRetriever.cpp | 26 | ||||
-rw-r--r-- | media/libmedia/IMediaMetadataRetriever.cpp | 34 | ||||
-rw-r--r-- | media/libmedia/mediametadataretriever.cpp | 17 | ||||
-rw-r--r-- | media/libmediaplayerservice/MetadataRetrieverClient.cpp | 23 | ||||
-rw-r--r-- | media/libmediaplayerservice/MetadataRetrieverClient.h | 3 | ||||
-rw-r--r-- | media/libstagefright/StagefrightMetadataRetriever.cpp | 31 | ||||
-rw-r--r-- | media/libstagefright/include/StagefrightMetadataRetriever.h | 2 |
12 files changed, 157 insertions, 107 deletions
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index 7e7f6d1..07e506a 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -681,10 +681,12 @@ int main(int argc, char **argv) { METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL), (status_t)OK); - sp<IMemory> mem = retriever->captureFrame(); + sp<IMemory> mem = + retriever->getFrameAtTime(-1, + MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); if (mem != NULL) { - printf("captureFrame(%s) => OK\n", filename); + printf("getFrameAtTime(%s) => OK\n", filename); VideoFrame *frame = (VideoFrame *)mem->pointer(); @@ -704,7 +706,7 @@ int main(int argc, char **argv) { if (mem != NULL) { printf("extractAlbumArt(%s) => OK\n", filename); } else { - printf("both captureFrame and extractAlbumArt " + printf("both getFrameAtTime and extractAlbumArt " "failed on file '%s'.\n", filename); } } diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h index 9baba8e..e517cf0 100644 --- a/include/media/IMediaMetadataRetriever.h +++ b/include/media/IMediaMetadataRetriever.h @@ -33,8 +33,7 @@ public: virtual status_t setDataSource(const char* srcUrl) = 0; virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; virtual status_t setMode(int mode) = 0; - virtual status_t getMode(int* mode) const = 0; - virtual sp<IMemory> captureFrame() = 0; + virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option) = 0; virtual sp<IMemory> extractAlbumArt() = 0; virtual const char* extractMetadata(int keyCode) = 0; }; diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h index ff57774..717849d 100644 --- a/include/media/MediaMetadataRetrieverInterface.h +++ b/include/media/MediaMetadataRetrieverInterface.h @@ -33,8 +33,7 @@ public: virtual status_t setDataSource(const char *url) = 0; virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; virtual status_t setMode(int mode) = 0; - virtual status_t getMode(int* mode) const = 0; - virtual VideoFrame* captureFrame() = 0; + virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) = 0; virtual MediaAlbumArt* extractAlbumArt() = 0; virtual const char* extractMetadata(int keyCode) = 0; }; @@ -67,7 +66,7 @@ public: } virtual status_t getMode(int* mode) const { *mode = mMode; return NO_ERROR; } - virtual VideoFrame* captureFrame() { return NULL; } + virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) { return NULL; } virtual MediaAlbumArt* extractAlbumArt() { return NULL; } virtual const char* extractMetadata(int keyCode) { return NULL; } diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h index dbbcc49..ed54b37 100644 --- a/include/media/mediametadataretriever.h +++ b/include/media/mediametadataretriever.h @@ -81,8 +81,7 @@ public: status_t setDataSource(const char* dataSourceUrl); status_t setDataSource(int fd, int64_t offset, int64_t length); status_t setMode(int mode); - status_t getMode(int* mode); - sp<IMemory> captureFrame(); + sp<IMemory> getFrameAtTime(int64_t timeUs, int option); sp<IMemory> extractAlbumArt(); const char* extractMetadata(int keyCode); diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 681751b..c92fc23 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -71,12 +71,6 @@ public class MediaMetadataRetriever public native void setMode(int mode); /** - * @return the current mode of operation. A negative return value indicates - * some runtime error has occurred. - */ - public native int getMode(); - - /** * Sets the data source (file pathname) to use. Call this * method before the rest of the methods in this class. This method may be * time-consuming. @@ -190,13 +184,94 @@ public class MediaMetadataRetriever /** * Call this method after setDataSource(). This method finds a - * representative frame if successful and returns it as a bitmap. This is - * useful for generating a thumbnail for an input media source. - * + * representative frame close to the given time position by considering + * the given option if possible, and returns it as a bitmap. This is + * useful for generating a thumbnail for an input data source or just + * obtain and display a frame at the given time position. + * + * @param timeUs The time position where the frame will be retrieved. + * When retrieving the frame at the given time position, there is no + * guarantee that the data source has a frame located at the position. + * When this happens, a frame nearby will be returned. If timeUs is + * negative, time position and option will ignored, and any frame + * that the implementation considers as representative may be returned. + * + * @param option a hint on how the frame is found. Use + * {@link OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame + * that has a timestamp earlier than or the same as timeUs. Use + * {@link OPTION_NEXT_SYNC} if one wants to retrieve a sync frame + * that has a timestamp later than or the same as timeUs. Use + * {@link OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame + * that has a timestamp closest to or the same as timeUs. Use + * {@link OPTION_CLOSEST} if one wants to retrieve a frame that may + * or may not be a sync frame but is closest to or the same as timeUs. + * {@link OPTION_CLOSEST} often has larger performance overhead compared + * to the other options if there is no sync frame located at timeUs. + * * @return A Bitmap containing a representative video frame, which * can be null, if such a frame cannot be retrieved. */ - public native Bitmap captureFrame(); + public Bitmap getFrameAtTime(long timeUs, int option) { + if (option < OPTION_PREVIOUS_SYNC || + option > OPTION_CLOSEST) { + throw new IllegalArgumentException("Unsupported option: " + option); + } + + return _getFrameAtTime(timeUs, option); + } + + /** + * Call this method after setDataSource(). This method finds a + * representative frame close to the given time position if possible, + * and returns it as a bitmap. This is useful for generating a thumbnail + * for an input data source. Call this method if one does not care + * how the frame is found as long as it is close to the given time; + * otherwise, please call {@link getFrameAtTime(long, int)}. + * + * @param timeUs The time position where the frame will be retrieved. + * When retrieving the frame at the given time position, there is no + * guarentee that the data source has a frame located at the position. + * When this happens, a frame nearby will be returned. If timeUs is + * negative, time position and option will ignored, and any frame + * that the implementation considers as representative may be returned. + * + * @return A Bitmap containing a representative video frame, which + * can be null, if such a frame cannot be retrieved. + * + * @see #getFrameAtTime(long, int) + */ + public Bitmap getFrameAtTime(long timeUs) { + return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC); + } + + /** + * Call this method after setDataSource(). This method finds a + * representative frame at any time position if possible, + * and returns it as a bitmap. This is useful for generating a thumbnail + * for an input data source. Call this method if one does not + * care about where the frame is located; otherwise, please call + * {@link getFrameAtTime(long)} or {@link getFrameAtTime(long, int)} + * + * @return A Bitmap containing a representative video frame, which + * can be null, if such a frame cannot be retrieved. + * + * @see #getFrameAtTime(long) + * @see #getFrameAtTime(long, int) + */ + public Bitmap getFrameAtTime() { + return getFrameAtTime(-1, OPTION_CLOSEST_SYNC); + } + + /** + * FIXME + * To be removed and replaced by getFrameAt(). + */ + public Bitmap captureFrame() { + return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC); + } + + private native Bitmap _getFrameAtTime(long timeUs, int option); + /** * Call this method after setDataSource(). This method finds the optional @@ -229,6 +304,20 @@ public class MediaMetadataRetriever public static final int MODE_GET_METADATA_ONLY = 0x01; public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; + /** + * Option used in method {@link getFrameAtTime(long, int)} to get a + * frame at a specified location. + * + * @see #getFrameAtTime(long, int) + */ + /* Do not change these values without updating their counterparts + * in include/media/stagefright/MediaSource.h! + */ + public static final int OPTION_PREVIOUS_SYNC = 0x00; + public static final int OPTION_NEXT_SYNC = 0x01; + public static final int OPTION_CLOSEST_SYNC = 0x02; + public static final int OPTION_CLOSEST = 0x03; + /* * Do not change these values without updating their counterparts * in include/media/mediametadataretriever.h! diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 63e9dc8..5904bfe 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -142,22 +142,9 @@ static void android_media_MediaMetadataRetriever_setMode(JNIEnv *env, jobject th process_media_retriever_call(env, retriever->setMode(mode), "java/lang/RuntimeException", "setMode failed"); } -static int android_media_MediaMetadataRetriever_getMode(JNIEnv *env, jobject thiz) +static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option) { - LOGV("getMode"); - MediaMetadataRetriever* retriever = getRetriever(env, thiz); - if (retriever == 0) { - jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); - return -1; // Error - } - int mode = -1; - retriever->getMode(&mode); - return mode; -} - -static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jobject thiz) -{ - LOGV("captureFrame"); + LOGV("getFrameAtTime: %lld us option: %d", timeUs, option); MediaMetadataRetriever* retriever = getRetriever(env, thiz); if (retriever == 0) { jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); @@ -166,12 +153,12 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo // Call native method to retrieve a video frame VideoFrame *videoFrame = NULL; - sp<IMemory> frameMemory = retriever->captureFrame(); + sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option); if (frameMemory != 0) { // cast the shared structure to a VideoFrame object videoFrame = static_cast<VideoFrame *>(frameMemory->pointer()); } if (videoFrame == NULL) { - LOGE("captureFrame: videoFrame is a NULL pointer"); + LOGE("getFrameAtTime: videoFrame is a NULL pointer"); return NULL; } @@ -213,7 +200,7 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo // Create a SkBitmap to hold the pixels SkBitmap *bitmap = new SkBitmap(); if (bitmap == NULL) { - LOGE("captureFrame: cannot instantiate a SkBitmap object."); + LOGE("getFrameAtTime: cannot instantiate a SkBitmap object."); return NULL; } bitmap->setConfig(SkBitmap::kRGB_565_Config, videoFrame->mDisplayWidth, videoFrame->mDisplayHeight); @@ -366,8 +353,7 @@ static JNINativeMethod nativeMethods[] = { {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource}, {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD}, {"setMode", "(I)V", (void *)android_media_MediaMetadataRetriever_setMode}, - {"getMode", "()I", (void *)android_media_MediaMetadataRetriever_getMode}, - {"captureFrame", "()Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_captureFrame}, + {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime}, {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata}, {"extractAlbumArt", "()[B", (void *)android_media_MediaMetadataRetriever_extractAlbumArt}, {"release", "()V", (void *)android_media_MediaMetadataRetriever_release}, diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp index e529d25..0193e25 100644 --- a/media/libmedia/IMediaMetadataRetriever.cpp +++ b/media/libmedia/IMediaMetadataRetriever.cpp @@ -82,8 +82,7 @@ enum { SET_DATA_SOURCE_URL, SET_DATA_SOURCE_FD, SET_MODE, - GET_MODE, - CAPTURE_FRAME, + GET_FRAME_AT_TIME, EXTRACT_ALBUM_ART, EXTRACT_METADATA, }; @@ -133,23 +132,17 @@ public: return reply.readInt32(); } - status_t getMode(int* mode) const - { - Parcel data, reply; - data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); - remote()->transact(GET_MODE, data, &reply); - *mode = reply.readInt32(); - return reply.readInt32(); - } - - sp<IMemory> captureFrame() + sp<IMemory> getFrameAtTime(int64_t timeUs, int option) { + LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); Parcel data, reply; data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); + data.writeInt64(timeUs); + data.writeInt32(option); #ifndef DISABLE_GROUP_SCHEDULE_HACK sendSchedPolicy(data); #endif - remote()->transact(CAPTURE_FRAME, data, &reply); + remote()->transact(GET_FRAME_AT_TIME, data, &reply); status_t ret = reply.readInt32(); if (ret != NO_ERROR) { return NULL; @@ -222,20 +215,15 @@ status_t BnMediaMetadataRetriever::onTransact( reply->writeInt32(setMode(mode)); return NO_ERROR; } break; - case GET_MODE: { - CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); - int mode; - status_t status = getMode(&mode); - reply->writeInt32(mode); - reply->writeInt32(status); - return NO_ERROR; - } break; - case CAPTURE_FRAME: { + case GET_FRAME_AT_TIME: { CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); + int64_t timeUs = data.readInt64(); + int option = data.readInt32(); + LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); #ifndef DISABLE_GROUP_SCHEDULE_HACK setSchedPolicy(data); #endif - sp<IMemory> bitmap = captureFrame(); + sp<IMemory> bitmap = getFrameAtTime(timeUs, option); if (bitmap != 0) { // Don't send NULL across the binder interface reply->writeInt32(NO_ERROR); reply->writeStrongBinder(bitmap->asBinder()); diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index e2712ba..39b5bc3 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -134,26 +134,15 @@ status_t MediaMetadataRetriever::setMode(int mode) return mRetriever->setMode(mode); } -status_t MediaMetadataRetriever::getMode(int* mode) +sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option) { - LOGV("getMode"); - Mutex::Autolock _l(mLock); - if (mRetriever == 0) { - LOGE("retriever is not initialized"); - return INVALID_OPERATION; - } - return mRetriever->getMode(mode); -} - -sp<IMemory> MediaMetadataRetriever::captureFrame() -{ - LOGV("captureFrame"); + LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option); Mutex::Autolock _l(mLock); if (mRetriever == 0) { LOGE("retriever is not initialized"); return NULL; } - return mRetriever->captureFrame(); + return mRetriever->getFrameAtTime(timeUs, option); } const char* MediaMetadataRetriever::extractMetadata(int keyCode) diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index b069345..abaec02 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -196,33 +196,16 @@ status_t MetadataRetrieverClient::setMode(int mode) return NO_ERROR; } -status_t MetadataRetrieverClient::getMode(int* mode) const +sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option) { - LOGV("getMode"); - Mutex::Autolock lock(mLock); - - // TODO: - // This may not be necessary. - // If setDataSource() has not been called, return the cached value - // otherwise, return the value retrieved from the retriever - if (mRetriever == NULL) { - *mode = mMode; - } else { - mRetriever->getMode(mode); - } - return NO_ERROR; -} - -sp<IMemory> MetadataRetrieverClient::captureFrame() -{ - LOGV("captureFrame"); + LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option); Mutex::Autolock lock(mLock); mThumbnail.clear(); if (mRetriever == NULL) { LOGE("retriever is not initialized"); return NULL; } - VideoFrame *frame = mRetriever->captureFrame(); + VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option); if (frame == NULL) { LOGE("failed to capture a video frame"); return NULL; diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h index 4aab94f..8b4c0c7 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.h +++ b/media/libmediaplayerservice/MetadataRetrieverClient.h @@ -44,8 +44,7 @@ public: virtual status_t setDataSource(const char *url); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual status_t setMode(int mode); - virtual status_t getMode(int* mode) const; - virtual sp<IMemory> captureFrame(); + virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option); virtual sp<IMemory> extractAlbumArt(); virtual const char* extractMetadata(int keyCode); diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 763a914..c28de93 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -108,7 +108,10 @@ status_t StagefrightMetadataRetriever::setDataSource( static VideoFrame *extractVideoFrameWithCodecFlags( OMXClient *client, const sp<MetaData> &trackMeta, - const sp<MediaSource> &source, uint32_t flags) { + const sp<MediaSource> &source, + uint32_t flags, + int64_t frameTimeUs, + int seekMode) { sp<MediaSource> decoder = OMXCodec::Create( client->interface(), source->getFormat(), false, source, @@ -130,11 +133,22 @@ static VideoFrame *extractVideoFrameWithCodecFlags( // and spurious empty buffers. MediaSource::ReadOptions options; + if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC || + seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) { + + LOGE("Unknown seek mode: %d", seekMode); + return NULL; + } + + MediaSource::ReadOptions::SeekMode mode = + static_cast<MediaSource::ReadOptions::SeekMode>(seekMode); + int64_t thumbNailTime; - if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) { - options.setSeekTo(thumbNailTime); + if (frameTimeUs < 0 && trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) { + options.setSeekTo(thumbNailTime, mode); } else { thumbNailTime = -1; + options.setSeekTo(frameTimeUs, mode); } MediaBuffer *buffer = NULL; @@ -238,9 +252,10 @@ static VideoFrame *extractVideoFrameWithCodecFlags( return frame; } -VideoFrame *StagefrightMetadataRetriever::captureFrame() { - LOGV("captureFrame"); +VideoFrame *StagefrightMetadataRetriever::getFrameAtTime( + int64_t timeUs, int option) { + LOGV("getFrameAtTime: %lld us option: %d", timeUs, option); if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) { LOGV("captureFrame disabled by mode (0x%08x)", mMode); @@ -282,13 +297,15 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() { VideoFrame *frame = extractVideoFrameWithCodecFlags( - &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs); + &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs, + timeUs, option); if (frame == NULL) { LOGV("Software decoder failed to extract thumbnail, " "trying hardware decoder."); - frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0); + frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0, + timeUs, option); } return frame; diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h index b80387f..07b1ec8 100644 --- a/media/libstagefright/include/StagefrightMetadataRetriever.h +++ b/media/libstagefright/include/StagefrightMetadataRetriever.h @@ -35,7 +35,7 @@ struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface { virtual status_t setDataSource(const char *url); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); - virtual VideoFrame *captureFrame(); + virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option); virtual MediaAlbumArt *extractAlbumArt(); virtual const char *extractMetadata(int keyCode); |