Squash commits of the following patches, cherry-picked from other branch - do not merge.
o Prepare for publishing MediaMetadataRetriever as public API step one: o replaced captureFrame with getFrameAtTime o removed getMode o Replace MediaMetadataRetriever.captureFrame() with MediaMetadataRetriever.getFrameAtTime() as part of the preparation for publishing MediaMetadataRetriever as public Java API o Remove captureFrame from MediaMetadataRetriever.java class It has been replaced by getFrameAtTime() method o Replace extractAlbumArt() with getEmbeddedPicture() in MediaMetadataRetriever.java o Publish MediaMetadataRetriever.java as public API o Removed setMode() methods and related mode constants o Removed some of the unused the metadata keys o Updated the javadoc o part of a multi-project change. bug - 3309041 Change-Id: I2efb6e8b8d52897186b016cb4efda6862f5584c4
This commit is contained in:
379
api/current.xml
379
api/current.xml
@@ -85965,6 +85965,385 @@
|
||||
</parameter>
|
||||
</method>
|
||||
</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"
|
||||
extends="java.lang.Object"
|
||||
abstract="false"
|
||||
|
||||
@@ -596,21 +596,19 @@ int main(int argc, char **argv) {
|
||||
const char *filename = argv[k];
|
||||
|
||||
CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
|
||||
CHECK_EQ(retriever->setMode(
|
||||
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);
|
||||
} else {
|
||||
mem = retriever->extractAlbumArt();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,7 @@ public:
|
||||
virtual void disconnect() = 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 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;
|
||||
};
|
||||
|
||||
@@ -32,9 +32,7 @@ public:
|
||||
virtual ~MediaMetadataRetrieverBase() {}
|
||||
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;
|
||||
};
|
||||
@@ -43,35 +41,12 @@ public:
|
||||
class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase
|
||||
{
|
||||
public:
|
||||
MediaMetadataRetrieverInterface()
|
||||
: mMode(0) {
|
||||
}
|
||||
MediaMetadataRetrieverInterface() {}
|
||||
|
||||
virtual ~MediaMetadataRetrieverInterface() {}
|
||||
|
||||
// @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 VideoFrame* getFrameAtTime(int64_t timeUs, int option) { return NULL; }
|
||||
virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
|
||||
virtual const char* extractMetadata(int keyCode) { return NULL; }
|
||||
|
||||
uint32_t mMode;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
@@ -42,37 +42,14 @@ enum {
|
||||
METADATA_KEY_YEAR = 8,
|
||||
METADATA_KEY_DURATION = 9,
|
||||
METADATA_KEY_NUM_TRACKS = 10,
|
||||
METADATA_KEY_IS_DRM_CRIPPLED = 11,
|
||||
METADATA_KEY_CODEC = 12,
|
||||
METADATA_KEY_RATING = 13,
|
||||
METADATA_KEY_COMMENT = 14,
|
||||
METADATA_KEY_COPYRIGHT = 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,
|
||||
METADATA_KEY_WRITER = 11,
|
||||
METADATA_KEY_MIMETYPE = 12,
|
||||
METADATA_KEY_ALBUMARTIST = 13,
|
||||
METADATA_KEY_DISC_NUMBER = 14,
|
||||
METADATA_KEY_COMPILATION = 15,
|
||||
// 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
|
||||
{
|
||||
public:
|
||||
@@ -81,9 +58,7 @@ public:
|
||||
void disconnect();
|
||||
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);
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.io.IOException;
|
||||
/**
|
||||
* MediaMetadataRetriever class provides a unified interface for retrieving
|
||||
* frame and meta data from an input media file.
|
||||
* {@hide}
|
||||
*/
|
||||
public class MediaMetadataRetriever
|
||||
{
|
||||
@@ -42,40 +41,12 @@ public class MediaMetadataRetriever
|
||||
@SuppressWarnings("unused")
|
||||
private int mNativeContext;
|
||||
|
||||
private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF;
|
||||
|
||||
public MediaMetadataRetriever() {
|
||||
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
|
||||
* 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
|
||||
* 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);
|
||||
}
|
||||
|
||||
private native Bitmap _getFrameAtTime(long timeUs, int option);
|
||||
|
||||
|
||||
/**
|
||||
* Call this method after setDataSource(). This method finds the optional
|
||||
* graphic or album art associated (embedded or external url linked) the
|
||||
* related data source.
|
||||
* graphic or album art associated associated with the data source. If
|
||||
* there are more than one pictures, (any) one of them is returned.
|
||||
*
|
||||
* @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
|
||||
@@ -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
|
||||
* in include/media/mediametadataretriever.h!
|
||||
* Do not change these metadata key values without updating their
|
||||
* 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;
|
||||
/**
|
||||
* The metadata key to retrieve the information about the album title
|
||||
* of the data source.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* The metadata key to retrieve the information about the author of
|
||||
* the data source.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* The metadata key to retrieve the date when the data source was created
|
||||
* or modified.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* The metadata key to retrieve the data source title.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* The metadata key to retrieve the playback duration of the data source.
|
||||
*/
|
||||
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_IS_DRM_CRIPPLED = 11;
|
||||
public static final int METADATA_KEY_CODEC = 12;
|
||||
public static final int METADATA_KEY_RATING = 13;
|
||||
public static final int METADATA_KEY_COMMENT = 14;
|
||||
public static final int METADATA_KEY_COPYRIGHT = 15;
|
||||
public static final int METADATA_KEY_BIT_RATE = 16;
|
||||
public static final int METADATA_KEY_FRAME_RATE = 17;
|
||||
public static final int METADATA_KEY_VIDEO_FORMAT = 18;
|
||||
public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
|
||||
public static final int METADATA_KEY_VIDEO_WIDTH = 20;
|
||||
public static final int METADATA_KEY_WRITER = 21;
|
||||
public static final int METADATA_KEY_MIMETYPE = 22;
|
||||
public static final int METADATA_KEY_DISCNUMBER = 23;
|
||||
public static final int METADATA_KEY_ALBUMARTIST = 24;
|
||||
public static final int METADATA_KEY_COMPILATION = 25;
|
||||
/**
|
||||
* The metadata key to retrieve the information of the writer (such as
|
||||
* lyricist) of the data source.
|
||||
*/
|
||||
public static final int METADATA_KEY_WRITER = 11;
|
||||
/**
|
||||
* The metadata key to retrieve the mime type of the data source. Some
|
||||
* example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb",
|
||||
* etc.
|
||||
*/
|
||||
public static final int METADATA_KEY_MIMETYPE = 12;
|
||||
/**
|
||||
* The metadata key to retrieve the information about the performers or
|
||||
* artist associated with the data source.
|
||||
*/
|
||||
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...
|
||||
}
|
||||
|
||||
@@ -146,9 +146,8 @@ public class ThumbnailUtils {
|
||||
Bitmap bitmap = null;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
try {
|
||||
retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
|
||||
retriever.setDataSource(filePath);
|
||||
bitmap = retriever.captureFrame();
|
||||
bitmap = retriever.getFrameAtTime(-1);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Assume this is a corrupt video file
|
||||
} catch (RuntimeException ex) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
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");
|
||||
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");
|
||||
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 +142,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 +189,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);
|
||||
@@ -242,21 +218,26 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
|
||||
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);
|
||||
if (retriever == 0) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
|
||||
return 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();
|
||||
if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object
|
||||
mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer());
|
||||
}
|
||||
if (mediaAlbumArt == NULL) {
|
||||
LOGE("extractAlbumArt: Call to extractAlbumArt failed.");
|
||||
LOGE("getEmbeddedPicture: Call to getEmbeddedPicture failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -264,7 +245,7 @@ static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *e
|
||||
char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
|
||||
jbyteArray array = env->NewByteArray(len);
|
||||
if (!array) { // OutOfMemoryError exception has already been thrown.
|
||||
LOGE("extractAlbumArt: OutOfMemoryError is thrown.");
|
||||
LOGE("getEmbeddedPicture: OutOfMemoryError is thrown.");
|
||||
} else {
|
||||
jbyte* bytes = env->GetByteArrayElements(array, NULL);
|
||||
if (bytes != NULL) {
|
||||
@@ -365,11 +346,9 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje
|
||||
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},
|
||||
{"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
|
||||
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
|
||||
{"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
|
||||
{"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup},
|
||||
|
||||
@@ -81,9 +81,7 @@ enum {
|
||||
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
|
||||
SET_DATA_SOURCE_URL,
|
||||
SET_DATA_SOURCE_FD,
|
||||
SET_MODE,
|
||||
GET_MODE,
|
||||
CAPTURE_FRAME,
|
||||
GET_FRAME_AT_TIME,
|
||||
EXTRACT_ALBUM_ART,
|
||||
EXTRACT_METADATA,
|
||||
};
|
||||
@@ -124,32 +122,17 @@ public:
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
status_t setMode(int mode)
|
||||
{
|
||||
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()
|
||||
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;
|
||||
@@ -216,26 +199,15 @@ status_t BnMediaMetadataRetriever::onTransact(
|
||||
reply->writeInt32(setDataSource(fd, offset, length));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case SET_MODE: {
|
||||
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: {
|
||||
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());
|
||||
|
||||
@@ -123,37 +123,15 @@ status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t l
|
||||
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);
|
||||
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");
|
||||
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)
|
||||
|
||||
@@ -65,7 +65,6 @@ MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
|
||||
mThumbnail = NULL;
|
||||
mAlbumArt = NULL;
|
||||
mRetriever = NULL;
|
||||
mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
|
||||
}
|
||||
|
||||
MetadataRetrieverClient::~MetadataRetrieverClient()
|
||||
@@ -80,7 +79,7 @@ status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) con
|
||||
char buffer[SIZE];
|
||||
String8 result;
|
||||
result.append(" MetadataRetrieverClient\n");
|
||||
snprintf(buffer, 255, " pid(%d) mode(%d)\n", mPid, mMode);
|
||||
snprintf(buffer, 255, " pid(%d)\n", mPid);
|
||||
result.append(buffer);
|
||||
write(fd, result.string(), result.size());
|
||||
write(fd, "\n", 1);
|
||||
@@ -94,7 +93,6 @@ void MetadataRetrieverClient::disconnect()
|
||||
mRetriever.clear();
|
||||
mThumbnail.clear();
|
||||
mAlbumArt.clear();
|
||||
mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
|
||||
IPCThreadState::self()->flushCommands();
|
||||
}
|
||||
|
||||
@@ -140,10 +138,7 @@ status_t MetadataRetrieverClient::setDataSource(const char *url)
|
||||
LOGV("player type = %d", playerType);
|
||||
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
|
||||
if (p == NULL) return NO_INIT;
|
||||
status_t ret = p->setMode(mMode);
|
||||
if (ret == NO_ERROR) {
|
||||
ret = p->setDataSource(url);
|
||||
}
|
||||
status_t ret = p->setDataSource(url);
|
||||
if (ret == NO_ERROR) mRetriever = p;
|
||||
return ret;
|
||||
}
|
||||
@@ -181,55 +176,22 @@ status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t
|
||||
::close(fd);
|
||||
return NO_INIT;
|
||||
}
|
||||
status_t status = p->setMode(mMode);
|
||||
if (status == NO_ERROR) {
|
||||
p->setDataSource(fd, offset, length);
|
||||
}
|
||||
status_t status = p->setDataSource(fd, offset, length);
|
||||
if (status == NO_ERROR) mRetriever = p;
|
||||
::close(fd);
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t MetadataRetrieverClient::setMode(int mode)
|
||||
sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
|
||||
{
|
||||
LOGV("setMode");
|
||||
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");
|
||||
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;
|
||||
|
||||
@@ -43,9 +43,7 @@ public:
|
||||
virtual void disconnect();
|
||||
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);
|
||||
|
||||
@@ -60,7 +58,6 @@ private:
|
||||
mutable Mutex mLock;
|
||||
sp<MediaMetadataRetrieverBase> mRetriever;
|
||||
pid_t mPid;
|
||||
int mMode;
|
||||
|
||||
// Keep the shared memory copy of album art and capture frame (for thumbnail)
|
||||
sp<IMemory> mAlbumArt;
|
||||
|
||||
@@ -130,9 +130,7 @@ status_t StagefrightMediaScanner::processFile(
|
||||
return HandleMIDI(path, &client);
|
||||
}
|
||||
|
||||
if (mRetriever->setDataSource(path) == OK
|
||||
&& mRetriever->setMode(
|
||||
METADATA_MODE_METADATA_RETRIEVAL_ONLY) == OK) {
|
||||
if (mRetriever->setDataSource(path) == OK) {
|
||||
const char *value;
|
||||
if ((value = mRetriever->extractMetadata(
|
||||
METADATA_KEY_MIMETYPE)) != NULL) {
|
||||
@@ -181,9 +179,7 @@ char *StagefrightMediaScanner::extractAlbumArt(int fd) {
|
||||
}
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (mRetriever->setDataSource(fd, 0, size) == OK
|
||||
&& mRetriever->setMode(
|
||||
METADATA_MODE_FRAME_CAPTURE_ONLY) == OK) {
|
||||
if (mRetriever->setDataSource(fd, 0, size) == OK) {
|
||||
sp<IMemory> mem = mRetriever->extractAlbumArt();
|
||||
|
||||
if (mem != NULL) {
|
||||
|
||||
@@ -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;
|
||||
@@ -226,14 +240,10 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
|
||||
return frame;
|
||||
}
|
||||
|
||||
VideoFrame *StagefrightMetadataRetriever::captureFrame() {
|
||||
LOGV("captureFrame");
|
||||
VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
|
||||
int64_t timeUs, int option) {
|
||||
|
||||
if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) {
|
||||
LOGV("captureFrame disabled by mode (0x%08x)", mMode);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
LOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
|
||||
|
||||
if (mExtractor.get() == NULL) {
|
||||
LOGV("no extractor.");
|
||||
@@ -270,13 +280,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;
|
||||
@@ -285,12 +297,6 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
|
||||
MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
|
||||
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) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -309,12 +315,6 @@ MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
|
||||
}
|
||||
|
||||
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) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -532,7 +532,7 @@ public class CodecTest {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
Bitmap outThumbnail = mMediaMetadataRetriever.captureFrame();
|
||||
Bitmap outThumbnail = mMediaMetadataRetriever.getFrameAtTime(-1);
|
||||
|
||||
//Verify the thumbnail
|
||||
Bitmap goldenBitmap = mBitmapFactory.decodeFile(goldenPath);
|
||||
|
||||
@@ -202,7 +202,6 @@ public class MediaMetadataTest extends AndroidTestCase {
|
||||
}
|
||||
String value = null;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
|
||||
try {
|
||||
retriever.setDataSource(meta_data_file[fileIndex][0]);
|
||||
} catch(Exception e) {
|
||||
|
||||
@@ -36,13 +36,12 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
|
||||
// Test album art extraction.
|
||||
@MediumTest
|
||||
public static void testAlbumArt() throws Exception {
|
||||
Log.v(TAG, "testAlbumArt starts.");
|
||||
public static void testGetEmbeddedPicture() throws Exception {
|
||||
Log.v(TAG, "testGetEmbeddedPicture starts.");
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
boolean supportWMA = MediaProfileReader.getWMAEnable();
|
||||
boolean hasFailed = false;
|
||||
boolean supportWMV = MediaProfileReader.getWMVEnable();
|
||||
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
|
||||
for (int i = 0, n = MediaNames.ALBUMART_TEST_FILES.length; i < n; ++i) {
|
||||
try {
|
||||
Log.v(TAG, "File " + i + ": " + MediaNames.ALBUMART_TEST_FILES[i]);
|
||||
@@ -53,13 +52,13 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
continue;
|
||||
}
|
||||
retriever.setDataSource(MediaNames.ALBUMART_TEST_FILES[i]);
|
||||
byte[] albumArt = retriever.extractAlbumArt();
|
||||
byte[] albumArt = retriever.getEmbeddedPicture();
|
||||
|
||||
// TODO:
|
||||
// A better test would be to compare the retrieved album art with the
|
||||
// known result.
|
||||
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;
|
||||
}
|
||||
} catch(Exception e) {
|
||||
@@ -69,7 +68,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
Thread.yield(); // Don't be evil
|
||||
}
|
||||
retriever.release();
|
||||
Log.v(TAG, "testAlbumArt completes.");
|
||||
Log.v(TAG, "testGetEmbeddedPicture completes.");
|
||||
assertTrue(!hasFailed);
|
||||
}
|
||||
|
||||
@@ -92,7 +91,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
continue;
|
||||
}
|
||||
retriever.setDataSource(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
|
||||
Bitmap bitmap = retriever.captureFrame();
|
||||
Bitmap bitmap = retriever.getFrameAtTime(-1);
|
||||
assertTrue(bitmap != null);
|
||||
try {
|
||||
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 hasFailed = false;
|
||||
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) {
|
||||
try {
|
||||
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 {
|
||||
boolean hasFailed = false;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
|
||||
try {
|
||||
retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
/*
|
||||
* captureFrame() fails due to lack of permission to access hardware decoder devices
|
||||
Bitmap bitmap = retriever.captureFrame();
|
||||
Bitmap bitmap = retriever.getFrameAtTime(-1);
|
||||
assertTrue(bitmap != null);
|
||||
try {
|
||||
java.io.OutputStream stream = new FileOutputStream("/sdcard/thumbnailout.jpg");
|
||||
@@ -162,7 +157,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
} catch (Exception e) {
|
||||
throw new Exception("Fails to convert the bitmap to a JPEG file for " + MediaNames.TEST_PATH_1, e);
|
||||
}
|
||||
*/
|
||||
extractAllSupportedMetadataValues(retriever);
|
||||
} catch(Exception e) {
|
||||
Log.e(TAG, "Fails to setDataSource for " + MediaNames.TEST_PATH_1, e);
|
||||
@@ -172,18 +166,17 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
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.
|
||||
@MediumTest
|
||||
public static void testBasicAbnormalMethodCallSequence() {
|
||||
boolean hasFailed = false;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
|
||||
if (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM) != null) {
|
||||
Log.e(TAG, "No album metadata expected, but is available");
|
||||
hasFailed = true;
|
||||
}
|
||||
if (retriever.captureFrame() != null) {
|
||||
if (retriever.getFrameAtTime(-1) != null) {
|
||||
Log.e(TAG, "No frame expected, but is available");
|
||||
hasFailed = true;
|
||||
}
|
||||
@@ -194,7 +187,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
@MediumTest
|
||||
public static void testSetDataSource() {
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
|
||||
boolean hasFailed = false;
|
||||
|
||||
// Null pointer argument
|
||||
@@ -259,14 +251,13 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
// By default, capture frame and retrieve metadata
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
boolean hasFailed = false;
|
||||
// retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
// assertTrue(retriever.captureFrame() != null);
|
||||
// assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
|
||||
retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
assertTrue(retriever.getFrameAtTime(-1) != null);
|
||||
assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
|
||||
|
||||
// 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);
|
||||
if (retriever.captureFrame() != null) {
|
||||
if (retriever.getFrameAtTime(-1) != null) {
|
||||
Log.e(TAG, "No frame expected, but is available");
|
||||
hasFailed = true;
|
||||
}
|
||||
@@ -276,23 +267,20 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
// Capture frame only
|
||||
// retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
|
||||
// retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
// assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
|
||||
retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
|
||||
|
||||
// Retriever metadata only
|
||||
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
|
||||
retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
if (retriever.captureFrame() != null) {
|
||||
if (retriever.getFrameAtTime(-1) != null) {
|
||||
Log.e(TAG, "No frame expected, but is available");
|
||||
hasFailed = true;
|
||||
}
|
||||
|
||||
// Capture frame and retrieve metadata
|
||||
// retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY | MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
|
||||
// retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
// assertTrue(retriever.captureFrame() != null);
|
||||
// assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
|
||||
retriever.setDataSource(MediaNames.TEST_PATH_1);
|
||||
assertTrue(retriever.getFrameAtTime(-1) != null);
|
||||
assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
|
||||
retriever.release();
|
||||
assertTrue(!hasFailed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user