Merge "Squash commits of the following patches, cherry-picked from other branch - do not merge." into gingerbread

This commit is contained in:
James Dong
2011-01-14 16:27:48 -08:00
committed by Android (Google) Code Review
18 changed files with 675 additions and 341 deletions

View File

@@ -86147,6 +86147,385 @@
</parameter> </parameter>
</method> </method>
</interface> </interface>
<class name="MediaMetadataRetriever"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<constructor name="MediaMetadataRetriever"
type="android.media.MediaMetadataRetriever"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</constructor>
<method name="extractMetadata"
return="java.lang.String"
abstract="false"
native="true"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="keyCode" type="int">
</parameter>
</method>
<method name="getEmbeddedPicture"
return="byte[]"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="getFrameAtTime"
return="android.graphics.Bitmap"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="timeUs" type="long">
</parameter>
<parameter name="option" type="int">
</parameter>
</method>
<method name="getFrameAtTime"
return="android.graphics.Bitmap"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="timeUs" type="long">
</parameter>
</method>
<method name="getFrameAtTime"
return="android.graphics.Bitmap"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="release"
return="void"
abstract="false"
native="true"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="setDataSource"
return="void"
abstract="false"
native="true"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="path" type="java.lang.String">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
<method name="setDataSource"
return="void"
abstract="false"
native="true"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="fd" type="java.io.FileDescriptor">
</parameter>
<parameter name="offset" type="long">
</parameter>
<parameter name="length" type="long">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
<method name="setDataSource"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="fd" type="java.io.FileDescriptor">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
<method name="setDataSource"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="uri" type="android.net.Uri">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
<exception name="SecurityException" type="java.lang.SecurityException">
</exception>
</method>
<field name="METADATA_KEY_ALBUM"
type="int"
transient="false"
volatile="false"
value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_ALBUMARTIST"
type="int"
transient="false"
volatile="false"
value="13"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_ARTIST"
type="int"
transient="false"
volatile="false"
value="2"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_AUTHOR"
type="int"
transient="false"
volatile="false"
value="3"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_CD_TRACK_NUMBER"
type="int"
transient="false"
volatile="false"
value="0"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_COMPILATION"
type="int"
transient="false"
volatile="false"
value="15"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_COMPOSER"
type="int"
transient="false"
volatile="false"
value="4"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_DATE"
type="int"
transient="false"
volatile="false"
value="5"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_DISC_NUMBER"
type="int"
transient="false"
volatile="false"
value="14"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_DURATION"
type="int"
transient="false"
volatile="false"
value="9"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_GENRE"
type="int"
transient="false"
volatile="false"
value="6"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_MIMETYPE"
type="int"
transient="false"
volatile="false"
value="12"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_NUM_TRACKS"
type="int"
transient="false"
volatile="false"
value="10"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_TITLE"
type="int"
transient="false"
volatile="false"
value="7"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_WRITER"
type="int"
transient="false"
volatile="false"
value="11"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="METADATA_KEY_YEAR"
type="int"
transient="false"
volatile="false"
value="8"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="OPTION_CLOSEST"
type="int"
transient="false"
volatile="false"
value="3"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="OPTION_CLOSEST_SYNC"
type="int"
transient="false"
volatile="false"
value="2"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="OPTION_NEXT_SYNC"
type="int"
transient="false"
volatile="false"
value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="OPTION_PREVIOUS_SYNC"
type="int"
transient="false"
volatile="false"
value="0"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
</class>
<class name="MediaPlayer" <class name="MediaPlayer"
extends="java.lang.Object" extends="java.lang.Object"
abstract="false" abstract="false"

View File

@@ -596,21 +596,19 @@ int main(int argc, char **argv) {
const char *filename = argv[k]; const char *filename = argv[k];
CHECK_EQ(retriever->setDataSource(filename), (status_t)OK); CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
CHECK_EQ(retriever->setMode( sp<IMemory> mem =
METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL), retriever->getFrameAtTime(-1,
(status_t)OK); MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
sp<IMemory> mem = retriever->captureFrame();
if (mem != NULL) { if (mem != NULL) {
printf("captureFrame(%s) => OK\n", filename); printf("getFrameAtTime(%s) => OK\n", filename);
} else { } else {
mem = retriever->extractAlbumArt(); mem = retriever->extractAlbumArt();
if (mem != NULL) { if (mem != NULL) {
printf("extractAlbumArt(%s) => OK\n", filename); printf("extractAlbumArt(%s) => OK\n", filename);
} else { } else {
printf("both captureFrame and extractAlbumArt " printf("both getFrameAtTime and extractAlbumArt "
"failed on file '%s'.\n", filename); "failed on file '%s'.\n", filename);
} }
} }

View File

@@ -32,9 +32,7 @@ public:
virtual void disconnect() = 0; virtual void disconnect() = 0;
virtual status_t setDataSource(const char* srcUrl) = 0; virtual status_t setDataSource(const char* srcUrl) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setMode(int mode) = 0; virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option) = 0;
virtual status_t getMode(int* mode) const = 0;
virtual sp<IMemory> captureFrame() = 0;
virtual sp<IMemory> extractAlbumArt() = 0; virtual sp<IMemory> extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0; virtual const char* extractMetadata(int keyCode) = 0;
}; };

View File

