| /* |
| ** |
| ** 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 |