blob: 8b594425d303c59ab65c9c3ed28b420598064535 [file] [log] [blame]
/*
**
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "MetadataDriver"
#include <utils/Log.h>
#include <media/thread_init.h>
#include <core/SkBitmap.h>
#include <private/media/VideoFrame.h>
#include "metadatadriver.h"
using namespace android;
const char* MetadataDriver::ALBUM_ART_KEY = "graphic";
const char* MetadataDriver::METADATA_KEYS[NUM_METADATA_KEYS] = {
"track-info/track-number",
"album",
"artist",
"author",
"composer",
"date",
"genre",
"title",
"year",
"duration",
"num-tracks",
"drm/is-protected",
"track-info/codec-name",
"rating",
"comment",
"copyright",
"track-info/bit-rate",
"track-info/frame-rate",
"track-info/video/format",
"track-info/video/height",
"track-info/video/width",
"writer",
};
static void dumpkeystolog(PVPMetadataList list)
{
LOGV("dumpkeystolog");
uint32 n = list.size();
for(uint32 i = 0; i < n; ++i) {
LOGI("@@@@@ wma key: %s", list[i].get_cstr());
}
}
MetadataDriver::MetadataDriver(uint32 mode): OsclActiveObject(OsclActiveObject::EPriorityNominal, "MetadataDriver")
{
LOGV("constructor");
mMode = mode;
mUtil = NULL;
mDataSource = NULL;
#if BEST_THUMBNAIL_MODE
mLocalDataSource = NULL;
#endif
mCmdId = 0;
mContextObjectRefValue = 0x5C7A; // Some random number
mContextObject = mContextObjectRefValue;
mMediaAlbumArt = NULL;
mSharedFd = -1;
mVideoFrame = NULL;
for (uint32 i = 0; i < NUM_METADATA_KEYS; ++i) {
mMetadataValues[i][0] = '\0';
}
LOGV("constructor: Mode (%d).", mMode);
}
/*static*/ int MetadataDriver::startDriverThread(void *cookie)
{
LOGV("startDriverThread");
MetadataDriver *driver = (MetadataDriver *)cookie;
return driver->retrieverThread();
}
int MetadataDriver::retrieverThread()
{
LOGV("retrieverThread");
if (!InitializeForThread()) {
LOGV("InitializeForThread fail");
mSyncSem->Signal();
return -1;
}
OMX_MasterInit();
OsclScheduler::Init("PVAuthorEngineWrapper");
mState = STATE_CREATE;
AddToScheduler();
RunIfNotReady();
OsclExecScheduler *sched = OsclExecScheduler::Current();
{
OsclLeaveCode error = OsclErrNone;
OSCL_TRY(error, sched->StartScheduler());
OSCL_FIRST_CATCH_ANY(error,
// Some AO did a leave, log it
LOGE("Ln %d Player Engine AO did a leave, error=%d", __LINE__, error)
);
}
mSyncSem->Signal(); // Signal that doSetDataSource() is done.
OsclScheduler::Cleanup();
OMX_MasterDeinit();
UninitializeForThread();
return 0;
}
MetadataDriver::~MetadataDriver()
{
LOGV("destructor");
mCmdId = 0;
delete mVideoFrame;
mVideoFrame = NULL;
delete mMediaAlbumArt;
mMediaAlbumArt = NULL;
delete mSyncSem;
mSyncSem = NULL;
closeSharedFdIfNecessary();
}
const char* MetadataDriver::extractMetadata(int keyCode)
{
LOGV("extractMetadata");
char *value = NULL;
if (mMode & GET_METADATA_ONLY) {
// Comparing int with unsigned int
if (keyCode < 0 || keyCode >= (int) NUM_METADATA_KEYS) {
LOGE("extractMetadata: Invalid keyCode: %d.", keyCode);
} else {
value = mMetadataValues[keyCode];
}
}
if (value == NULL || value[0] == '\0') {
return NULL;
}
return value;
}
MediaAlbumArt *MetadataDriver::extractAlbumArt()
{
LOGV("extractAlbumArt");
if (mMode & GET_METADATA_ONLY) { // copy out
if (mMediaAlbumArt != NULL && mMediaAlbumArt->mSize > 0) {
return new MediaAlbumArt(*mMediaAlbumArt);
} else {
LOGE("failed to extract album art");
return NULL;
}
}
LOGE("extractAlbumArt: invalid mode (%d) to extract album art", mMode);
return NULL;
}
// How to better manage these constant strings?
bool MetadataDriver::containsSupportedKey(const OSCL_HeapString<OsclMemAllocator>& str) const
{
LOGV("containsSupportedKey");
const char* cStr = str.get_cstr();
for (uint32 i = 0; i < NUM_METADATA_KEYS; ++i) {
if (strcasestr(cStr, METADATA_KEYS[i])) {
return true;
}
}
// Key "graphic" is a special metadata key for retrieving album art image.
if (strcasestr(cStr, "graphic")) {
return true;
}
return false;
}
// Delete unnecessary keys before retrieving the metadata values to avoid
// retrieving all metadata values for all metadata keys
void MetadataDriver::trimKeys()
{
LOGV("trimKeys");
//dumpkeystolog(mMetadataKeyList);
mActualMetadataKeyList.clear();
uint32 n = mMetadataKeyList.size();
mActualMetadataKeyList.reserve(n);
for (uint32 i = 0; i < n; ++i) {
if (containsSupportedKey(mMetadataKeyList[i])) {
mActualMetadataKeyList.push_back(mMetadataKeyList[i]);
}
}
mMetadataKeyList.clear();
}
// Returns:
// 1. UNKNOWN_ERROR
// a. If the metadata value(s) is too long, and cannot be hold in valueLength bytes
// b. If nothing is found
// 2. OK
// a. If metadata value(s) is found
status_t MetadataDriver::extractMetadata(const char* key, char* value, uint32 valueLength)
{
LOGV("extractMetadata");
bool found = false;
value[0] = '\0';
for (uint32 i = 0, n = mMetadataValueList.size(); i < n; ++i) {
if (0 == strncasecmp(mMetadataValueList[i].key, key, strlen(key))) {
found = true;
switch(GetValTypeFromKeyString(mMetadataValueList[i].key)) {
case PVMI_KVPVALTYPE_CHARPTR: {
uint32 length = oscl_strlen(mMetadataValueList[i].value.pChar_value) + 1;
if (length > valueLength) {
return UNKNOWN_ERROR;
}
oscl_snprintf(value, length, "%s", mMetadataValueList[i].value.pChar_value);
break;
}
case PVMI_KVPVALTYPE_WCHARPTR: {
// Assume string is in UCS-2 encoding so convert to UTF-8.
uint32 length = oscl_strlen(mMetadataValueList[i].value.pWChar_value) + 1;
if (length > valueLength) {
return UNKNOWN_ERROR;
}
length = oscl_UnicodeToUTF8(mMetadataValueList[i].value.pWChar_value, length, value, valueLength);
break;
}
case PVMI_KVPVALTYPE_UINT32: {
// FIXME:
// This is an ugly hack since OpenCore returns duration in the following two formats:
// 1. duration;valtype=uint32 (the duration is an integer representing milliseconds)
// 2. duration;valtype=uint32;timescale=8000 (the duration is an integer representing the
// duration in a timescale of 8 kHz)
// It would be nice to have OpenCore always return duration in the first format.
// PV will study on fixing this to always return duration in the first format.
// Until that fix is available, we still need to do this.
const char* durKeyStr = "duration";
const char* timeScaleStr = "timescale=";
int timescale = 1000;
if (strncasecmp(key, durKeyStr, strlen(durKeyStr)) == 0) {
char *p;
if ((p = strcasestr(mMetadataValueList[i].key, timeScaleStr)) != NULL) {
timescale = atoi(p + strlen(timeScaleStr));
}
}
int duration = (mMetadataValueList[i].value.uint32_value * 1000LL) / timescale;
oscl_snprintf(value, valueLength, "%d", duration);
break;
}
case PVMI_KVPVALTYPE_INT32:
oscl_snprintf(value, valueLength, "%d", mMetadataValueList[i].value.int32_value);
break;
case PVMI_KVPVALTYPE_UINT8:
oscl_snprintf(value, valueLength, "%d", mMetadataValueList[i].value.uint8_value);
break;
case PVMI_KVPVALTYPE_FLOAT:
oscl_snprintf(value, valueLength, "%f", mMetadataValueList[i].value.float_value);
break;
case PVMI_KVPVALTYPE_DOUBLE:
oscl_snprintf(value, valueLength, "%f", mMetadataValueList[i].value.double_value);
break;
case PVMI_KVPVALTYPE_BOOL:
oscl_snprintf(value, valueLength, "%s", mMetadataValueList[i].value.bool_value? "true": "false");
break;
default:
return UNKNOWN_ERROR;
}
LOGV("value is: %s.", value);
break;
}
}
return found? OK: UNKNOWN_ERROR;
}
void MetadataDriver::cacheMetadataRetrievalResults()
{
LOGV("cacheMetadataRetrievalResults");
#if _METADATA_DRIVER_INTERNAL_DEBUG_ENABLE_
for (uint32 i = 0, n = mMetadataValueList.size(); i < n; ++i) {
LOGV("Value %d: Key string: %s.", (i+1), mMetadataValueList[i].key);
}
#endif
for (uint32 i = 0; i < NUM_METADATA_KEYS; ++i) {
LOGV("extract metadata key: %s", METADATA_KEYS[i]);
extractMetadata(METADATA_KEYS[i], mMetadataValues[i], MAX_METADATA_STRING_LENGTH - 1);
}
doExtractAlbumArt();
}
status_t MetadataDriver::extractEmbeddedAlbumArt(const PvmfApicStruct* apic)
{
LOGV("extractEmbeddedAlbumArt");
char* buf = (char*) apic->iGraphicData;
uint32 size = apic->iGraphicDataLen;
LOGV("extractEmbeddedAlbumArt: Embedded graphic or album art (%d bytes) is found.", size);
if (size && buf) {
delete mMediaAlbumArt;
mMediaAlbumArt = new MediaAlbumArt();
if (mMediaAlbumArt == NULL) {
LOGE("extractEmbeddedAlbumArt: Not enough memory to hold a MediaAlbumArt object");
return NO_MEMORY;
}
mMediaAlbumArt->mSize = size;
mMediaAlbumArt->mData = new uint8[size];
if (mMediaAlbumArt->mData == NULL) {
LOGE("extractEmbeddedAlbumArt: Not enough memory to hold the binary data of a MediaAlbumArt object");
delete mMediaAlbumArt;
mMediaAlbumArt = NULL;
return NO_MEMORY;
}
memcpy(mMediaAlbumArt->mData, buf, size);
return NO_ERROR;
}
return BAD_VALUE;
}
status_t MetadataDriver::extractExternalAlbumArt(const char* url)
{
LOGV("extractExternalAlbumArt: External graphic or album art is found: %s.", url);
delete mMediaAlbumArt;
mMediaAlbumArt = new MediaAlbumArt(url);
return (mMediaAlbumArt && mMediaAlbumArt->mSize > 0)? OK: BAD_VALUE;
}
// Finds the first album art and extract it.
status_t MetadataDriver::doExtractAlbumArt()
{
LOGV("doExtractAlbumArt");
status_t status = UNKNOWN_ERROR;
for (uint32 i = 0, n = mMetadataValueList.size(); i < n; ++i) {
if (strcasestr(mMetadataValueList[i].key, ALBUM_ART_KEY)) {
LOGV("doExtractAlbumArt: album art key: %s", mMetadataValueList[i].key);
if (PVMI_KVPVALTYPE_KSV == GetValTypeFromKeyString(mMetadataValueList[i].key)) {
const char* embeddedKey = "graphic;format=APIC;valtype=ksv";
const char* externalKey = "graphic;valtype=char*";
if (strstr(mMetadataValueList[i].key, embeddedKey) && mMetadataValueList[i].value.key_specific_value) {
// Embedded album art.
status = extractEmbeddedAlbumArt(((PvmfApicStruct*)mMetadataValueList[i].value.key_specific_value));
} else if (strstr(mMetadataValueList[i].key, externalKey)) {
// Album art linked with an external url.
status = extractExternalAlbumArt(mMetadataValueList[i].value.pChar_value);
}
if (status != OK) {
continue;
}
return status; // Found the album art.
}
}
}
return UNKNOWN_ERROR;
}
void MetadataDriver::clearCache()
{
LOGV("clearCache");
delete mVideoFrame;
mVideoFrame = NULL;
delete mMediaAlbumArt;
mMediaAlbumArt = NULL;
for(uint32 i = 0; i < NUM_METADATA_KEYS; ++i) {
mMetadataValues[i][0] = '\0';
}
}
status_t MetadataDriver::setDataSourceFd(
int fd, int64_t offset, int64_t length) {
LOGV("setDataSourceFd");
closeSharedFdIfNecessary();
if (offset < 0 || length < 0) {
if (offset < 0) {
LOGE("negative offset (%lld)", offset);
}
if (length < 0) {
LOGE("negative length (%lld)", length);
}
return INVALID_OPERATION;
}
mSharedFd = dup(fd);
char url[80];
sprintf(url, "sharedfd://%d:%lld:%lld", mSharedFd, offset, length);
clearCache();
return doSetDataSource(url);
}
status_t MetadataDriver::setDataSource(const char* srcUrl)
{
LOGV("setDataSource");
closeSharedFdIfNecessary();
// Don't let somebody trick us in to reading some random block of memory.
if (strncmp("sharedfd://", srcUrl, 11) == 0) {
LOGE("setDataSource: Invalid url (%s).", srcUrl);
return UNKNOWN_ERROR;
}
if (oscl_strlen(srcUrl) > MAX_STRING_LENGTH) {
LOGE("setDataSource: Data source url length (%d) is too long.", oscl_strlen(srcUrl));
return UNKNOWN_ERROR;
}
clearCache();
return doSetDataSource(srcUrl);
}
status_t MetadataDriver::doSetDataSource(const char* dataSrcUrl)
{
LOGV("doSetDataSource");
if (mMode & GET_FRAME_ONLY) {
#if BEST_THUMBNAIL_MODE
mFrameSelector.iSelectionMethod = PVFrameSelector::SPECIFIC_FRAME;
mFrameSelector.iFrameInfo.iTimeOffsetMilliSec = 0;
#else
mFrameSelector.iSelectionMethod=PVFrameSelector::SPECIFIC_FRAME;
mFrameSelector.iFrameInfo.iFrameIndex=0;
#endif
}
mIsSetDataSourceSuccessful = false;
oscl_wchar tmpWCharBuf[MAX_STRING_LENGTH];
oscl_UTF8ToUnicode(dataSrcUrl, oscl_strlen(dataSrcUrl), tmpWCharBuf, sizeof(tmpWCharBuf));
mDataSourceUrl.set(tmpWCharBuf, oscl_strlen(tmpWCharBuf));
mSyncSem = new OsclSemaphore();
mSyncSem->Create();
createThreadEtc(MetadataDriver::startDriverThread, this, "PVMetadataRetriever");
mSyncSem->Wait();
return mIsSetDataSourceSuccessful? OK: UNKNOWN_ERROR;
}
VideoFrame* MetadataDriver::captureFrame()
{
LOGV("captureFrame");
if (mMode & GET_FRAME_ONLY) { // copy out
if (mVideoFrame != NULL && mVideoFrame->mSize > 0) {
return new VideoFrame(*mVideoFrame);
} else {
LOGE("failed to capture frame");
return NULL;
}
}
LOGE("captureFrame: invalid mode (%d) to capture a frame", mMode);
return NULL;
}
void MetadataDriver::doColorConversion()
{
LOGV("doColorConversion");
// Do color conversion using PV's color conversion utility
int width = mFrameBufferProp.iFrameWidth;
int height = mFrameBufferProp.iFrameHeight;
int displayWidth = mFrameBufferProp.iDisplayWidth;
int displayHeight = mFrameBufferProp.iDisplayHeight;
SkBitmap *bitmap = new SkBitmap();
if (!bitmap) {
LOGE("doColorConversion: cannot instantiate a SkBitmap object.");
return;
}
bitmap->setConfig(SkBitmap::kRGB_565_Config, displayWidth, displayHeight);
if (!bitmap->allocPixels()) {
LOGE("allocPixels failed");
delete bitmap;
return;
}
// When passing parameters in Init call of ColorConverter library
// we need to take care of passing even width and height to the CC.
// If Width is odd then making it even as below
// will reduce the pitch by 1. This may result in a tilted image for
// clips with odd width.
ColorConvertBase* colorConverter = ColorConvert16::NewL();
if (!colorConverter ||
!colorConverter->Init(((width)&(~1)), ((height)&(~1)), ((width)&(~1)), displayWidth, ((displayHeight)&(~1)), ((displayWidth)&(~1)), CCROTATE_NONE) ||
//!colorConverter->Init(width, height, width, displayWidth, displayHeight, displayWidth, CCROTATE_NONE) ||
!colorConverter->SetMode(1) ||
!colorConverter->Convert(mFrameBuffer, (uint8*)bitmap->getPixels())) {
LOGE("failed to do color conversion");
delete colorConverter;
delete bitmap;
return;
}
delete colorConverter;
// Store the SkBitmap pixels in a private shared structure with known
// internal memory layout so that the pixels can be sent across the
// binder interface
delete mVideoFrame;
mVideoFrame = new VideoFrame();
if (!mVideoFrame) {
LOGE("failed to allocate memory for a VideoFrame object");
delete bitmap;
return;
}
mVideoFrame->mWidth = width;
mVideoFrame->mHeight = height;
mVideoFrame->mDisplayWidth = displayWidth;
mVideoFrame->mDisplayHeight = displayHeight;
mVideoFrame->mSize = bitmap->getSize();
LOGV("display width (%d) and height (%d), and size (%d)", displayWidth, displayHeight, mVideoFrame->mSize);
mVideoFrame->mData = new uint8[mVideoFrame->mSize];
if (!mVideoFrame->mData) {
LOGE("doColorConversion: cannot allocate buffer to hold SkBitmap pixels");
delete bitmap;
delete mVideoFrame;
mVideoFrame = NULL;
return;
}
memcpy(mVideoFrame->mData, (uint8*) bitmap->getPixels(), mVideoFrame->mSize);
delete bitmap;
}
// Instantiate a frame and metadata utility object.
void MetadataDriver::handleCreate()
{
LOGV("handleCreate");
int error = 0;
OSCL_TRY(error, mUtil = PVFrameAndMetadataFactory::CreateFrameAndMetadataUtility((char*)PVMF_MIME_YUV420, this, this, this, false));
if (error || mUtil->SetMode(PV_FRAME_METADATA_INTERFACE_MODE_SOURCE_METADATA_AND_THUMBNAIL) != PVMFSuccess) {
handleCommandFailure();
} else {
mState = STATE_ADD_DATA_SOURCE;
RunIfNotReady();
}
}
// Create a data source and add it.
void MetadataDriver::handleAddDataSource()
{
LOGV("handleAddDataSource");
int error = 0;
mDataSource = new PVPlayerDataSourceURL;
if (mDataSource) {
mDataSource->SetDataSourceURL(mDataSourceUrl);
mDataSource->SetDataSourceFormatType((char*)PVMF_MIME_FORMAT_UNKNOWN);
if (mMode & GET_FRAME_ONLY) {
#if BEST_THUMBNAIL_MODE
// Set the intent to thumbnails.
mLocalDataSource = new PVMFLocalDataSource();
mLocalDataSource->iIntent = BITMASK_PVMF_SOURCE_INTENT_THUMBNAILS;
mDataSource->SetDataSourceContextData((OsclAny*)mLocalDataSource);
#endif
}
OSCL_TRY(error, mCmdId = mUtil->AddDataSource(*mDataSource, (OsclAny*)&mContextObject));
OSCL_FIRST_CATCH_ANY(error, handleCommandFailure());
}
}
void MetadataDriver::handleRemoveDataSource()
{
LOGV("handleRemoveDataSource");
int error = 0;
OSCL_TRY(error, mCmdId = mUtil->RemoveDataSource(*mDataSource, (OsclAny*)&mContextObject));
OSCL_FIRST_CATCH_ANY(error, handleCommandFailure());
}
// Clean up, due to either failure or task completion.
void MetadataDriver::handleCleanUp()
{
LOGV("handleCleanUp");
if (mUtil)
{
PVFrameAndMetadataFactory::DeleteFrameAndMetadataUtility(mUtil);
mUtil = NULL;
}
#if BEST_THUMBNAIL_MODE
delete mLocalDataSource;
mLocalDataSource = NULL;
#endif
delete mDataSource;
mDataSource = NULL;
OsclExecScheduler *sched=OsclExecScheduler::Current();
if (sched) {
sched->StopScheduler();
}
}
// Retrieve all the available metadata keys.
void MetadataDriver::handleGetMetadataKeys()
{
LOGV("handleGetMetadataKeys");
int error = 0;
mMetadataKeyList.clear();
OSCL_TRY(error, mCmdId = mUtil->GetMetadataKeys(mMetadataKeyList, 0, -1, NULL, (OsclAny*)&mContextObject));
OSCL_FIRST_CATCH_ANY(error, handleCommandFailure());
}
// Retrieve a frame and store the contents into an internal buffer.
void MetadataDriver::handleGetFrame()
{
LOGV("handleGetFrame");
int error = 0;
mFrameBufferSize = MAX_VIDEO_FRAME_SIZE;
OSCL_TRY(error, mCmdId = mUtil->GetFrame(mFrameSelector, mFrameBuffer, mFrameBufferSize, mFrameBufferProp, (OsclAny*)&mContextObject));
OSCL_FIRST_CATCH_ANY(error, handleCommandFailure());
}
// Retrieve all the available metadata values associated with the given keys.
void MetadataDriver::handleGetMetadataValues()
{
LOGV("handleGetMetadataValues");
int error = 0;
mNumMetadataValues = 0;
mMetadataValueList.clear();
trimKeys(); // Switch to use actual supported key list.
OSCL_TRY(error, mCmdId = mUtil->GetMetadataValues(mActualMetadataKeyList, 0, -1, mNumMetadataValues, mMetadataValueList, (OsclAny*)&mContextObject));
OSCL_FIRST_CATCH_ANY(error, handleCommandFailure());
}
void MetadataDriver::Run()
{
LOGV("Run (%d)", mState);
switch(mState) {
case STATE_CREATE:
handleCreate();
break;
case STATE_ADD_DATA_SOURCE:
handleAddDataSource();
break;
case STATE_GET_METADATA_KEYS:
handleGetMetadataKeys();
break;
case STATE_GET_METADATA_VALUES:
handleGetMetadataValues();
break;
case STATE_GET_FRAME:
handleGetFrame();
break;
case STATE_REMOVE_DATA_SOURCE:
handleRemoveDataSource();
break;
default:
handleCleanUp();
break;
}
}
bool MetadataDriver::isCommandSuccessful(const PVCmdResponse& aResponse) const
{
LOGV("isCommandSuccessful");
bool success = ((aResponse.GetCmdId() == mCmdId) &&
(aResponse.GetCmdStatus() == PVMFSuccess) &&
(aResponse.GetContext() == (OsclAny*)&mContextObject));
if (!success) {
LOGE("isCommandSuccessful: Command id(%d and expected %d) and status (%d and expected %d), data corruption (%s) at state (%d).",
aResponse.GetCmdId(), mCmdId, aResponse.GetCmdStatus(), PVMFSuccess, (aResponse.GetContext() == (OsclAny*)&mContextObject)? "false": "true", mState);
}
return success;
}
void MetadataDriver::handleCommandFailure()
{
LOGV("handleCommandFailure");
if (mState == STATE_REMOVE_DATA_SOURCE) {
mState = STATE_CLEANUP_AND_COMPLETE;
}
else{
mState = STATE_REMOVE_DATA_SOURCE;
}
RunIfNotReady();
}
// Callback handler for a request completion by frameandmetadatautility.
void MetadataDriver::CommandCompleted(const PVCmdResponse& aResponse)
{
LOGV("CommandCompleted (%d)", mState);
if (!isCommandSuccessful(aResponse)) {
handleCommandFailure();
return;
}
switch(mState) {
case STATE_ADD_DATA_SOURCE:
if (mMode & GET_METADATA_ONLY) {
mState = STATE_GET_METADATA_KEYS;
} else if (mMode & GET_FRAME_ONLY) {
mState = STATE_GET_FRAME;
} else {
LOGV("CommandCompleted: Neither retrieve metadata nor capture frame.");
mState = STATE_REMOVE_DATA_SOURCE;
}
mIsSetDataSourceSuccessful = true;
break;
case STATE_GET_METADATA_KEYS:
mState = STATE_GET_METADATA_VALUES;
break;
case STATE_GET_METADATA_VALUES:
if (mMode & GET_FRAME_ONLY) {
mState = STATE_GET_FRAME;
} else {
mState = STATE_REMOVE_DATA_SOURCE;
}
cacheMetadataRetrievalResults();
break;
case STATE_GET_FRAME:
doColorConversion();
mState = STATE_REMOVE_DATA_SOURCE;
break;
case STATE_REMOVE_DATA_SOURCE:
mState = STATE_CLEANUP_AND_COMPLETE;
break;
default:
mState = STATE_CLEANUP_AND_COMPLETE;
break;
}
RunIfNotReady();
}
void MetadataDriver::HandleErrorEvent(const PVAsyncErrorEvent& aEvent)
{
// Error occurs, clean up and terminate.
LOGE("HandleErrorEvent: Event [type(%d), response type(%d)] received.", aEvent.GetEventType(), aEvent.GetResponseType());
handleCommandFailure();
}
void MetadataDriver::HandleInformationalEvent(const PVAsyncInformationalEvent& aEvent)
{
LOGV("HandleInformationalEvent: Event [type(%d), response type(%d)] received.", aEvent.GetEventType(), aEvent.GetResponseType());
}
void MetadataDriver::closeSharedFdIfNecessary() {
if (mSharedFd >= 0) {
close(mSharedFd);
mSharedFd = -1;
}
}
//------------------------------------------------------------------------------
#include <media/PVMetadataRetriever.h>
namespace android {
//#define LOG_NDEBUG 0
//#define LOG_TAG "PVMetadataRetriever"
// A concrete subclass of MediaMetadataRetrieverInterface implementation
// Use the MetadataDriver object as a delegate and forward related calls
// to the MetadataDriver object.
PVMetadataRetriever::PVMetadataRetriever()
{
LOGV("constructor");
mMetadataDriver = new MetadataDriver();
}
PVMetadataRetriever::~PVMetadataRetriever()
{
LOGV("destructor");
Mutex::Autolock lock(mLock);
delete mMetadataDriver;
}
status_t PVMetadataRetriever::setDataSource(const char *url)
{
LOGV("setDataSource (%s)", url);
Mutex::Autolock lock(mLock);
if (mMetadataDriver == 0) {
LOGE("No MetadataDriver available");
return INVALID_OPERATION;
}
if (url == 0) {
LOGE("Null pointer is passed as argument");
return INVALID_OPERATION;
}
return mMetadataDriver->setDataSource(url);
}
status_t PVMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
{
LOGV("setDataSource fd(%d), offset(%lld), length(%lld)", fd, offset, length);
Mutex::Autolock lock(mLock);
if (mMetadataDriver == 0) {
LOGE("No MetadataDriver available");
return INVALID_OPERATION;
}
return mMetadataDriver->setDataSourceFd(fd, offset, length);
}
status_t PVMetadataRetriever::setMode(int mode)
{
LOGV("setMode (%d)", mode);
Mutex::Autolock lock(mLock);
if (mMetadataDriver == 0) {
LOGE("No MetadataDriver available");
return NO_INIT;
}
if (mode < METADATA_MODE_NOOP ||
mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
LOGE("set to invalid mode (%d)", mode);
return BAD_VALUE;
}
return mMetadataDriver->setMode(mode);
}
status_t PVMetadataRetriever::getMode(int* mode) const
{
LOGV("getMode");
Mutex::Autolock lock(mLock);
if (mMetadataDriver == 0) {
LOGE("No MetadataDriver available");
return INVALID_OPERATION;
}
if (mode == 0) {
LOGE("Null pointer is passed as argument");
return INVALID_OPERATION;
}
return mMetadataDriver->getMode(mode);
}
VideoFrame *PVMetadataRetriever::captureFrame()
{
LOGV("captureFrame");
Mutex::Autolock lock(mLock);
if (mMetadataDriver == 0) {
LOGE("No MetadataDriver available");
return NULL;
}
return mMetadataDriver->captureFrame();
}
MediaAlbumArt *PVMetadataRetriever::extractAlbumArt()
{
LOGV("extractAlbumArt");
Mutex::Autolock lock(mLock);
if (mMetadataDriver == 0) {
LOGE("No MetadataDriver available");
return NULL;
}
return mMetadataDriver->extractAlbumArt();
}
const char* PVMetadataRetriever::extractMetadata(int keyCode)
{
LOGV("extractMetadata");
Mutex::Autolock lock(mLock);
if (mMetadataDriver == 0) {
LOGE("No MetadataDriver available");
return NULL;
}
return mMetadataDriver->extractMetadata(keyCode);
}
}; // android