/* * Copyright (C) Texas Instruments - http://www.ti.com/ * * 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. */ /** * @file OMXDccDataSave.cpp * * This file contains functionality for handling DCC data save * */ #include "CameraHal.h" #include "OMXCameraAdapter.h" namespace Ti { namespace Camera { status_t OMXCameraAdapter::initDccFileDataSave(OMX_HANDLETYPE* omxHandle, int portIndex) { OMX_CONFIG_EXTRADATATYPE extraDataControl; status_t ret = NO_ERROR; OMX_ERRORTYPE eError = OMX_ErrorNone; LOG_FUNCTION_NAME; OMX_INIT_STRUCT_PTR (&extraDataControl, OMX_CONFIG_EXTRADATATYPE); extraDataControl.nPortIndex = portIndex; extraDataControl.eExtraDataType = OMX_TI_DccData; extraDataControl.bEnable = OMX_TRUE; eError = OMX_SetConfig(*omxHandle, ( OMX_INDEXTYPE ) OMX_IndexConfigOtherExtraDataControl, &extraDataControl); if ( OMX_ErrorNone != eError ) { CAMHAL_LOGEB("Error while configuring dcc data overwrite extra data 0x%x", eError); ret = NO_INIT; } if (mDccData.pData) { free(mDccData.pData); mDccData.pData = NULL; } LOG_FUNCTION_NAME_EXIT; return ret; } status_t OMXCameraAdapter::sniffDccFileDataSave(OMX_BUFFERHEADERTYPE* pBuffHeader) { OMX_OTHER_EXTRADATATYPE *extraData; OMX_TI_DCCDATATYPE* dccData; status_t ret = NO_ERROR; LOG_FUNCTION_NAME; android::AutoMutex lock(mDccDataLock); if ( NULL == pBuffHeader ) { CAMHAL_LOGEA("Invalid Buffer header"); LOG_FUNCTION_NAME_EXIT; return -EINVAL; } extraData = getExtradata(pBuffHeader->pPlatformPrivate, (OMX_EXTRADATATYPE)OMX_TI_DccData); if ( NULL != extraData ) { CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x", extraData->nSize, sizeof(OMX_OTHER_EXTRADATATYPE), extraData->eType, extraData->nDataSize, extraData->nPortIndex, extraData->nVersion); } else { CAMHAL_LOGVA("Invalid OMX_TI_DCCDATATYPE"); LOG_FUNCTION_NAME_EXIT; return NO_ERROR; } dccData = ( OMX_TI_DCCDATATYPE * ) extraData->data; if (NULL == dccData) { CAMHAL_LOGVA("OMX_TI_DCCDATATYPE is not found in extra data"); LOG_FUNCTION_NAME_EXIT; return NO_ERROR; } if (mDccData.pData) { free(mDccData.pData); } memcpy(&mDccData, dccData, sizeof(mDccData)); int dccDataSize = (int)dccData->nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData)); mDccData.pData = (OMX_PTR)malloc(dccDataSize); if (NULL == mDccData.pData) { CAMHAL_LOGVA("not enough memory for DCC data"); LOG_FUNCTION_NAME_EXIT; return NO_ERROR; } memcpy(mDccData.pData, &(dccData->pData), dccDataSize); LOG_FUNCTION_NAME_EXIT; return ret; } // Recursively searches given directory contents for the correct DCC file. // The directory must be opened and its stream pointer + path passed // as arguments. As this function is called recursively, to avoid excessive // stack usage the path param is reused -> this MUST be char array with // enough length!!! (260 should suffice). Path must end with "/". // The directory must also be closed in the caller function. // If the correct camera DCC file is found (based on the OMX measurement data) // its file stream pointer is returned. NULL is returned otherwise FILE * OMXCameraAdapter::parseDCCsubDir(DIR *pDir, char *path) { FILE *pFile; DIR *pSubDir; struct dirent *dirEntry; int initialPathLength = strlen(path); LOG_FUNCTION_NAME; /* check each directory entry */ while ((dirEntry = readdir(pDir)) != NULL) { if (dirEntry->d_name[0] == '.') continue; strcat(path, dirEntry->d_name); // dirEntry might be sub directory -> check it pSubDir = opendir(path); if (pSubDir) { // dirEntry is sub directory -> parse it strcat(path, "/"); pFile = parseDCCsubDir(pSubDir, path); closedir(pSubDir); if (pFile) { // the correct DCC file found! LOG_FUNCTION_NAME_EXIT; return pFile; } } else { // dirEntry is file -> open it pFile = fopen(path, "rb"); if (pFile) { // now check if this is the correct DCC file for that camera OMX_U32 dccFileIDword; OMX_U32 *dccFileDesc = (OMX_U32 *) &mDccData.nCameraModuleId; int i; // DCC file ID is 3 4-byte words for (i = 0; i < 3; i++) { if (fread(&dccFileIDword, sizeof(OMX_U32), 1, pFile) != 1) { // file too short break; } if (dccFileIDword != dccFileDesc[i]) { // DCC file ID word i does not match break; } } fclose(pFile); if (i == 3) { // the correct DCC file found! CAMHAL_LOGDB("DCC file to be updated: %s", path); // reopen it for modification pFile = fopen(path, "rb+"); if (!pFile) CAMHAL_LOGEB("ERROR: DCC file %s failed to open for modification", path); LOG_FUNCTION_NAME_EXIT; return pFile; } } else { CAMHAL_LOGEB("ERROR: Failed to open file %s for reading", path); } } // restore original path path[initialPathLength] = '\0'; } LOG_FUNCTION_NAME_EXIT; // DCC file not found in this directory tree return NULL; } // Finds the DCC file corresponding to the current camera based on the // OMX measurement data, opens it and returns the file stream pointer // (NULL on error or if file not found). // The folder string dccFolderPath must end with "/" FILE * OMXCameraAdapter::fopenCameraDCC(const char *dccFolderPath) { FILE *pFile; DIR *pDir; char dccPath[260]; LOG_FUNCTION_NAME; strcpy(dccPath, dccFolderPath); pDir = opendir(dccPath); if (!pDir) { CAMHAL_LOGEB("ERROR: Opening DCC directory %s failed", dccPath); LOG_FUNCTION_NAME_EXIT; return NULL; } pFile = parseDCCsubDir(pDir, dccPath); closedir(pDir); if (pFile) { CAMHAL_LOGDB("DCC file %s opened for modification", dccPath); } LOG_FUNCTION_NAME_EXIT; return pFile; } // Positions the DCC file stream pointer to the correct offset within the // correct usecase based on the OMX mesurement data. Returns 0 on success status_t OMXCameraAdapter::fseekDCCuseCasePos(FILE *pFile) { OMX_U32 dccNumUseCases = 0; OMX_U32 dccUseCaseData[3]; OMX_U32 i; LOG_FUNCTION_NAME; // position the file pointer to the DCC use cases section if (fseek(pFile, 80, SEEK_SET)) { CAMHAL_LOGEA("ERROR: Unexpected end of DCC file"); LOG_FUNCTION_NAME_EXIT; return -EINVAL; } if (fread(&dccNumUseCases, sizeof(OMX_U32), 1, pFile) != 1 || dccNumUseCases == 0) { CAMHAL_LOGEA("ERROR: DCC file contains 0 use cases"); LOG_FUNCTION_NAME_EXIT; return -EINVAL; } for (i = 0; i < dccNumUseCases; i++) { if (fread(dccUseCaseData, sizeof(OMX_U32), 3, pFile) != 3) { CAMHAL_LOGEA("ERROR: Unexpected end of DCC file"); LOG_FUNCTION_NAME_EXIT; return -EINVAL; } if (dccUseCaseData[0] == mDccData.nUseCaseId) { // DCC use case match! break; } } if (i == dccNumUseCases) { CAMHAL_LOGEB("ERROR: Use case ID %lu not found in DCC file", mDccData.nUseCaseId); LOG_FUNCTION_NAME_EXIT; return -EINVAL; } // dccUseCaseData[1] is the offset to the beginning of the actual use case // from the beginning of the file // mDccData.nOffset is the offset within the actual use case (from the // beginning of the use case to the data to be modified) if (fseek(pFile,dccUseCaseData[1] + mDccData.nOffset, SEEK_SET )) { CAMHAL_LOGEA("ERROR: Error setting the correct offset"); LOG_FUNCTION_NAME_EXIT; return -EINVAL; } LOG_FUNCTION_NAME_EXIT; return NO_ERROR; } status_t OMXCameraAdapter::saveDccFileDataSave() { status_t ret = NO_ERROR; LOG_FUNCTION_NAME; android::AutoMutex lock(mDccDataLock); if (mDccData.pData) { FILE *fd = fopenCameraDCC(DCC_PATH); if (fd) { if (!fseekDCCuseCasePos(fd)) { int dccDataSize = (int)mDccData.nSize - (int)(&(((OMX_TI_DCCDATATYPE*)0)->pData)); if (fwrite(mDccData.pData, dccDataSize, 1, fd) != 1) { CAMHAL_LOGEA("ERROR: Writing to DCC file failed"); } else { CAMHAL_LOGDA("DCC file successfully updated"); } } fclose(fd); } else { CAMHAL_LOGEA("ERROR: Correct DCC file not found or failed to open for modification"); } } LOG_FUNCTION_NAME_EXIT; return ret; } status_t OMXCameraAdapter::closeDccFileDataSave() { status_t ret = NO_ERROR; LOG_FUNCTION_NAME; android::AutoMutex lock(mDccDataLock); if (mDccData.pData) { free(mDccData.pData); mDccData.pData = NULL; } LOG_FUNCTION_NAME_EXIT; return ret; } } // namespace Camera } // namespace Ti