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