jpeg Exif file format Marker APP1 简介
jpeg Exif file format Marker APP1 分析
Android P 分析 HAL3 JpegNode 生成图片流程
我的设备 MTK cpu , Android P
在相册中查看手机拍摄的照片详情, 图片的相关信息: 制造商、日期、曝光时间、焦距、光圈值、GPS等信息。
那么拍摄照片的过程中是如何生成照片详情信息的呢?
照片中的信息保存的格式是 EXIF 。关于 Jpeg EIXF 的知识参考 jpeg Exif file format Marker APP1 简介 。
在分析 JpegNode 拍照pipeline 时,找到了 Jpeg EXIF 的代码。在这里简要分析。
代码位置:
vendor\mediatek\proprietary\hardware\mtkcam\utils\exif\v3\StdExif.cpp
vendor\mediatek\proprietary\hardware\mtkcam\include\mtkcam\utils\exif\IBaseCamExif.h -> ExifParams
初始化 ExifParams 的值。
MBOOL
StdExif::
init(
ExifParams const& rExifParams,
MBOOL const enableDbgExif
)
{
mExifParam = rExifParams;
MY_LOGI("mpExifParam(%p) ImageSize(%dx%d) FNumber(%d/10) FocalLegth(%d/1000) AWBMode(%d) Strobe(%d) AEMeterMode(%d) AEExpBias(%d)",
&mExifParam, mExifParam.u4ImageWidth, mExifParam.u4ImageHeight, mExifParam.u4FNumber, mExifParam.u4FocalLength,
mExifParam.u4AWBMode, mExifParam.u4FlashLightTimeus, mExifParam.u4AEMeterMode, mExifParam.i4AEExpBias);
MY_LOGI("CapExposureTime(%d) AEISOSpeed(%d) LightSource(%d) ExpProgram(%d) SceneCapType(%d) Orientation(%d) ZoomRatio(%d) Facing(%d) ICC(%d)",
mExifParam.u4CapExposureTime, mExifParam.u4AEISOSpeed, mExifParam.u4LightSource, mExifParam.u4ExpProgram,
mExifParam.u4SceneCapType, mExifParam.u4Orientation, mExifParam.u4ZoomRatio, mExifParam.u4Facing, mExifParam.u4ICCIdx);
MY_LOGI("GPS(%d), Altitude(%d), Latitude(%s), Longitude(%s), TimeStamp(%s), ProcessingMethod(%s)",
mExifParam.u4GpsIsOn, mExifParam.u4GPSAltitude, mExifParam.uGPSLatitude,
mExifParam.uGPSLongitude, mExifParam.uGPSTimeStamp, mExifParam.uGPSProcessingMethod);
// DebugExif: reset debug information
mDbgInfo.clear();
mMapModuleID.clear();
//
// Exif Utilitis
mpBaseExif = new ExifUtils();
if ( !(mpBaseExif->init(mExifParam.u4GpsIsOn)) )
{
MY_LOGE("mpBaseExif->init() fail");
return MFALSE;
}
//
mpDebugIdMap = new ExifIdMap();
//
mbEnableDbgExif = enableDbgExif;
mApp1Size = mpBaseExif->exifApp1SizeGet();
mDbgAppnSize = isEnableDbgExif() ? (APPN_SIZE*APPN_COUNT) : 0;
mICCIdx = mExifParam.u4ICCIdx ; // sRGB
mICCIdx = ::property_get_int32("jpeg.exif.icc.profile", mExifParam.u4ICCIdx);
mICCSize = mICCIdx==EXIF_ICC_PROFILE_SRGB ? sizeof(icc_profile_srgb)/sizeof(int8_t) :
(mICCIdx==EXIF_ICC_PROFILE_DCI_P3 ? sizeof(icc_profile_display_p3)/sizeof(int8_t) : 0) ;
MY_LOGD_IF(mLogLevel, "ICCIdx %d ICCSize %zu", mICCIdx, mICCSize);
//
if ( ! getDebugExif() ) {
MY_LOGE("bad getDebugExif()");
return MFALSE;
}
//
if ( ! getBufInfo_cam() ) {
MY_LOGE("bad getBufInfo_cam()");
return MFALSE;
}
//
return MTRUE;
}
struct ExifParams {
MUINT32 u4ImageWidth; // Image width
MUINT32 u4ImageHeight; // Image height
//
MUINT32 u4FNumber; // Format: F2.8 = 28
MUINT32 u4FocalLength; // Format: FL 3.5 = 350
MUINT32 u4FocalLength35mm; // Format: FL35mm 28 = 28
MUINT32 u4AWBMode; // White balance mode
MUINT32 u4LightSource; // Light Source mode
MUINT32 u4ExpProgram; // Exposure Program
MUINT32 u4SceneCapType; // Scene Capture Type
MUINT32 u4FlashLightTimeus; // Strobe on/off
MUINT32 u4AEMeterMode; // Exposure metering mode
MINT32 i4AEExpBias; // Exposure index*10
MUINT32 u4CapExposureTime; //
MUINT32 u4AEISOSpeed; // AE ISO value
//
MUINT32 u4GpsIsOn;
MUINT32 u4GPSAltitude;
MUINT8 uGPSLatitude[32];
MUINT8 uGPSLongitude[32];
MUINT8 uGPSTimeStamp[32];
MUINT8 uGPSProcessingMethod[64]; //(values of "GPS", "CELLID", "WLAN" or "MANUAL" by the EXIF spec.)
//
MUINT32 u4Orientation; // 0, 90, 180, 270
MUINT32 u4ZoomRatio; // Digital zoom ratio (x100) For example, 100, 114, and 132 refer to 1.00, 1.14, and 1.32 respectively.
//
MUINT32 u4Facing; // 1: front camera, 0: not front
MUINT32 u4ICCIdx;
//
public: Operations.
ExifParams() { ::memset(this, 0, sizeof(ExifParams)); }
};
void
StdExif::
updateStdExif(exifAPP1Info_s* exifApp1Info)
{
/*********************************************************************************
GPS
**********************************************************************************/
...
/*********************************************************************************
common
**********************************************************************************/
...
/*********************************************************************************
3A
**********************************************************************************/
...
/*********************************************************************************
update customized exif
**********************************************************************************/
...
/*********************************************************************************
MISC
**********************************************************************************/
// [flashPixVer]
memcpy(exifApp1Info->strFlashPixVer, "0100 ", 5);
// [exposure mode]
exifApp1Info->exposureMode = 0; // 0 means Auto exposure
}
如下代码,第一步调用 updateStdExif(&exifApp1Info); 生成 EXIF APP1
status_t
StdExif::
make(
MUINTPTR const outputExifBuf,
size_t& rOutputExifSize
)
{
int ret = 0;
mpOutputExifBuf = outputExifBuf;
// set 0 first for error return
rOutputExifSize = 0;
MY_LOGI("out buffer(%#" PRIxPTR ")", getBufAddr());
unsigned int u4OutputExifSize = 0;
exifAPP1Info_s exifApp1Info;
exifImageInfo_s exifImgInfo;
// (1) Fill exifApp1Info
updateStdExif(&exifApp1Info);
// (2) Fill exifImgInfo
::memset(&exifImgInfo, 0, sizeof(exifImageInfo_t));
exifImgInfo.bufAddr = getBufAddr();
exifImgInfo.mainWidth = mExifParam.u4ImageWidth;
exifImgInfo.mainHeight = mExifParam.u4ImageHeight;
exifImgInfo.thumbSize = getThumbnailSize();
ret = mpBaseExif->exifApp1Make(&exifImgInfo, &exifApp1Info, &u4OutputExifSize);
rOutputExifSize = (size_t)u4OutputExifSize;
// (4) Append App2
int app2 = 2;
unsigned int app2ReturnSize = 0;
int size = mICCSize; // Data(n bytes)
unsigned char *pAddr = (unsigned char*)getBufAddr()+ getStdExifSize() + getThumbnailSize();
MY_LOGD_IF(mLogLevel,"offset %zu buf %p ", getBufAddr(), getStdExifSize() + getThumbnailSize() , pAddr);
if(mICCIdx == EXIF_ICC_PROFILE_SRGB) {
ret = mpBaseExif->exifAppnMake(app2, pAddr, (unsigned char*)&icc_profile_srgb, size, &app2ReturnSize, 0);
}
else if(mICCIdx == EXIF_ICC_PROFILE_DCI_P3) {
ret = mpBaseExif->exifAppnMake(app2, pAddr, (unsigned char*)&icc_profile_display_p3, size, &app2ReturnSize, 0);
}
else
MY_LOGE("not support ICC profile %d", mICCIdx);
// return app2ReturnSize is mICCSize + 2 +2 (Data(n bytes) + Data size(2 bytes) + Data tag(2 bytes))
// (3) Append debug exif
if ( isEnableDbgExif() )
{
updateDbgExif();
}
return (status_t)ret;
}
上述代码简要概述了相机拍照时 JpegNode 调用 StdExif 生成照片详细信息的流程。
如果需要加入自定义的照片信息,修改 StudExif.cpp 即可。