@@ -32,9 +32,7 @@ public:
virtual ~MediaMetadataRetrieverBase() {} virtual ~MediaMetadataRetrieverBase() {}
virtual status_t setDataSource(const char *url) = 0; virtual status_t setDataSource(const char *url) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setMode(int mode) = 0; virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) = 0;
virtual status_t getMode(int* mode) const = 0;
virtual VideoFrame* captureFrame() = 0;
virtual MediaAlbumArt* extractAlbumArt() = 0; virtual MediaAlbumArt* extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0; virtual const char* extractMetadata(int keyCode) = 0;
}; };
@@ -43,35 +41,12 @@ public:
class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase
{ {
public: public:
MediaMetadataRetrieverInterface() MediaMetadataRetrieverInterface() {}
: mMode(0) {
}
virtual ~MediaMetadataRetrieverInterface() {} virtual ~MediaMetadataRetrieverInterface() {}
virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) { return NULL; }
// @param mode The intended mode of operations:
// can be any of the following:
// METADATA_MODE_NOOP: Experimental - just add and remove data source.
// METADATA_MODE_FRAME_CAPTURE_ONLY: For capture frame/thumbnail only.
// METADATA_MODE_METADATA_RETRIEVAL_ONLY: For meta data retrieval only.
// METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL: For both frame
// capture and meta data retrieval.
virtual status_t setMode(int mode) {
if (mode < METADATA_MODE_NOOP ||
mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
return BAD_VALUE;
}
mMode = mode;
return NO_ERROR;
}
virtual status_t getMode(int* mode) const { *mode = mMode; return NO_ERROR; }
virtual VideoFrame* captureFrame() { return NULL; }
virtual MediaAlbumArt* extractAlbumArt() { return NULL; } virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
virtual const char* extractMetadata(int keyCode) { return NULL; } virtual const char* extractMetadata(int keyCode) { return NULL; }
uint32_t mMode;
}; };
}; // namespace android }; // namespace android

View File

