1520 lines
57 KiB
C++
Executable File
1520 lines
57 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
|
|
* All rights reserved.
|
|
*
|
|
* File : awmetadataretriever.cpp
|
|
* Description : metadataretriever
|
|
* History :
|
|
*
|
|
*/
|
|
|
|
#define LOG_TAG "awmetadataretriever"
|
|
#include "cdx_log.h"
|
|
|
|
#include "awmetadataretriever.h"
|
|
#include "memoryAdapter.h"
|
|
//#include <AwPluginManager.h>
|
|
#include <stdio.h>
|
|
#include <binder/MemoryBase.h>
|
|
#include <binder/MemoryHeapBase.h>
|
|
#include <private/media/VideoFrame.h>
|
|
|
|
#if (CONF_ANDROID_MAJOR_VER >= 5)
|
|
#include "media/CharacterEncodingDetector.h"
|
|
#endif
|
|
|
|
#include "unicode/ucnv.h"
|
|
#include "unicode/ustring.h"
|
|
#include <cutils/properties.h>
|
|
|
|
//#include "vdecoder.h" //* video decode library in "LIBRARY/CODEC/VIDEO/DECODER"
|
|
//#include "CdxParser.h" //* parser library in "LIBRARY/DEMUX/PARSER/include/"
|
|
//#include "CdxStream.h" //* parser library in "LIBRARY/DEMUX/STREAM/include/"
|
|
#include <iniparserapi.h>
|
|
#include "xmetadataretriever.h"
|
|
|
|
#define MediaScanDedug (0)
|
|
|
|
struct Map {
|
|
int from;
|
|
int to;
|
|
const char *name;
|
|
};
|
|
|
|
static const Map kMap[] = {
|
|
{ kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL },
|
|
{ kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" },
|
|
{ kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" },
|
|
{ kKeyAlbum, METADATA_KEY_ALBUM, "album" },
|
|
{ kKeyArtist, METADATA_KEY_ARTIST, "artist" },
|
|
{ kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" },
|
|
{ kKeyAuthor, METADATA_KEY_AUTHOR, NULL },
|
|
{ kKeyComposer, METADATA_KEY_COMPOSER, "composer" },
|
|
{ kKeyDate, METADATA_KEY_DATE, NULL },
|
|
{ kKeyGenre, METADATA_KEY_GENRE, "genre" },
|
|
{ kKeyTitle, METADATA_KEY_TITLE, "title" },
|
|
{ kKeyYear, METADATA_KEY_YEAR, "year" },
|
|
{ kKeyWriter, METADATA_KEY_WRITER, "writer" },
|
|
{ kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" },
|
|
{ kKeyLocation, METADATA_KEY_LOCATION, NULL },
|
|
};
|
|
|
|
static cdx_int32 kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
|
|
|
|
#if SAVE_BITSTREAM
|
|
const char* bitstreamPath = "/data/camera/out.h264";
|
|
static FILE* fph264 = NULL;
|
|
#endif
|
|
|
|
/* process 4096 packets to get a frame at maximum. */
|
|
#define MAX_PACKET_COUNT_TO_GET_A_FRAME 4096
|
|
|
|
/* use 5 seconds to get a frame at maximum. */
|
|
#define MAX_TIME_TO_GET_A_FRAME 5000000
|
|
|
|
/* use 10 seconds to get a stream at maximum. */
|
|
#define MAX_TIME_TO_GET_A_STREAM 10000000
|
|
#define MAX_OUTPUT_STREAM_SIZE (1024*1024)
|
|
|
|
typedef struct MetadataPriData{
|
|
CdxDataSourceT mSource;
|
|
CdxMediaInfoT mMediaInfo;
|
|
int mCancelPrepareFlag;
|
|
MediaAlbumArt* mAlbumArtPic;
|
|
KeyedVector<int, String8>* mMetaData;
|
|
#if MediaScanDedug
|
|
int mFd;
|
|
#endif
|
|
XRetriever *mXRetriever;
|
|
CdxKeyedVectorT *mHeader;
|
|
}MetadataPriData;
|
|
|
|
static int parseHeaders(CdxKeyedVectorT **header, char *uri,
|
|
KeyedVector<String8, String8>* pHeaders);
|
|
static void clearHeaders(CdxKeyedVectorT **header);
|
|
|
|
static int64_t GetSysTime();
|
|
static int transfromId3Info(String8* mStringId3, cdx_uint8* pData, cdx_int32 nSize,
|
|
cdx_int32 nEncodeTpye, cdx_int32 flag);
|
|
|
|
AwMetadataRetriever::AwMetadataRetriever()
|
|
{
|
|
logd("AwMetadataRetriever Create.");
|
|
//AwPluginInit();
|
|
//TODO: add plugin in config proc
|
|
mPriData = (MetadataPriData*)malloc(sizeof(MetadataPriData));
|
|
memset(mPriData,0x00,sizeof(MetadataPriData));
|
|
mPriData->mCancelPrepareFlag = 0;
|
|
mPriData->mAlbumArtPic = NULL;
|
|
#if MediaScanDedug
|
|
mPriData->mFd = 0;
|
|
#endif
|
|
memset(&mPriData->mSource, 0, sizeof(CdxDataSourceT));
|
|
|
|
mPriData->mMetaData = new KeyedVector<int, String8>();
|
|
|
|
mPriData->mXRetriever = XRetrieverCreate();
|
|
if (mPriData->mXRetriever == NULL)
|
|
{
|
|
loge("XRetrieverCreate failed.");
|
|
if (mPriData->mMetaData)
|
|
{
|
|
delete mPriData->mMetaData;
|
|
mPriData->mMetaData = NULL;
|
|
}
|
|
free(mPriData);
|
|
mPriData = NULL;
|
|
}
|
|
}
|
|
|
|
AwMetadataRetriever::~AwMetadataRetriever()
|
|
{
|
|
mPriData->mCancelPrepareFlag = 1;
|
|
clear();
|
|
|
|
if (mPriData->mMetaData)
|
|
{
|
|
delete mPriData->mMetaData;
|
|
mPriData->mMetaData = NULL;
|
|
}
|
|
|
|
if (mPriData->mXRetriever)
|
|
{
|
|
XRetrieverDestory(mPriData->mXRetriever);
|
|
}
|
|
|
|
if (mPriData)
|
|
{
|
|
free(mPriData);
|
|
mPriData = NULL;
|
|
}
|
|
logi("AwMetadataRetriever destroyed.");
|
|
}
|
|
|
|
void AwMetadataRetriever::clear()
|
|
{
|
|
//* set mCancelPrepareFlag to force the CdxParserPrepare() quit.
|
|
//* this can prevend the setDataSource() operation from blocking at a network io.
|
|
//* but the retriever's setDataSource() method is a synchronize operation, so I think
|
|
//* this take no effect, because user can not return from setDataSource() to call this
|
|
//* method if user's thread is blocked at the setDataSource() operation.
|
|
|
|
if(mPriData->mAlbumArtPic != NULL)
|
|
{
|
|
delete mPriData->mAlbumArtPic;
|
|
mPriData->mAlbumArtPic = NULL;
|
|
}
|
|
|
|
clearHeaders(&mPriData->mHeader);
|
|
memset(&mPriData->mMediaInfo, 0, sizeof(CdxMediaInfoT));
|
|
mPriData->mMetaData->clear();
|
|
|
|
#if MediaScanDedug
|
|
mPriData->mFd = -1;
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
#if (CONF_ANDROID_MAJOR_VER >= 5)
|
|
status_t AwMetadataRetriever::setDataSource(const sp<IMediaHTTPService> &httpService,
|
|
const char* pUrl, const KeyedVector<String8, String8>* pHeaders)
|
|
#else
|
|
status_t AwMetadataRetriever::setDataSource(const char* pUrl,
|
|
const KeyedVector<String8, String8>* pHeaders)
|
|
#endif
|
|
{
|
|
int ret = 0;
|
|
|
|
#if (CONF_ANDROID_MAJOR_VER >= 5)
|
|
CEDARX_UNUSE(httpService);
|
|
#endif
|
|
|
|
logd("set data source, url = %s", pUrl);
|
|
clear(); //* release parser, decoder and other resource for previous file.
|
|
|
|
//* 1. parse pHeaders.
|
|
ret = parseHeaders(&mPriData->mHeader, (char*)pUrl, (KeyedVector<String8, String8>*)pHeaders);
|
|
if (ret < 0)
|
|
{
|
|
loge("parseHeaders failed.");
|
|
return NO_MEMORY;
|
|
}
|
|
|
|
//* 2. XRetriever set datasource.
|
|
ret = XRetrieverSetDataSource(mPriData->mXRetriever, pUrl, mPriData->mHeader);
|
|
if (ret < 0)
|
|
{
|
|
loge("XRetrieverSetDataSource failed.");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
XRetrieverGetMetaData(mPriData->mXRetriever, METADATA_MEDIAINFO, &mPriData->mMediaInfo);
|
|
|
|
storeMetadata();
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t AwMetadataRetriever::setDataSource(int fd, int64_t nOffset, int64_t nLength)
|
|
{
|
|
char str[128];
|
|
int ret = 0;
|
|
|
|
clear(); //* release parser, decoder and other resource for previous file.
|
|
logd("set data source, fd = %d", fd);
|
|
#if MediaScanDedug
|
|
mPriData->mFd = fd;
|
|
#endif
|
|
|
|
//* 1. set the datasource object.
|
|
sprintf(str, "fd://%d?offset=%ld&length=%ld", fd, (long int)nOffset, (long int)nLength);
|
|
|
|
ret = XRetrieverSetDataSource(mPriData->mXRetriever, str, mPriData->mHeader);
|
|
if (ret < 0)
|
|
{
|
|
loge("XRetrieverSetDataSource failed.");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
XRetrieverGetMetaData(mPriData->mXRetriever, METADATA_MEDIAINFO, &mPriData->mMediaInfo);
|
|
|
|
storeMetadata();
|
|
|
|
return OK;
|
|
}
|
|
|
|
#if (CONF_ANDROID_MAJOR_VER >= 6)
|
|
status_t AwMetadataRetriever::setDataSource(const sp<DataSource>& source)
|
|
{
|
|
CEDARX_UNUSE(source);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
#endif
|
|
|
|
void AwMetadataRetriever::storeMetadata(void)
|
|
{
|
|
int i;
|
|
char tmp[256];
|
|
int nStrLen = 0;
|
|
String8 mStrData;
|
|
if(mPriData->mMediaInfo.pAlbumArtBuf != NULL &&
|
|
mPriData->mMediaInfo.nAlbumArtBufSize > 0 &&
|
|
mPriData->mAlbumArtPic == NULL)
|
|
{
|
|
#if (CONF_ANDROID_MAJOR_VER >= 5)
|
|
mPriData->mAlbumArtPic = MediaAlbumArt::fromData(mPriData->mMediaInfo.nAlbumArtBufSize,
|
|
mPriData->mMediaInfo.pAlbumArtBuf);
|
|
#else
|
|
mPriData->mAlbumArtPic = new MediaAlbumArt;
|
|
mPriData->mAlbumArtPic->mSize = mPriData->mMediaInfo.nAlbumArtBufSize;
|
|
mPriData->mAlbumArtPic->mData = new uint8_t[mPriData->mMediaInfo.nAlbumArtBufSize];
|
|
memcpy(mPriData->mAlbumArtPic->mData, mPriData->mMediaInfo.pAlbumArtBuf,
|
|
mPriData->mMediaInfo.nAlbumArtBufSize);
|
|
#endif
|
|
}
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the numeric string describing the
|
|
//* * order of the audio data source on its original recording.
|
|
//* */
|
|
//* public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_CD_TRACK_NUMBER, String8("0"));
|
|
//* no information to give the order of the audio
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "TRACKNUMBER";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TRK" or "TRCK";
|
|
//* mov file may contain this information in its metadata, index by FOURCC 't' 'r' 'k' 'n';
|
|
#endif
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the information about the album title
|
|
//* * of the data source.
|
|
//* */
|
|
//* public static final int METADATA_KEY_ALBUM = 1;
|
|
//nStrLen = strlen((const char*)mMediaInfo.album);
|
|
nStrLen = mPriData->mMediaInfo.albumsz;
|
|
if(nStrLen > 0)
|
|
{
|
|
logv("METADATA_KEY_ALBUM:%d",nStrLen);
|
|
transfromId3Info(&mStrData, mPriData->mMediaInfo.album, mPriData->mMediaInfo.albumsz,
|
|
mPriData->mMediaInfo.albumCharEncode, kKeyAlbum);
|
|
mPriData->mMetaData->add(METADATA_KEY_ALBUM,mStrData);
|
|
}
|
|
//* no information to give the album title.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "ALBUM";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TALB" or "TAL";
|
|
//* mov file may contain this information in its metadata, index by FOURCC 0xa9 'a' 'l' 'b';
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the information about the artist of
|
|
//* * the data source.
|
|
//* */
|
|
//* public static final int METADATA_KEY_ARTIST = 2;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_ARTIST, String8("unknown artist"));
|
|
//* no information to give the artist.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "ARTIST";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TPE1" or "TP1";
|
|
//* mov file may contain this information in its metadata, index by FOURCC 0xa9 'a' 'r' 't';
|
|
#endif
|
|
|
|
//* warning: we put author as artist here
|
|
//nStrLen = strlen((const char*)mMediaInfo.author);
|
|
nStrLen = mPriData->mMediaInfo.authorsz;
|
|
if(nStrLen != 0)
|
|
{
|
|
logv("METADATA_KEY_ARTIST:%d",nStrLen);
|
|
transfromId3Info(&mStrData, mPriData->mMediaInfo.author, mPriData->mMediaInfo.authorsz,
|
|
mPriData->mMediaInfo.authorCharEncode, kKeyArtist);
|
|
mPriData->mMetaData->add(METADATA_KEY_ARTIST, mStrData);
|
|
}
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the information about the author of
|
|
//* * the data source.
|
|
//* */
|
|
//* public static final int METADATA_KEY_AUTHOR = 3;
|
|
//nStrLen = strlen((const char*)mMediaInfo.author);
|
|
nStrLen = mPriData->mMediaInfo.authorsz;
|
|
if(nStrLen > 0)
|
|
{
|
|
logv("METADATA_KEY_AUTHOR:%d",nStrLen);
|
|
transfromId3Info(&mStrData, mPriData->mMediaInfo.author, mPriData->mMediaInfo.authorsz,
|
|
mPriData->mMediaInfo.authorCharEncode, kKeyAuthor);
|
|
mPriData->mMetaData->add(METADATA_KEY_AUTHOR, mStrData);
|
|
}
|
|
//* no information to give the author.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "AUTHOR";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TXT" or "TEXT";
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the information about the composer of
|
|
//* * the data source.
|
|
//* */
|
|
//* public static final int METADATA_KEY_COMPOSER = 4;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_COMPOSER, String8("unknown composer"));
|
|
//* no information to give the composer.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "COMPOSER";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TCOM" or "TCM";
|
|
#endif
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the date when the data source was created
|
|
//* * or modified.
|
|
//* */
|
|
//* public static final int METADATA_KEY_DATE = 5;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_DATE, String8("unknown date"));
|
|
//* no information to give the date.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "DATE";
|
|
//* mov file may find this information by getting its mvhd header's creation time.
|
|
#endif
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the content type or genre of the data
|
|
//* * source.
|
|
//* */
|
|
//* public static final int METADATA_KEY_GENRE = 6;
|
|
nStrLen = strlen((const char*)mPriData->mMediaInfo.genre);
|
|
if(nStrLen > 0)
|
|
mPriData->mMetaData->add(METADATA_KEY_GENRE,
|
|
String8((const char*)mPriData->mMediaInfo.genre));
|
|
//* no information to give the genre.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "GENRE";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TCON" or "TCO";
|
|
//* mov file may contain this information in its metadata, index by FOURCC 'gnre' or
|
|
//* "0xa9 'g' 'e' 'n'";
|
|
//* for mov, iTunes genre codes are the standard id3 codes, except they start at 1 instead of 0
|
|
//* (e.g. Pop is 14, not 13), if you use standard id3 numbering, you should subtract 1.
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the data source title.
|
|
//* */
|
|
//* public static final int METADATA_KEY_TITLE = 7;
|
|
|
|
//* mPriData->mMetaData->add(METADATA_KEY_TITLE, String8("unknown title"));
|
|
|
|
//* no information to give the title.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "TITLE";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TIT2" or "TT2";
|
|
//* mov file may contain this information in its metadata, index by FOURCC "0xa9 'n' 'a' 'm'";
|
|
|
|
//nStrLen = strlen((const char*)mMediaInfo.title);
|
|
nStrLen = mPriData->mMediaInfo.titlesz;
|
|
if(nStrLen != 0)
|
|
{
|
|
logv("METADATA_KEY_TITLE:%d",nStrLen);
|
|
transfromId3Info(&mStrData, mPriData->mMediaInfo.title, mPriData->mMediaInfo.titlesz,
|
|
mPriData->mMediaInfo.titleCharEncode, kKeyTitle);
|
|
mPriData->mMetaData->add(METADATA_KEY_TITLE, mStrData);
|
|
}
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the year when the data source was created
|
|
//* * or modified.
|
|
//* */
|
|
//* public static final int METADATA_KEY_YEAR = 8;
|
|
nStrLen = strlen((const char*)mPriData->mMediaInfo.year);
|
|
if(nStrLen > 0)
|
|
mPriData->mMetaData->add(METADATA_KEY_YEAR,
|
|
String8((const char*)mPriData->mMediaInfo.year));
|
|
//* no information to give the title.
|
|
//* mp3 file may contain this information in its metadata, index by tag "TYE" or "TYER";
|
|
//* mov file may contain this information in its metadata, index by FOURCC "0xa9 'd' 'a' 'y'";
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the playback duration of the data source.
|
|
//* */
|
|
//* public static final int METADATA_KEY_DURATION = 9;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
//* The duration value is a string representing the duration in ms.
|
|
sprintf(tmp, "%d",
|
|
mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].duration);
|
|
mPriData->mMetaData->add(METADATA_KEY_DURATION, String8(tmp));
|
|
logv("duration:%d",
|
|
mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].duration);
|
|
}
|
|
|
|
//* /**
|
|
//* * 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;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
int nTrackCount =
|
|
mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].videoNum +
|
|
mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].audioNum +
|
|
mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].subtitleNum;
|
|
sprintf(tmp, "%d", nTrackCount);
|
|
mPriData->mMetaData->add(METADATA_KEY_NUM_TRACKS, String8(tmp));
|
|
}
|
|
|
|
//* /**
|
|
//* * 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;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_WRITER, String8("unknown writer"));
|
|
//* no information to give the writer.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "LYRICIST";
|
|
//* mov file may contain this information in its metadata, index by FOURCC "0xa9 'w' 'r' 't'";
|
|
#endif
|
|
|
|
//* /**
|
|
//* * 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;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
int type = -1;
|
|
XRetrieverGetMetaData(mPriData->mXRetriever, METADATA_PARSER_TYPE, &type);
|
|
switch(type)
|
|
{
|
|
case CDX_PARSER_MOV:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/mp4"));
|
|
break;
|
|
case CDX_PARSER_MKV:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-matroska"));
|
|
break;
|
|
case CDX_PARSER_ASF:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-ms-asf"));
|
|
break;
|
|
case CDX_PARSER_MPG:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/mpeg"));
|
|
break;
|
|
case CDX_PARSER_TS:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/mp2ts"));
|
|
break;
|
|
case CDX_PARSER_AVI:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/avi"));
|
|
break;
|
|
case CDX_PARSER_FLV:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_PMP:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_HLS:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("application/vnd.apple.mpegurl"));
|
|
break;
|
|
case CDX_PARSER_DASH:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_MMS:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_BD:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_OGG:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("application/ogg"));
|
|
break;
|
|
case CDX_PARSER_M3U9:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_RMVB:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_PLAYLIST:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
case CDX_PARSER_WAV:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("audio/x-wav"));
|
|
break;
|
|
case CDX_PARSER_APE:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("audio/cedara"));
|
|
break;
|
|
case CDX_PARSER_MP3:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("audio/mpeg"));
|
|
break;
|
|
case CDX_PARSER_WVM:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("application/x-android-drm-fl"));
|
|
break;
|
|
case CDX_PARSER_REMUX:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/cedarx"));
|
|
break;
|
|
default:
|
|
break;
|
|
//* going to be add:
|
|
//* WAV: audio/x-wav
|
|
//* APE:
|
|
//* ...
|
|
//* Widevine: video/wvm
|
|
//* ...
|
|
}
|
|
|
|
#if 0
|
|
//* add video mimetype.
|
|
for(i=0; i<mPriData->mMediaInfo.program[mMediaInfo.programIndex].videoNum; i++)
|
|
{
|
|
switch(mPriData->mMediaInfo.program[mMediaInfo.programIndex].video[i].eCodecFormat)
|
|
{
|
|
case VIDEO_CODEC_FORMAT_MJPEG:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/jpeg"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_MPEG1:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/mpeg1"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_MPEG2:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/mpeg2"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_MPEG4:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/mp4v-es"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_MSMPEG4V1:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-ms-mpeg4v1"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_MSMPEG4V2:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-ms-mpeg4v2"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_DIVX3:
|
|
case VIDEO_CODEC_FORMAT_DIVX4:
|
|
case VIDEO_CODEC_FORMAT_DIVX5:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/divx"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_XVID:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/xvid"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_H263:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/3gpp"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_SORENSSON_H263:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/flv1"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_RXG2:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/rvg2"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_WMV1:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/wmv1"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_WMV2:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/wmv2"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_WMV3:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-ms-wmv"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_VP6:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-vnd.on2.vp6"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_VP8:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-vnd.on2.vp8"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_VP9:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/x-vnd.on2.vp9"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_RX:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/realvideo"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_H264:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/avc"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_H265:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/hevc"));
|
|
break;
|
|
case VIDEO_CODEC_FORMAT_AVS:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("video/avs"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if 1
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
if((mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].audioNum > 0) &&
|
|
(mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].videoNum <= 0))
|
|
{
|
|
//* add audio mimetype.
|
|
int programIndex = mPriData->mMediaInfo.programIndex;
|
|
int audioNum = mPriData->mMediaInfo.program[programIndex].audioNum;
|
|
for(i = 0; i < audioNum; i++)
|
|
{
|
|
enum EAUDIOCODECFORMAT eCodecFormat =
|
|
mPriData->mMediaInfo.program[programIndex].audio[i].eCodecFormat;
|
|
switch(eCodecFormat)
|
|
{
|
|
case AUDIO_CODEC_FORMAT_MP1:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_MP2:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_MP3:
|
|
case AUDIO_CODEC_FORMAT_MP3_PRO:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/mpeg"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_MPEG_AAC_LC:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_AC3:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_DTS:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_LPCM_V:
|
|
case AUDIO_CODEC_FORMAT_LPCM_A:
|
|
case AUDIO_CODEC_FORMAT_ADPCM:
|
|
case AUDIO_CODEC_FORMAT_PPCM:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_PCM:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_WMA_STANDARD:
|
|
case AUDIO_CODEC_FORMAT_WMA_LOSS:
|
|
case AUDIO_CODEC_FORMAT_WMA_PRO:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/x-ms-wma"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_FLAC:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/flac"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_APE:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_OGG:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/ogg"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_RAAC:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/aac-adts"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_COOK:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cook"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_SIPR:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/sipr"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_ATRC:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/atrc"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_AMR:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/amr"));
|
|
break;
|
|
case AUDIO_CODEC_FORMAT_RA:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("audio/cedara"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
//* add subtitle mimetype.
|
|
for(i=0; i<mMediaInfo.program[mMediaInfo.programIndex].subtitleNum; i++)
|
|
{
|
|
switch(mMediaInfo.program[mMediaInfo.programIndex].subtitle[i].eCodecFormat)
|
|
{
|
|
case SUBTITLE_CODEC_DVDSUB:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("subtitle/x-subrip"));
|
|
break;
|
|
case SUBTITLE_CODEC_IDXSUB:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("subtitle/index-subtitle"));
|
|
break;
|
|
case SUBTITLE_CODEC_PGS:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE,
|
|
String8("subtitle/bd-subtitle"));
|
|
break;
|
|
case SUBTITLE_CODEC_TXT:
|
|
case SUBTITLE_CODEC_TIMEDTEXT:
|
|
case SUBTITLE_CODEC_SRT:
|
|
case SUBTITLE_CODEC_SMI:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("text/3gpp-tt"));
|
|
break;
|
|
case SUBTITLE_CODEC_SSA:
|
|
mPriData->mMetaData->add(METADATA_KEY_MIMETYPE, String8("text/ssa"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//* /**
|
|
//* * 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;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_ALBUMARTIST, String8("unknown album artist"));
|
|
//* no information to give the artist.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "ALBUMARTIST"
|
|
//* or "ALBUM ARTIST";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TPE2" or "TP2";
|
|
//* mov file may contain this information in its metadata, index by FOURCC "'a' 'A' 'R' 'T'";
|
|
#endif
|
|
|
|
//* /**
|
|
//* * 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;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_DISC_NUMBER, String8("unknown disk number"));
|
|
//* no information to tell which part of a set the audio data source comes from.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "DISCNUMBER";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TPA" or "TPOS";
|
|
//* mov file may contain this information in its metadata, index by FOURCC "'d' 'i' 's' 'k'";
|
|
#endif
|
|
|
|
//* /**
|
|
//* * The metadata key to retrieve the music album compilation status.
|
|
//* */
|
|
//* public static final int METADATA_KEY_COMPILATION = 15;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_COMPILATION, String8("unknown compilation"));
|
|
//* no information to tell which part of a set the audio data source comes from.
|
|
//* ogg file may contain this information in its vorbis comment, index by tag "COMPILATION";
|
|
//* mp3 file may contain this information in its metadata, index by tag "TCP" or "TCMP";
|
|
//* mov file may contain this information in its metadata, index by FOURCC "'c' 'p' 'i' 'l'";
|
|
#endif
|
|
|
|
//* /**
|
|
//* * If this key exists the media contains audio content.
|
|
//* */
|
|
//* public static final int METADATA_KEY_HAS_AUDIO = 16;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
//* add HAS_AUDIO info when have audio,or not add
|
|
//* (reference to StagefrightMetadataRetriever.cpp)
|
|
if(mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].audioNum > 0)
|
|
mPriData->mMetaData->add(METADATA_KEY_HAS_AUDIO, String8("yes"));
|
|
}
|
|
|
|
//* /**
|
|
//* * If this key exists the media contains video content.
|
|
//* */
|
|
//* public static final int METADATA_KEY_HAS_VIDEO = 17;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
//* add HAS_VIDEO info when hava video, or not add
|
|
//* (reference to StagefrightMetadataRetriever.cpp)
|
|
if(mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].videoNum > 0)
|
|
mPriData->mMetaData->add(METADATA_KEY_HAS_VIDEO, String8("yes"));
|
|
}
|
|
|
|
//* /**
|
|
//* * If the media contains video, this key retrieves its width.
|
|
//* */
|
|
//* public static final int METADATA_KEY_VIDEO_WIDTH = 18;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
if(mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].videoNum > 0)
|
|
{
|
|
sprintf(tmp, "%d",
|
|
mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].video[0].nWidth);
|
|
mPriData->mMetaData->add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
|
|
}
|
|
}
|
|
|
|
//* /**
|
|
//* * If the media contains video, this key retrieves its height.
|
|
//* */
|
|
//* public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
if(mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].videoNum > 0)
|
|
{
|
|
sprintf(tmp, "%d",
|
|
mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].video[0].nHeight);
|
|
//* add the video height
|
|
mPriData->mMetaData->add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
|
|
}
|
|
}
|
|
|
|
//* /**
|
|
//* * This key retrieves the average bitrate (in bits/sec), if available.
|
|
//* */
|
|
//* public static final int METADATA_KEY_BITRATE = 20;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_BITRATE, String8("unknown bitrate"));
|
|
//* no information to give the average bitrate.
|
|
#endif
|
|
|
|
//* /**
|
|
//* * This key retrieves the language code of text tracks, if available.
|
|
//* * If multiple text tracks present, the return value will look like:
|
|
//* * "eng:chi"
|
|
//* * @hide
|
|
//* */
|
|
//* public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES = 21;
|
|
if(mPriData->mMediaInfo.programIndex >= 0 &&
|
|
mPriData->mMediaInfo.programNum >= mPriData->mMediaInfo.programIndex)
|
|
{
|
|
if(mPriData->mMediaInfo.program[mPriData->mMediaInfo.programIndex].subtitleNum > 0)
|
|
{
|
|
int len;
|
|
char buffer[256];
|
|
tmp[0] = '\0';
|
|
buffer[0] = '\0';
|
|
int index = mPriData->mMediaInfo.programIndex;
|
|
for(i=0; i<mPriData->mMediaInfo.program[index].subtitleNum; i++)
|
|
{
|
|
if(i != 0)
|
|
sprintf(buffer, "%s:", tmp); //* add a ":".
|
|
|
|
len = strlen((const char*)mPriData->mMediaInfo.program[index].subtitle[i].strLang);
|
|
if(len == 0)
|
|
len = strlen("unknown");
|
|
|
|
if(len + strlen(tmp) >= (sizeof(tmp)-1))
|
|
{
|
|
logw("can not set the language of subtitle correctly");
|
|
break; //* for save.
|
|
}
|
|
|
|
if(strlen((const char*)mPriData->mMediaInfo.program[index].subtitle[i].strLang) > 0)
|
|
sprintf(buffer, "%s%s", tmp,
|
|
mPriData->mMediaInfo.program[index].subtitle[i].strLang);
|
|
else
|
|
sprintf(buffer, "%s%s", tmp, "unknown");
|
|
}
|
|
mPriData->mMetaData->add(METADATA_KEY_TIMED_TEXT_LANGUAGES, String8(buffer));
|
|
}
|
|
}
|
|
|
|
//* /**
|
|
//* * If this key exists the media is drm-protected.
|
|
//* * @hide
|
|
//* */
|
|
//* public static final int METADATA_KEY_IS_DRM = 22;
|
|
#if 0
|
|
mPriData->mMetaData->add(METADATA_KEY_IS_DRM, String8("0"));
|
|
//* no information to give the drm info.
|
|
#endif
|
|
|
|
//* /**
|
|
//* * This key retrieves the location information, if available.
|
|
//* * The location should be specified according to ISO-6709 standard, under
|
|
//* * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
|
|
//* * of 180 degrees will be retrieved as "-90.0000+180.0000", for instance.
|
|
//* */
|
|
//* public static final int METADATA_KEY_LOCATION = 23;
|
|
|
|
//* set the location info
|
|
//* we should not add it when the nStrlen is 0
|
|
nStrLen = strlen((const char*)mPriData->mMediaInfo.location);
|
|
if(nStrLen != 0)
|
|
mPriData->mMetaData->add(METADATA_KEY_LOCATION,
|
|
String8((const char*)mPriData->mMediaInfo.location));
|
|
|
|
//* /**
|
|
//* * This key retrieves the video rotation angle in degrees, if available.
|
|
//* * The video rotation angle may be 0, 90, 180, or 270 degrees.
|
|
//* */
|
|
//* public static final int METADATA_KEY_VIDEO_ROTATION = 24;
|
|
|
|
//* set rotation info
|
|
//* mov parser can get the rotate angle.
|
|
//* we should not add it when the nStrlen is 0
|
|
nStrLen = strlen((const char*)mPriData->mMediaInfo.rotate);
|
|
if(nStrLen != 0)
|
|
mPriData->mMetaData->add(METADATA_KEY_VIDEO_ROTATION,
|
|
String8((const char*)mPriData->mMediaInfo.rotate));
|
|
|
|
return;
|
|
}
|
|
|
|
const char* AwMetadataRetriever::extractMetadata(int keyCode)
|
|
{
|
|
//* keyCode is defined in "android/framworks/av/include/media/mediametadataretriever.h" and
|
|
//* "android/frameworks/base/media/java/android/media/mediametadataretriever.java".
|
|
//* keyCodes list here.
|
|
//* /**
|
|
//* * The metadata key to retrieve the numeric 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;
|
|
//* /**
|
|
//* * 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;
|
|
//* /**
|
|
//* * If this key exists the media contains audio content.
|
|
//* */
|
|
//* public static final int METADATA_KEY_HAS_AUDIO = 16;
|
|
//* /**
|
|
//* * If this key exists the media contains video content.
|
|
//* */
|
|
//* public static final int METADATA_KEY_HAS_VIDEO = 17;
|
|
//* /**
|
|
//* * If the media contains video, this key retrieves its width.
|
|
//* */
|
|
//* public static final int METADATA_KEY_VIDEO_WIDTH = 18;
|
|
//* /**
|
|
//* * If the media contains video, this key retrieves its height.
|
|
//* */
|
|
//* public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
|
|
//* /**
|
|
//* * This key retrieves the average bitrate (in bits/sec), if available.
|
|
//* */
|
|
//* public static final int METADATA_KEY_BITRATE = 20;
|
|
//* /**
|
|
//* * This key retrieves the language code of text tracks, if available.
|
|
//* * If multiple text tracks present, the return value will look like:
|
|
//* * "eng:chi"
|
|
//* * @hide
|
|
//* */
|
|
//* public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES = 21;
|
|
//* /**
|
|
//* * If this key exists the media is drm-protected.
|
|
//* * @hide
|
|
//* */
|
|
//* public static final int METADATA_KEY_IS_DRM = 22;
|
|
//* /**
|
|
//* * This key retrieves the location information, if available.
|
|
//* * The location should be specified according to ISO-6709 standard, under
|
|
//* * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
|
|
//* * of 180 degrees will be retrieved as "-90.0000+180.0000", for instance.
|
|
//* */
|
|
//* public static final int METADATA_KEY_LOCATION = 23;
|
|
//* /**
|
|
//* * This key retrieves the video rotation angle in degrees, if available.
|
|
//* * The video rotation angle may be 0, 90, 180, or 270 degrees.
|
|
//* */
|
|
//* public static final int METADATA_KEY_VIDEO_ROTATION = 24;
|
|
|
|
int index;
|
|
const char* strMetadataName[] =
|
|
{
|
|
"CD_TRACK_NUMBER", "ALBUM", "ARTIST", "AUTHOR",
|
|
"CD_TRACK_COMPOSER", "DATE", "GENRE", "TITLE",
|
|
"YEAR", "DURATION", "NUM_TRACKS", "WRITER",
|
|
"MIMETYPE", "ALBUMARTIST", "DISC_NUMBER", "COMPILATION",
|
|
"HAS_AUDIO", "HAS_VIDEO", "VIDEO_WIDTH", "VIDEO_HEIGHT",
|
|
"BITRATE", "TIMED_TEXT_LANGUAGES", "IS_DRM", "LOCATION",
|
|
"VIDEO_ROTATION"
|
|
};
|
|
|
|
index = mPriData->mMetaData->indexOfKey(keyCode);
|
|
if (index < 0)
|
|
{
|
|
if(keyCode >=0 && keyCode <= 24)
|
|
{
|
|
logw("no metadata for %s.", strMetadataName[keyCode]);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
return mPriData->mMetaData->valueAt(index).string();
|
|
}
|
|
|
|
MediaAlbumArt* AwMetadataRetriever::extractAlbumArt()
|
|
{
|
|
//* no album art picture extracted.
|
|
//* ogg parser can find the album art picture in its vorbis comment,
|
|
//* index by tag "METADATA_BLOCK_PICTURE";
|
|
//* flac parser can find the album art picture in its meta data;
|
|
//* mp3 parser can find the album art picture in its id3 data;
|
|
//* mov parser can find the album art picture in its metadata,
|
|
//* index by FOURCC "'c' 'o' 'v' 'r'";
|
|
|
|
if(mPriData->mAlbumArtPic != NULL)
|
|
{
|
|
#if (CONF_ANDROID_MAJOR_VER >= 5)
|
|
return mPriData->mAlbumArtPic->clone();
|
|
#else
|
|
return new MediaAlbumArt(*mPriData->mAlbumArtPic);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
//* note:
|
|
//* if it is a media file with drm protection, we should not return an album art picture.
|
|
}
|
|
|
|
sp<IMemory> AwMetadataRetriever::getStreamAtTime(int64_t timeUs)
|
|
{
|
|
sp<IMemory> mem = NULL;
|
|
XVideoStream *pXVideoStream;
|
|
uint8_t* pOutBuf;
|
|
int32_t nBitStreamLength;
|
|
|
|
pXVideoStream = XRetrieverGetStreamAtTime(mPriData->mXRetriever, timeUs);
|
|
if(pXVideoStream == NULL)
|
|
{
|
|
loge("XRetrieverGetStreamAtTime failed.");
|
|
return NULL;
|
|
}
|
|
|
|
pOutBuf = pXVideoStream->mBuf;
|
|
nBitStreamLength = pXVideoStream->mSize;
|
|
|
|
//* copy bitstream to ashmem.
|
|
if(pOutBuf && nBitStreamLength)
|
|
{
|
|
sp<MemoryHeapBase> heap = new MemoryHeapBase(nBitStreamLength + 4, 0,
|
|
"awmetadataretriever");
|
|
unsigned char* pData = NULL;
|
|
if (heap == NULL)
|
|
loge("failed to create MemoryDealer");
|
|
|
|
mem = new MemoryBase(heap, 0, nBitStreamLength + 4);
|
|
if (mem == NULL)
|
|
{
|
|
loge("not enough memory for stream size = %d", nBitStreamLength);
|
|
}
|
|
else
|
|
{
|
|
pData = static_cast<unsigned char*>(mem->pointer());
|
|
pData[0] = (nBitStreamLength) & 0xff;
|
|
pData[1] = (nBitStreamLength>>8) & 0xff;
|
|
pData[2] = (nBitStreamLength>>16) & 0xff;
|
|
pData[3] = (nBitStreamLength>>24) & 0xff;
|
|
memcpy(pData+4, pOutBuf, nBitStreamLength);
|
|
}
|
|
}
|
|
|
|
logv("bBitStreamLength: %p,%d", pOutBuf, nBitStreamLength);
|
|
|
|
return mem;
|
|
}
|
|
|
|
VideoFrame *AwMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
|
|
{
|
|
VideoFrame* pVideoFrame;
|
|
XVideoFrame* pXVideoFrame;
|
|
|
|
CEDARX_UNUSE(option);
|
|
|
|
#if MediaScanDedug
|
|
logd("getFrameAtTime, mFd=%d", mPriData->mFd);
|
|
#endif
|
|
|
|
pXVideoFrame = XRetrieverGetFrameAtTime(mPriData->mXRetriever, timeUs);
|
|
if(pXVideoFrame == NULL)
|
|
{
|
|
loge("XRetrieverGetFrameAtTime failed.");
|
|
return NULL;
|
|
}
|
|
|
|
pVideoFrame = new VideoFrame;
|
|
if(pVideoFrame == NULL)
|
|
{
|
|
loge("can not allocate memory for video frame.");
|
|
return NULL;
|
|
}
|
|
|
|
pVideoFrame->mDisplayWidth = pXVideoFrame->mDisplayWidth;
|
|
pVideoFrame->mDisplayHeight = pXVideoFrame->mDisplayHeight;
|
|
pVideoFrame->mWidth = pXVideoFrame->mWidth;
|
|
pVideoFrame->mHeight = pXVideoFrame->mHeight;
|
|
pVideoFrame->mSize = pXVideoFrame->mSize;
|
|
pVideoFrame->mRotationAngle = pXVideoFrame->mRotationAngle;
|
|
pVideoFrame->mData = new unsigned char[pVideoFrame->mSize];
|
|
if(pVideoFrame->mData == NULL)
|
|
{
|
|
loge("can not allocate memory for video frame.");
|
|
delete pVideoFrame;
|
|
return NULL;
|
|
}
|
|
memcpy(pVideoFrame->mData, pXVideoFrame->mData, pXVideoFrame->mSize);
|
|
|
|
return pVideoFrame;
|
|
}
|
|
|
|
static int parseHeaders(CdxKeyedVectorT **header, char *uri,
|
|
KeyedVector<String8, String8>* pHeaders)
|
|
{
|
|
int nHeaderSize;
|
|
int i;
|
|
|
|
clearHeaders(header);
|
|
|
|
if(uri != NULL)
|
|
{
|
|
if(pHeaders != NULL &&
|
|
(!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)))
|
|
{
|
|
//* remove "x-hide-urls-from-log" ?
|
|
|
|
nHeaderSize = pHeaders->size();
|
|
if (nHeaderSize <= 0)
|
|
return -1;
|
|
|
|
*header = CdxKeyedVectorCreate(nHeaderSize);
|
|
if (*header == NULL)
|
|
{
|
|
logw("CdxKeyedVectorCreate() failed");
|
|
return -1;
|
|
}
|
|
|
|
String8 key;
|
|
String8 value;
|
|
for (i = 0; i < nHeaderSize; i++)
|
|
{
|
|
key = pHeaders->keyAt(i);
|
|
value = pHeaders->valueAt(i);
|
|
if (CdxKeyedVectorAdd(*header, key.string(), value.string()) != 0)
|
|
{
|
|
clearHeaders(header);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void clearHeaders(CdxKeyedVectorT **header)
|
|
{
|
|
if (*header != NULL)
|
|
{
|
|
CdxKeyedVectorDestroy(*header);
|
|
*header = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static int64_t GetSysTime()
|
|
{
|
|
int64_t time;
|
|
struct timeval t;
|
|
gettimeofday(&t, NULL);
|
|
time = (int64_t)t.tv_sec * 1000000;
|
|
time += t.tv_usec;
|
|
return time;
|
|
}
|
|
|
|
static int transfromId3Info(String8* mStringId3, cdx_uint8* pData, cdx_int32 nSize,
|
|
cdx_int32 nEncodeTpye,cdx_int32 flag)
|
|
{
|
|
if(pData == NULL || nSize == 0)
|
|
{
|
|
logd("*** transfromId3Info failed, pData = %p, size = %d",pData,nSize);
|
|
return -1;
|
|
}
|
|
|
|
#if (CONF_ANDROID_MAJOR_VER >= 5)
|
|
cdx_int32 encoding = nEncodeTpye;
|
|
size_t nDataLen = nSize;
|
|
const char* name = NULL;
|
|
const char* pDataConvert = NULL;
|
|
|
|
mStringId3->setTo("");
|
|
|
|
if (encoding == 0x00)
|
|
{
|
|
// supposedly ISO 8859-1
|
|
mStringId3->setTo((const char*)(pData), nDataLen);
|
|
}
|
|
else if (encoding == 0x03)
|
|
{
|
|
// supposedly UTF-8
|
|
mStringId3->setTo((const char *)(pData), nDataLen);
|
|
}
|
|
else if (encoding == 0x02)
|
|
{
|
|
// supposedly UTF-16 BE, no byte order mark.
|
|
// API wants number of characters, not number of bytes...
|
|
int len = nDataLen / 2;
|
|
const char16_t *framedata = (const char16_t *) (pData);
|
|
mStringId3->setTo(framedata, len);
|
|
}
|
|
else if (encoding == 0x01)
|
|
{
|
|
// UCS-2
|
|
// API wants number of characters, not number of bytes...
|
|
int len = nDataLen / 2;
|
|
const char16_t *framedata = (const char16_t *) (pData);
|
|
|
|
// check if the resulting data consists entirely of 8-bit values
|
|
bool eightBit = true;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
if (framedata[i] > 0xff)
|
|
{
|
|
eightBit = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (eightBit)
|
|
{
|
|
// collapse to 8 bit, then let the media scanner client figure out the real encoding
|
|
char *frame8 = new char[len];
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
frame8[i] = framedata[i];
|
|
}
|
|
mStringId3->setTo(frame8, len);
|
|
delete [] frame8;
|
|
}
|
|
else
|
|
{
|
|
mStringId3->setTo(framedata, len);
|
|
}
|
|
}
|
|
cdx_int32 idx = 0;
|
|
logv("** pDataConvert before = %s",mStringId3->string());
|
|
#if 1
|
|
CharacterEncodingDetector *pEcodingdetector = new CharacterEncodingDetector();
|
|
for(idx = 0; idx < kNumMapEntries; idx++)
|
|
{
|
|
if(flag == kMap[idx].from)
|
|
{
|
|
if(kMap[idx].name != NULL)
|
|
{
|
|
pEcodingdetector->addTag(kMap[idx].name, (const char*)mStringId3->string());
|
|
}
|
|
}
|
|
}
|
|
pEcodingdetector->detectAndConvert();
|
|
int nDetectorSize = pEcodingdetector->size();
|
|
if (nDetectorSize) {
|
|
for (int i = 0; i < nDetectorSize; i++) {
|
|
const char *pName;
|
|
const char *pValue;
|
|
pEcodingdetector->getTag(i, &pName, &pValue);
|
|
for (cdx_int32 j = 0; j < kNumMapEntries; ++j) {
|
|
if (kMap[j].name && !strcmp(kMap[j].name, pName)) {
|
|
//mPriData->mMetaData->add(kMap[j].to, String8(value));
|
|
mStringId3->setTo("");
|
|
mStringId3->setTo(pValue,strlen(pValue));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete pEcodingdetector;
|
|
|
|
#endif
|
|
logd("** pDataConvert finish = %s",mStringId3->string());
|
|
#else
|
|
cdx_int32 encoding = nEncodeTpye;
|
|
size_t nDataLen = nSize;
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
String8 srcString;
|
|
|
|
srcString.setTo("");
|
|
|
|
if(encoding == 0x00) //why gbk come here ?
|
|
{
|
|
// supposedly ISO 8859-1
|
|
srcString.setTo((const char*)(pData), nDataLen);
|
|
}
|
|
else if(encoding == 0x03)
|
|
{
|
|
// supposedly UTF-8
|
|
srcString.setTo((const char *)(pData), nDataLen);
|
|
}
|
|
else if(encoding == 0x02)
|
|
{
|
|
// supposedly UTF-16 BE, no byte order mark.
|
|
// API wants number of characters, not number of bytes...
|
|
int len = nDataLen / 2;
|
|
const uint16_t *framedata = (const uint16_t *) (pData);
|
|
|
|
srcString.setTo(framedata, len);
|
|
}
|
|
else if(encoding == 0x01)
|
|
{
|
|
// UCS-2
|
|
// API wants number of characters, not number of bytes...
|
|
int len = nDataLen / 2;
|
|
const uint16_t *framedata = (const uint16_t *) (pData);
|
|
|
|
// check if the resulting data consists entirely of 8-bit values
|
|
bool eightBit = true;
|
|
for(int i = 0; i < len; i++)
|
|
{
|
|
if(framedata[i] > 0xff)
|
|
{
|
|
eightBit = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(eightBit)
|
|
{
|
|
// collapse to 8 bit, then let the media scanner client figure out the real encoding
|
|
char *frame8 = new char[len];
|
|
for(int i = 0; i < len; i++)
|
|
{
|
|
frame8[i] = framedata[i];
|
|
}
|
|
srcString.setTo(frame8, len);
|
|
delete [] frame8;
|
|
}
|
|
else
|
|
{
|
|
srcString.setTo(framedata, len);
|
|
}
|
|
}
|
|
|
|
logd("convert before = %s, nDataLen %d",srcString.string(), nDataLen);
|
|
|
|
//*first we need to untangle the utf8 and convert it back to the original bytes
|
|
// since we are reducing the length of the string, we can do this in place
|
|
|
|
//*now convert from native encoding to UTF-8
|
|
if(0x00 == nEncodeTpye)
|
|
{
|
|
const char* gbkSrc = (char*)srcString.string();
|
|
int gbkLen = nDataLen;
|
|
int utf8Len = gbkLen * 3 + 1; //TODO
|
|
char* utf8Dst = (char*)malloc(utf8Len);
|
|
memset(utf8Dst, 0, utf8Len);
|
|
|
|
char value[256];
|
|
const char *srcEncoding;
|
|
property_get("persist.sys.language", value, "");
|
|
if (strncmp(value, "ko", 256) == 0)
|
|
{
|
|
srcEncoding = "EUC-KR";
|
|
}
|
|
else /* default set to GBK */
|
|
{
|
|
srcEncoding = "GBK";
|
|
}
|
|
|
|
logd("ucnv_convert, nEncodeTpye 0x%02x, using %s", nEncodeTpye, srcEncoding);
|
|
|
|
ucnv_convert("UTF-8",
|
|
srcEncoding,
|
|
utf8Dst,
|
|
utf8Len,
|
|
gbkSrc,
|
|
gbkLen,
|
|
&status);
|
|
|
|
if(U_FAILURE(status))
|
|
{
|
|
logw("ucnv_convertEx failed: %d\n", status);
|
|
}
|
|
|
|
logd("convert %s to utf-8 src = %s, dst = %s\n", srcEncoding, gbkSrc, utf8Dst);
|
|
|
|
mStringId3->setTo("");
|
|
mStringId3->setTo((const char*)utf8Dst);
|
|
}
|
|
else if(0x01 == nEncodeTpye)
|
|
{
|
|
logd("no conversion, nEncodeTpye 0x%02x", nEncodeTpye);
|
|
mStringId3->setTo("");
|
|
mStringId3->setTo((const char*)srcString.string());
|
|
}
|
|
else
|
|
{
|
|
logd("no implement, nEncodeTpye 0x%02x", nEncodeTpye);
|
|
mStringId3->setTo("");
|
|
mStringId3->setTo((const char*)srcString.string());
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|