Merge "Squash commits of the following patches, cherry-picked from other branch - do not merge." into gingerbread
This commit is contained in:
379
api/current.xml
379
api/current.xml
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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...
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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},
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user