@@ -42,37 +42,14 @@ enum {
METADATA_KEY_YEAR = 8, METADATA_KEY_YEAR = 8,
METADATA_KEY_DURATION = 9, METADATA_KEY_DURATION = 9,
METADATA_KEY_NUM_TRACKS = 10, METADATA_KEY_NUM_TRACKS = 10,
METADATA_KEY_IS_DRM_CRIPPLED = 11, METADATA_KEY_WRITER = 11,
METADATA_KEY_CODEC = 12, METADATA_KEY_MIMETYPE = 12,
METADATA_KEY_RATING = 13, METADATA_KEY_ALBUMARTIST = 13,
METADATA_KEY_COMMENT = 14, METADATA_KEY_DISC_NUMBER = 14,
METADATA_KEY_COPYRIGHT = 15, METADATA_KEY_COMPILATION = 15,
METADATA_KEY_BIT_RATE = 16,
METADATA_KEY_FRAME_RATE = 17,
METADATA_KEY_VIDEO_FORMAT = 18,
METADATA_KEY_VIDEO_HEIGHT = 19,
METADATA_KEY_VIDEO_WIDTH = 20,
METADATA_KEY_WRITER = 21,
METADATA_KEY_MIMETYPE = 22,
METADATA_KEY_DISC_NUMBER = 23,
METADATA_KEY_ALBUMARTIST = 24,
METADATA_KEY_COMPILATION = 25,
// Add more here... // Add more here...
}; };
// The intended mode of operations:$
// METADATA_MODE_NOOP: Experimental - just add and remove data source.$
// METADATA_MODE_FRAME_CAPTURE_ONLY: For capture frame/thumbnail only.$
// METADATA_MODE_METADATA_RETRIEVAL_ONLY: For meta data retrieval only.$
// METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL: For both frame capture
// and meta data retrieval.$
enum {
METADATA_MODE_NOOP = 0x00,
METADATA_MODE_METADATA_RETRIEVAL_ONLY = 0x01,
METADATA_MODE_FRAME_CAPTURE_ONLY = 0x02,
METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL = 0x03
};
class MediaMetadataRetriever: public RefBase class MediaMetadataRetriever: public RefBase
{ {
public: public:
@@ -81,9 +58,7 @@ public:
void disconnect(); void disconnect();
status_t setDataSource(const char* dataSourceUrl); status_t setDataSource(const char* dataSourceUrl);
status_t setDataSource(int fd, int64_t offset, int64_t length); status_t setDataSource(int fd, int64_t offset, int64_t length);
status_t setMode(int mode); sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
status_t getMode(int* mode);
sp<IMemory> captureFrame();
sp<IMemory> extractAlbumArt(); sp<IMemory> extractAlbumArt();
const char* extractMetadata(int keyCode); const char* extractMetadata(int keyCode);

View File

@@ -29,7 +29,6 @@ import java.io.IOException;
/** /**
* MediaMetadataRetriever class provides a unified interface for retrieving * MediaMetadataRetriever class provides a unified interface for retrieving
* frame and meta data from an input media file. * frame and meta data from an input media file.
* {@hide}
*/ */
public class MediaMetadataRetriever public class MediaMetadataRetriever
{ {
@@ -42,40 +41,12 @@ public class MediaMetadataRetriever
@SuppressWarnings("unused") @SuppressWarnings("unused")
private int mNativeContext; private int mNativeContext;
private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF;
public MediaMetadataRetriever() { public MediaMetadataRetriever() {
native_setup(); native_setup();
} }
/**
* Call this method before setDataSource() so that the mode becomes
* effective for subsequent operations. This method can be called only once
* at the beginning if the intended mode of operation for a
* MediaMetadataRetriever object remains the same for its whole lifetime,
* and thus it is unnecessary to call this method each time setDataSource()
* is called. If this is not never called (which is allowed), by default the
* intended mode of operation is to both capture frame and retrieve meta
* data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY).
* Often, this may not be what one wants, since doing this has negative
* performance impact on execution time of a call to setDataSource(), since
* both types of operations may be time consuming.
*
* @param mode The intended mode of operation. Can be any combination of
* MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY:
* 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY:
* For neither frame capture nor meta data retrieval
* 2. MODE_GET_METADATA_ONLY: For meta data retrieval only
* 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only
* 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY:
* For both frame capture and meta data retrieval
*/
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 * Sets the data source (file pathname) to use. Call this
* method before the rest of the methods in this class. This method may be * method before the rest of the methods in this class. This method may be
@@ -190,22 +161,99 @@ public class MediaMetadataRetriever
/** /**
* Call this method after setDataSource(). This method finds a * Call this method after setDataSource(). This method finds a
* representative frame if successful and returns it as a bitmap. This is * representative frame close to the given time position by considering
* useful for generating a thumbnail for an input media source. * 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 * @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved. * 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);
}
private native Bitmap _getFrameAtTime(long timeUs, int option);
/** /**
* Call this method after setDataSource(). This method finds the optional * Call this method after setDataSource(). This method finds the optional
* graphic or album art associated (embedded or external url linked) the * graphic or album art associated associated with the data source. If
* related data source. * there are more than one pictures, (any) one of them is returned.
* *
* @return null if no such graphic is found. * @return null if no such graphic is found.
*/ */
public native byte[] extractAlbumArt(); public byte[] getEmbeddedPicture() {
return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
}
private native byte[] getEmbeddedPicture(int pictureType);
/** /**
* Call it when one is done with the object. This method releases the memory * Call it when one is done with the object. This method releases the memory
@@ -226,38 +274,129 @@ 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 option values without updating their counterparts
* in include/media/stagefright/MediaSource.h!
*/
/**
* This option is used with {@link #getFrameAtTime(long, int)} to retrieve
* a sync (or key) frame associated with a data source that is located
* right before or at the given time.
*
* @see #getFrameAtTime(long, int)
*/
public static final int OPTION_PREVIOUS_SYNC = 0x00;
/**
* This option is used with {@link #getFrameAtTime(long, int)} to retrieve
* a sync (or key) frame associated with a data source that is located
* right after or at the given time.
*
* @see #getFrameAtTime(long, int)
*/
public static final int OPTION_NEXT_SYNC = 0x01;
/**
* This option is used with {@link #getFrameAtTime(long, int)} to retrieve
* a sync (or key) frame associated with a data source that is located
* closest to (in time) or at the given time.
*
* @see #getFrameAtTime(long, int)
*/
public static final int OPTION_CLOSEST_SYNC = 0x02;
/**
* This option is used with {@link #getFrameAtTime(long, int)} to retrieve
* a frame (not necessarily a key frame) associated with a data source that
* is located closest to or at the given time.
*
* @see #getFrameAtTime(long, int)
*/
public static final int OPTION_CLOSEST = 0x03;
/* /*
* Do not change these values without updating their counterparts * Do not change these metadata key values without updating their
* in include/media/mediametadataretriever.h! * counterparts in include/media/mediametadataretriever.h!
*/
/**
* The metadata key to retrieve the numberic string describing the
* order of the audio data source on its original recording.
*/ */
public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
/**
* The metadata key to retrieve the information about the album title
* of the data source.
*/
public static final int METADATA_KEY_ALBUM = 1; public static final int METADATA_KEY_ALBUM = 1;
/**
* The metadata key to retrieve the information about the artist of
* the data source.
*/
public static final int METADATA_KEY_ARTIST = 2; public static final int METADATA_KEY_ARTIST = 2;
/**
* The metadata key to retrieve the information about the author of
* the data source.
*/
public static final int METADATA_KEY_AUTHOR = 3; public static final int METADATA_KEY_AUTHOR = 3;
/**
* The metadata key to retrieve the information about the composer of
* the data source.
*/
public static final int METADATA_KEY_COMPOSER = 4; public static final int METADATA_KEY_COMPOSER = 4;
/**
* The metadata key to retrieve the date when the data source was created
* or modified.
*/
public static final int METADATA_KEY_DATE = 5; public static final int METADATA_KEY_DATE = 5;
/**
* The metadata key to retrieve the content type or genre of the data
* source.
*/
public static final int METADATA_KEY_GENRE = 6; public static final int METADATA_KEY_GENRE = 6;
/**
* The metadata key to retrieve the data source title.
*/
public static final int METADATA_KEY_TITLE = 7; public static final int METADATA_KEY_TITLE = 7;
/**
* The metadata key to retrieve the year when the data source was created
* or modified.
*/
public static final int METADATA_KEY_YEAR = 8; public static final int METADATA_KEY_YEAR = 8;
/**
* The metadata key to retrieve the playback duration of the data source.
*/
public static final int METADATA_KEY_DURATION = 9; public static final int METADATA_KEY_DURATION = 9;
/**
* The metadata key to retrieve the number of tracks, such as audio, video,
* text, in the data source, such as a mp4 or 3gpp file.
*/
public static final int METADATA_KEY_NUM_TRACKS = 10; public static final int METADATA_KEY_NUM_TRACKS = 10;
public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11; /**
public static final int METADATA_KEY_CODEC = 12; * The metadata key to retrieve the information of the writer (such as
public static final int METADATA_KEY_RATING = 13; * lyricist) of the data source.
public static final int METADATA_KEY_COMMENT = 14; */
public static final int METADATA_KEY_COPYRIGHT = 15; public static final int METADATA_KEY_WRITER = 11;
public static final int METADATA_KEY_BIT_RATE = 16; /**
public static final int METADATA_KEY_FRAME_RATE = 17; * The metadata key to retrieve the mime type of the data source. Some
public static final int METADATA_KEY_VIDEO_FORMAT = 18; * example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb",
public static final int METADATA_KEY_VIDEO_HEIGHT = 19; * etc.
public static final int METADATA_KEY_VIDEO_WIDTH = 20; */
public static final int METADATA_KEY_WRITER = 21; public static final int METADATA_KEY_MIMETYPE = 12;
public static final int METADATA_KEY_MIMETYPE = 22; /**
public static final int METADATA_KEY_DISCNUMBER = 23; * The metadata key to retrieve the information about the performers or
public static final int METADATA_KEY_ALBUMARTIST = 24; * artist associated with the data source.
public static final int METADATA_KEY_COMPILATION = 25; */
public static final int METADATA_KEY_ALBUMARTIST = 13;
/**
* The metadata key to retrieve the numberic string that describes which
* part of a set the audio data source comes from.
*/
public static final int METADATA_KEY_DISC_NUMBER = 14;
/**
* The metadata key to retrieve the music album compilation status.
*/
public static final int METADATA_KEY_COMPILATION = 15;
// Add more here... // Add more here...
} }

View File

@@ -146,9 +146,8 @@ public class ThumbnailUtils {
Bitmap bitmap = null; Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try { try {
retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
retriever.setDataSource(filePath); retriever.setDataSource(filePath);
bitmap = retriever.captureFrame(); bitmap = retriever.getFrameAtTime(-1);
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
// Assume this is a corrupt video file // Assume this is a corrupt video file
} catch (RuntimeException ex) { } catch (RuntimeException ex) {

View File

@@ -131,33 +131,9 @@ static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jo
process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed"); process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed");
} }
static void android_media_MediaMetadataRetriever_setMode(JNIEnv *env, jobject thiz, jint mode) static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option)
{ {
LOGV("setMode"); LOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return;
}
process_media_retriever_call(env, retriever->setMode(mode), "java/lang/RuntimeException", "setMode failed");
}
static int android_media_MediaMetadataRetriever_getMode(JNIEnv *env, jobject thiz)
{
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");
MediaMetadataRetriever* retriever = getRetriever(env, thiz); MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) { if (retriever == 0) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
@@ -166,12 +142,12 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
// Call native method to retrieve a video frame // Call native method to retrieve a video frame
VideoFrame *videoFrame = NULL; 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 if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
videoFrame = static_cast<VideoFrame *>(frameMemory->pointer()); videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
} }
if (videoFrame == NULL) { if (videoFrame == NULL) {
LOGE("captureFrame: videoFrame is a NULL pointer"); LOGE("getFrameAtTime: videoFrame is a NULL pointer");
return NULL; return NULL;
} }
@@ -213,7 +189,7 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
// Create a SkBitmap to hold the pixels // Create a SkBitmap to hold the pixels
SkBitmap *bitmap = new SkBitmap(); SkBitmap *bitmap = new SkBitmap();
if (bitmap == NULL) { if (bitmap == NULL) {
LOGE("captureFrame: cannot instantiate a SkBitmap object."); LOGE("getFrameAtTime: cannot instantiate a SkBitmap object.");
return NULL; return NULL;
} }
bitmap->setConfig(SkBitmap::kRGB_565_Config, videoFrame->mDisplayWidth, videoFrame->mDisplayHeight); bitmap->setConfig(SkBitmap::kRGB_565_Config, videoFrame->mDisplayWidth, videoFrame->mDisplayHeight);
@@ -242,21 +218,26 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
false); // filter false); // filter
} }
static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *env, jobject thiz) static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture(
JNIEnv *env, jobject thiz, jint pictureType)
{ {
LOGV("extractAlbumArt"); LOGV("getEmbeddedPicture: %d", pictureType);
MediaMetadataRetriever* retriever = getRetriever(env, thiz); MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) { if (retriever == 0) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available"); jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return NULL; return NULL;
} }
MediaAlbumArt* mediaAlbumArt = NULL; MediaAlbumArt* mediaAlbumArt = NULL;
// FIXME:
// Use pictureType to retrieve the intended embedded picture and also change
// the method name to getEmbeddedPicture().
sp<IMemory> albumArtMemory = retriever->extractAlbumArt(); sp<IMemory> albumArtMemory = retriever->extractAlbumArt();
if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object
mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer()); mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer());
} }
if (mediaAlbumArt == NULL) { if (mediaAlbumArt == NULL) {
LOGE("extractAlbumArt: Call to extractAlbumArt failed."); LOGE("getEmbeddedPicture: Call to getEmbeddedPicture failed.");
return NULL; return NULL;
} }
@@ -264,7 +245,7 @@ static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *e
char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt); char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
jbyteArray array = env->NewByteArray(len); jbyteArray array = env->NewByteArray(len);
if (!array) { // OutOfMemoryError exception has already been thrown. if (!array) { // OutOfMemoryError exception has already been thrown.
LOGE("extractAlbumArt: OutOfMemoryError is thrown."); LOGE("getEmbeddedPicture: OutOfMemoryError is thrown.");
} else { } else {
jbyte* bytes = env->GetByteArrayElements(array, NULL); jbyte* bytes = env->GetByteArrayElements(array, NULL);
if (bytes != NULL) { if (bytes != NULL) {
@@ -365,11 +346,9 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje
static JNINativeMethod nativeMethods[] = { static JNINativeMethod nativeMethods[] = {
{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource}, {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD}, {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"setMode", "(I)V", (void *)android_media_MediaMetadataRetriever_setMode}, {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{"getMode", "()I", (void *)android_media_MediaMetadataRetriever_getMode},
{"captureFrame", "()Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_captureFrame},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata}, {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
{"extractAlbumArt", "()[B", (void *)android_media_MediaMetadataRetriever_extractAlbumArt}, {"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release}, {"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
{"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize}, {"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
{"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup}, {"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup},

View File

@@ -81,9 +81,7 @@ enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_DATA_SOURCE_URL, SET_DATA_SOURCE_URL,
SET_DATA_SOURCE_FD, SET_DATA_SOURCE_FD,
SET_MODE, GET_FRAME_AT_TIME,
GET_MODE,
CAPTURE_FRAME,
EXTRACT_ALBUM_ART, EXTRACT_ALBUM_ART,
EXTRACT_METADATA, EXTRACT_METADATA,
}; };
@@ -124,32 +122,17 @@ public:
return reply.readInt32(); return reply.readInt32();
} }
status_t setMode(int mode) sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
data.writeInt32(mode);
remote()->transact(SET_MODE, data, &reply);
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()
{ {
LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
Parcel data, reply; Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
data.writeInt64(timeUs);
data.writeInt32(option);
#ifndef DISABLE_GROUP_SCHEDULE_HACK #ifndef DISABLE_GROUP_SCHEDULE_HACK
sendSchedPolicy(data); sendSchedPolicy(data);
#endif #endif
remote()->transact(CAPTURE_FRAME, data, &reply); remote()->transact(GET_FRAME_AT_TIME, data, &reply);
status_t ret = reply.readInt32(); status_t ret = reply.readInt32();
if (ret != NO_ERROR) { if (ret != NO_ERROR) {
return NULL; return NULL;
@@ -216,26 +199,15 @@ status_t BnMediaMetadataRetriever::onTransact(
reply->writeInt32(setDataSource(fd, offset, length)); reply->writeInt32(setDataSource(fd, offset, length));
return NO_ERROR; return NO_ERROR;
} break; } break;
case SET_MODE: { case GET_FRAME_AT_TIME: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
int mode = data.readInt32();
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: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 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 #ifndef DISABLE_GROUP_SCHEDULE_HACK
setSchedPolicy(data); setSchedPolicy(data);
#endif #endif
sp<IMemory> bitmap = captureFrame(); sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
if (bitmap != 0) { // Don't send NULL across the binder interface if (bitmap != 0) { // Don't send NULL across the binder interface
reply->writeInt32(NO_ERROR); reply->writeInt32(NO_ERROR);
reply->writeStrongBinder(bitmap->asBinder()); reply->writeStrongBinder(bitmap->asBinder());

View File

@@ -123,37 +123,15 @@ status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t l
return mRetriever->setDataSource(fd, offset, length); return mRetriever->setDataSource(fd, offset, length);
} }
status_t MediaMetadataRetriever::setMode(int mode) sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
{ {
LOGV("setMode(%d)", mode); LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
Mutex::Autolock _l(mLock);
if (mRetriever == 0) {
LOGE("retriever is not initialized");
return INVALID_OPERATION;
}
return mRetriever->setMode(mode);
}
status_t MediaMetadataRetriever::getMode(int* mode)
{
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");
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mLock);
if (mRetriever == 0) { if (mRetriever == 0) {
LOGE("retriever is not initialized"); LOGE("retriever is not initialized");
return NULL; return NULL;
} }
return mRetriever->captureFrame(); return mRetriever->getFrameAtTime(timeUs, option);
} }
const char* MediaMetadataRetriever::extractMetadata(int keyCode) const char* MediaMetadataRetriever::extractMetadata(int keyCode)

View File

@@ -65,7 +65,6 @@ MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
mThumbnail = NULL; mThumbnail = NULL;
mAlbumArt = NULL; mAlbumArt = NULL;
mRetriever = NULL; mRetriever = NULL;
mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
} }
MetadataRetrieverClient::~MetadataRetrieverClient() MetadataRetrieverClient::~MetadataRetrieverClient()
@@ -80,7 +79,7 @@ status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) con
char buffer[SIZE]; char buffer[SIZE];
String8 result; String8 result;
result.append(" MetadataRetrieverClient\n"); result.append(" MetadataRetrieverClient\n");
snprintf(buffer, 255, " pid(%d) mode(%d)\n", mPid, mMode); snprintf(buffer, 255, " pid(%d)\n", mPid);
result.append(buffer); result.append(buffer);
write(fd, result.string(), result.size()); write(fd, result.string(), result.size());
write(fd, "\n", 1); write(fd, "\n", 1);
@@ -94,7 +93,6 @@ void MetadataRetrieverClient::disconnect()
mRetriever.clear(); mRetriever.clear();
mThumbnail.clear(); mThumbnail.clear();
mAlbumArt.clear(); mAlbumArt.clear();
mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
IPCThreadState::self()->flushCommands(); IPCThreadState::self()->flushCommands();
} }
@@ -140,10 +138,7 @@ status_t MetadataRetrieverClient::setDataSource(const char *url)
LOGV("player type = %d", playerType); LOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType); sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) return NO_INIT; if (p == NULL) return NO_INIT;
status_t ret = p->setMode(mMode); status_t ret = p->setDataSource(url);
if (ret == NO_ERROR) {
ret = p->setDataSource(url);
}
if (ret == NO_ERROR) mRetriever = p; if (ret == NO_ERROR) mRetriever = p;
return ret; return ret;
} }
@@ -181,55 +176,22 @@ status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t
::close(fd); ::close(fd);
return NO_INIT; return NO_INIT;
} }
status_t status = p->setMode(mMode); status_t status = p->setDataSource(fd, offset, length);
if (status == NO_ERROR) {
p->setDataSource(fd, offset, length);
}
if (status == NO_ERROR) mRetriever = p; if (status == NO_ERROR) mRetriever = p;
::close(fd); ::close(fd);
return status; return status;
} }
status_t MetadataRetrieverClient::setMode(int mode) sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
{ {
LOGV("setMode"); LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
Mutex::Autolock lock(mLock);
if (mode < METADATA_MODE_NOOP ||
mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
LOGE("invalid mode %d", mode);
return BAD_VALUE;
}
mMode = mode;
return NO_ERROR;
}
status_t MetadataRetrieverClient::getMode(int* mode) const
{
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");
Mutex::Autolock lock(mLock); Mutex::Autolock lock(mLock);
mThumbnail.clear(); mThumbnail.clear();
if (mRetriever == NULL) { if (mRetriever == NULL) {
LOGE("retriever is not initialized"); LOGE("retriever is not initialized");
return NULL; return NULL;
} }
VideoFrame *frame = mRetriever->captureFrame(); VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
if (frame == NULL) { if (frame == NULL) {
LOGE("failed to capture a video frame"); LOGE("failed to capture a video frame");
return NULL; return NULL;

View File

@@ -43,9 +43,7 @@ public:
virtual void disconnect(); virtual void disconnect();
virtual status_t setDataSource(const char *url); virtual status_t setDataSource(const char *url);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
virtual status_t setMode(int mode); virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
virtual status_t getMode(int* mode) const;
virtual sp<IMemory> captureFrame();
virtual sp<IMemory> extractAlbumArt(); virtual sp<IMemory> extractAlbumArt();
virtual const char* extractMetadata(int keyCode); virtual const char* extractMetadata(int keyCode);
@@ -60,7 +58,6 @@ private:
mutable Mutex mLock; mutable Mutex mLock;
sp<MediaMetadataRetrieverBase> mRetriever; sp<MediaMetadataRetrieverBase> mRetriever;
pid_t mPid; pid_t mPid;
int mMode;
// Keep the shared memory copy of album art and capture frame (for thumbnail) // Keep the shared memory copy of album art and capture frame (for thumbnail)
sp<IMemory> mAlbumArt; sp<IMemory> mAlbumArt;

View File

@@ -130,9 +130,7 @@ status_t StagefrightMediaScanner::processFile(
return HandleMIDI(path, &client); return HandleMIDI(path, &client);
} }
if (mRetriever->setDataSource(path) == OK if (mRetriever->setDataSource(path) == OK) {
&& mRetriever->setMode(
METADATA_MODE_METADATA_RETRIEVAL_ONLY) == OK) {
const char *value; const char *value;
if ((value = mRetriever->extractMetadata( if ((value = mRetriever->extractMetadata(
METADATA_KEY_MIMETYPE)) != NULL) { METADATA_KEY_MIMETYPE)) != NULL) {
@@ -181,9 +179,7 @@ char *StagefrightMediaScanner::extractAlbumArt(int fd) {
} }
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
if (mRetriever->setDataSource(fd, 0, size) == OK if (mRetriever->setDataSource(fd, 0, size) == OK) {
&& mRetriever->setMode(
METADATA_MODE_FRAME_CAPTURE_ONLY) == OK) {
sp<IMemory> mem = mRetriever->extractAlbumArt(); sp<IMemory> mem = mRetriever->extractAlbumArt();
if (mem != NULL) { if (mem != NULL) {

View File

@@ -108,7 +108,10 @@ status_t StagefrightMetadataRetriever::setDataSource(
static VideoFrame *extractVideoFrameWithCodecFlags( static VideoFrame *extractVideoFrameWithCodecFlags(
OMXClient *client, OMXClient *client,
const sp<MetaData> &trackMeta, 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 = sp<MediaSource> decoder =
OMXCodec::Create( OMXCodec::Create(
client->interface(), source->getFormat(), false, source, client->interface(), source->getFormat(), false, source,
@@ -130,11 +133,22 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
// and spurious empty buffers. // and spurious empty buffers.
MediaSource::ReadOptions options; 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; int64_t thumbNailTime;
if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) { if (frameTimeUs < 0 && trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
options.setSeekTo(thumbNailTime); options.setSeekTo(thumbNailTime, mode);
} else { } else {
thumbNailTime = -1; thumbNailTime = -1;
options.setSeekTo(frameTimeUs, mode);
} }
MediaBuffer *buffer = NULL; MediaBuffer *buffer = NULL;
@@ -226,14 +240,10 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
return frame; return frame;
} }
VideoFrame *StagefrightMetadataRetriever::captureFrame() { VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
LOGV("captureFrame"); int64_t timeUs, int option) {
if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) { LOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
LOGV("captureFrame disabled by mode (0x%08x)", mMode);
return NULL;
}
if (mExtractor.get() == NULL) { if (mExtractor.get() == NULL) {
LOGV("no extractor."); LOGV("no extractor.");
@@ -270,13 +280,15 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
VideoFrame *frame = VideoFrame *frame =
extractVideoFrameWithCodecFlags( extractVideoFrameWithCodecFlags(
&mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs); &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
timeUs, option);
if (frame == NULL) { if (frame == NULL) {
LOGV("Software decoder failed to extract thumbnail, " LOGV("Software decoder failed to extract thumbnail, "
"trying hardware decoder."); "trying hardware decoder.");
frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0); frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
timeUs, option);
} }
return frame; return frame;
@@ -285,12 +297,6 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() { MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO"); LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
LOGV("extractAlbumArt/metadata retrieval disabled by mode");
return NULL;
}
if (mExtractor == NULL) { if (mExtractor == NULL) {
return NULL; return NULL;
} }
@@ -309,12 +315,6 @@ MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
} }
const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) { const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
LOGV("extractAlbumArt/metadata retrieval disabled by mode");
return NULL;
}
if (mExtractor == NULL) { if (mExtractor == NULL) {
return NULL; return NULL;
} }

View File

@@ -35,7 +35,7 @@ struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface {
virtual status_t setDataSource(const char *url); virtual status_t setDataSource(const char *url);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length); 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 MediaAlbumArt *extractAlbumArt();
virtual const char *extractMetadata(int keyCode); virtual const char *extractMetadata(int keyCode);

View File

@@ -532,7 +532,7 @@ public class CodecTest {
e.printStackTrace(); e.printStackTrace();
return false; return false;
} }
Bitmap outThumbnail = mMediaMetadataRetriever.captureFrame(); Bitmap outThumbnail = mMediaMetadataRetriever.getFrameAtTime(-1);
//Verify the thumbnail //Verify the thumbnail
Bitmap goldenBitmap = mBitmapFactory.decodeFile(goldenPath); Bitmap goldenBitmap = mBitmapFactory.decodeFile(goldenPath);

View File

@@ -202,7 +202,6 @@ public class MediaMetadataTest extends AndroidTestCase {
} }
String value = null; String value = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
try { try {
retriever.setDataSource(meta_data_file[fileIndex][0]); retriever.setDataSource(meta_data_file[fileIndex][0]);
} catch(Exception e) { } catch(Exception e) {

View File

@@ -36,13 +36,12 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
// Test album art extraction. // Test album art extraction.
@MediumTest @MediumTest
public static void testAlbumArt() throws Exception { public static void testGetEmbeddedPicture() throws Exception {
Log.v(TAG, "testAlbumArt starts."); Log.v(TAG, "testGetEmbeddedPicture starts.");
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
boolean supportWMA = MediaProfileReader.getWMAEnable(); boolean supportWMA = MediaProfileReader.getWMAEnable();
boolean hasFailed = false; boolean hasFailed = false;
boolean supportWMV = MediaProfileReader.getWMVEnable(); boolean supportWMV = MediaProfileReader.getWMVEnable();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
for (int i = 0, n = MediaNames.ALBUMART_TEST_FILES.length; i < n; ++i) { for (int i = 0, n = MediaNames.ALBUMART_TEST_FILES.length; i < n; ++i) {
try { try {
Log.v(TAG, "File " + i + ": " + MediaNames.ALBUMART_TEST_FILES[i]); Log.v(TAG, "File " + i + ": " + MediaNames.ALBUMART_TEST_FILES[i]);
@@ -53,13 +52,13 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
continue; continue;
} }
retriever.setDataSource(MediaNames.ALBUMART_TEST_FILES[i]); retriever.setDataSource(MediaNames.ALBUMART_TEST_FILES[i]);
byte[] albumArt = retriever.extractAlbumArt(); byte[] albumArt = retriever.getEmbeddedPicture();
// TODO: // TODO:
// A better test would be to compare the retrieved album art with the // A better test would be to compare the retrieved album art with the
// known result. // known result.
if (albumArt == null) { // Do we have expect in JUnit? if (albumArt == null) { // Do we have expect in JUnit?
Log.e(TAG, "Fails to extract album art for " + MediaNames.ALBUMART_TEST_FILES[i]); Log.e(TAG, "Fails to get embedded picture for " + MediaNames.ALBUMART_TEST_FILES[i]);
hasFailed = true; hasFailed = true;
} }
} catch(Exception e) { } catch(Exception e) {
@@ -69,7 +68,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
Thread.yield(); // Don't be evil Thread.yield(); // Don't be evil
} }
retriever.release(); retriever.release();
Log.v(TAG, "testAlbumArt completes."); Log.v(TAG, "testGetEmbeddedPicture completes.");
assertTrue(!hasFailed); assertTrue(!hasFailed);
} }
@@ -92,7 +91,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
continue; continue;
} }
retriever.setDataSource(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]); retriever.setDataSource(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
Bitmap bitmap = retriever.captureFrame(); Bitmap bitmap = retriever.getFrameAtTime(-1);
assertTrue(bitmap != null); assertTrue(bitmap != null);
try { try {
java.io.OutputStream stream = new FileOutputStream(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i] + ".jpg"); java.io.OutputStream stream = new FileOutputStream(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i] + ".jpg");
@@ -120,7 +119,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
boolean supportWMV = MediaProfileReader.getWMVEnable(); boolean supportWMV = MediaProfileReader.getWMVEnable();
boolean hasFailed = false; boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
for(int i = 0, n = MediaNames.METADATA_RETRIEVAL_TEST_FILES.length; i < n; ++i) { for(int i = 0, n = MediaNames.METADATA_RETRIEVAL_TEST_FILES.length; i < n; ++i) {
try { try {
Log.v(TAG, "File " + i + ": " + MediaNames.METADATA_RETRIEVAL_TEST_FILES[i]); Log.v(TAG, "File " + i + ": " + MediaNames.METADATA_RETRIEVAL_TEST_FILES[i]);
@@ -148,12 +146,9 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
public static void testBasicNormalMethodCallSequence() throws Exception { public static void testBasicNormalMethodCallSequence() throws Exception {
boolean hasFailed = false; boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
try { try {
retriever.setDataSource(MediaNames.TEST_PATH_1); retriever.setDataSource(MediaNames.TEST_PATH_1);
/* Bitmap bitmap = retriever.getFrameAtTime(-1);
* captureFrame() fails due to lack of permission to access hardware decoder devices
Bitmap bitmap = retriever.captureFrame();
assertTrue(bitmap != null); assertTrue(bitmap != null);
try { try {
java.io.OutputStream stream = new FileOutputStream("/sdcard/thumbnailout.jpg"); java.io.OutputStream stream = new FileOutputStream("/sdcard/thumbnailout.jpg");
@@ -162,7 +157,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
} catch (Exception e) { } catch (Exception e) {
throw new Exception("Fails to convert the bitmap to a JPEG file for " + MediaNames.TEST_PATH_1, e); throw new Exception("Fails to convert the bitmap to a JPEG file for " + MediaNames.TEST_PATH_1, e);
} }
*/
extractAllSupportedMetadataValues(retriever); extractAllSupportedMetadataValues(retriever);
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Fails to setDataSource for " + MediaNames.TEST_PATH_1, e); Log.e(TAG, "Fails to setDataSource for " + MediaNames.TEST_PATH_1, e);
@@ -172,18 +166,17 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
assertTrue(!hasFailed); assertTrue(!hasFailed);
} }
// If setDataSource() has not been called, both captureFrame() and extractMetadata() must // If setDataSource() has not been called, both getFrameAtTime() and extractMetadata() must
// return null. // return null.
@MediumTest @MediumTest
public static void testBasicAbnormalMethodCallSequence() { public static void testBasicAbnormalMethodCallSequence() {
boolean hasFailed = false; boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
if (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM) != null) { if (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM) != null) {
Log.e(TAG, "No album metadata expected, but is available"); Log.e(TAG, "No album metadata expected, but is available");
hasFailed = true; hasFailed = true;
} }
if (retriever.captureFrame() != null) { if (retriever.getFrameAtTime(-1) != null) {
Log.e(TAG, "No frame expected, but is available"); Log.e(TAG, "No frame expected, but is available");
hasFailed = true; hasFailed = true;
} }
@@ -194,7 +187,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
@MediumTest @MediumTest
public static void testSetDataSource() { public static void testSetDataSource() {
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
boolean hasFailed = false; boolean hasFailed = false;
// Null pointer argument // Null pointer argument
@@ -259,14 +251,13 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
// By default, capture frame and retrieve metadata // By default, capture frame and retrieve metadata
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); MediaMetadataRetriever retriever = new MediaMetadataRetriever();
boolean hasFailed = false; boolean hasFailed = false;
// retriever.setDataSource(MediaNames.TEST_PATH_1); retriever.setDataSource(MediaNames.TEST_PATH_1);
// assertTrue(retriever.captureFrame() != null); assertTrue(retriever.getFrameAtTime(-1) != null);
// assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null); assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
// Do not capture frame or retrieve metadata // Do not capture frame or retrieve metadata
retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY & MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
retriever.setDataSource(MediaNames.TEST_PATH_1); retriever.setDataSource(MediaNames.TEST_PATH_1);
if (retriever.captureFrame() != null) { if (retriever.getFrameAtTime(-1) != null) {
Log.e(TAG, "No frame expected, but is available"); Log.e(TAG, "No frame expected, but is available");
hasFailed = true; hasFailed = true;
} }
@@ -276,23 +267,20 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
} }
// Capture frame only // Capture frame only
// retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); retriever.setDataSource(MediaNames.TEST_PATH_1);
// retriever.setDataSource(MediaNames.TEST_PATH_1); assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
// assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
// Retriever metadata only // Retriever metadata only
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
retriever.setDataSource(MediaNames.TEST_PATH_1); retriever.setDataSource(MediaNames.TEST_PATH_1);
if (retriever.captureFrame() != null) { if (retriever.getFrameAtTime(-1) != null) {
Log.e(TAG, "No frame expected, but is available"); Log.e(TAG, "No frame expected, but is available");
hasFailed = true; hasFailed = true;
} }
// Capture frame and retrieve metadata // Capture frame and retrieve metadata
// retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY | MediaMetadataRetriever.MODE_GET_METADATA_ONLY); retriever.setDataSource(MediaNames.TEST_PATH_1);
// retriever.setDataSource(MediaNames.TEST_PATH_1); assertTrue(retriever.getFrameAtTime(-1) != null);
// assertTrue(retriever.captureFrame() != null); assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
// assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
retriever.release(); retriever.release();
assertTrue(!hasFailed); assertTrue(!hasFailed);
} }