summaryrefslogtreecommitdiff
authorGuosong Zhou <guosong.zhou@amlogic.com>2017-03-15 02:54:29 (GMT)
committer Guosong Zhou <guosong.zhou@amlogic.com>2017-03-15 04:43:05 (GMT)
commit8db828db7f121bcee01fc52c651a0504a5f8b394 (patch)
tree1803349ded8540f3835f74b9d2e7a371b1977b28
parentd846b15e01a881a9d92a4dcaee1fea167d64cea7 (diff)
downloadcamera-8db828db7f121bcee01fc52c651a0504a5f8b394.zip
camera-8db828db7f121bcee01fc52c651a0504a5f8b394.tar.gz
camera-8db828db7f121bcee01fc52c651a0504a5f8b394.tar.bz2
PD#140856: camera: fix android N camera cts when plug usb camera
Change-Id: I7d020f07f48a8e4ae53558d615267b5a45077787 Signed-off-by: Guosong Zhou <guosong.zhou@amlogic.com>
Diffstat
-rw-r--r--v3/Android.mk4
-rw-r--r--v3/EmulatedCamera3.cpp2
-rw-r--r--v3/EmulatedFakeCamera3.cpp99
-rw-r--r--v3/EmulatedFakeCamera3.h1
-rw-r--r--[-rwxr-xr-x]v3/EmulatedFakeCamera3Info.cpp1
-rw-r--r--[-rwxr-xr-x]v3/VendorTags.cpp7
-rw-r--r--v3/fake-pipeline2/Base.h2
-rw-r--r--v3/fake-pipeline2/JpegCompressor.cpp689
-rw-r--r--v3/fake-pipeline2/JpegCompressor.h26
-rw-r--r--v3/fake-pipeline2/Sensor.cpp45
-rw-r--r--v3/fake-pipeline2/Sensor.h2
11 files changed, 789 insertions, 89 deletions
diff --git a/v3/Android.mk b/v3/Android.mk
index 88475ce..4f465b7 100644
--- a/v3/Android.mk
+++ b/v3/Android.mk
@@ -57,7 +57,8 @@ LOCAL_SHARED_LIBRARIES:= \
libdl \
libjpeg \
libjhead \
- libexpat
+ libexpat \
+ libexif
# JPEG conversion libraries and includes.
LOCAL_SHARED_LIBRARIES += \
@@ -94,6 +95,7 @@ LOCAL_C_INCLUDES += external/jpeg \
$(LOCAL_PATH)/inc \
$(call include-path-for, camera) \
$(TOP)/external/expat/lib \
+ $(TOP)/external/libexif \
LOCAL_SRC_FILES := \
EmulatedCameraHal.cpp \
diff --git a/v3/EmulatedCamera3.cpp b/v3/EmulatedCamera3.cpp
index 0cd6a3e..dc0ce99 100644
--- a/v3/EmulatedCamera3.cpp
+++ b/v3/EmulatedCamera3.cpp
@@ -308,7 +308,7 @@ camera3_device_ops_t EmulatedCamera3::sDeviceOps = {
NULL,//EmulatedCamera3::register_stream_buffers,
EmulatedCamera3::construct_default_request_settings,
EmulatedCamera3::process_capture_request,
- EmulatedCamera3::get_metadata_vendor_tag_ops,
+ NULL,//EmulatedCamera3::get_metadata_vendor_tag_ops,
EmulatedCamera3::dump,
EmulatedCamera3::flush,
};
diff --git a/v3/EmulatedFakeCamera3.cpp b/v3/EmulatedFakeCamera3.cpp
index 54ff21d..04574cb 100644
--- a/v3/EmulatedFakeCamera3.cpp
+++ b/v3/EmulatedFakeCamera3.cpp
@@ -148,6 +148,7 @@ ssize_t EmulatedFakeCamera3::getJpegBufferSize(int width, int height) {
}
ssize_t maxJpegBufferSize = JpegCompressor::kMaxJpegSize;
+#if PLATFORM_SDK_VERSION <= 22
// Calculate final jpeg buffer size for the given resolution.
float scaleFactor = ((float) (width * height)) /
(maxJpegResolution.width * maxJpegResolution.height);
@@ -158,6 +159,17 @@ ssize_t EmulatedFakeCamera3::getJpegBufferSize(int width, int height) {
} else if (jpegBufferSize < kMinJpegBufferSize) {
jpegBufferSize = kMinJpegBufferSize;
}
+#else
+ assert(kMinJpegBufferSize < maxJpegBufferSize);
+ // Calculate final jpeg buffer size for the given resolution.
+ float scaleFactor = ((float) (width * height)) /
+ (maxJpegResolution.width * maxJpegResolution.height);
+ ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) +
+ kMinJpegBufferSize;
+ if (jpegBufferSize > maxJpegBufferSize)
+ jpegBufferSize = maxJpegBufferSize;
+#endif
+
return jpegBufferSize;
}
@@ -616,9 +628,6 @@ status_t EmulatedFakeCamera3::configureStreams(
privStream->alive = true;
privStream->registered = false;
- newStream->usage =
- mSensor->getStreamUsage(newStream->stream_type);
-
DBG_LOGB("stream_type=%d\n", newStream->stream_type);
newStream->max_buffers = kMaxBufferCount;
newStream->priv = privStream;
@@ -630,6 +639,10 @@ status_t EmulatedFakeCamera3::configureStreams(
CAMHAL_LOGDA("Existing stream ?");
privStream->alive = true;
}
+ // Always update usage and max buffers
+ /*for cts CameraDeviceTest -> testPrepare*/
+ newStream->max_buffers = kMaxBufferCount;
+ newStream->usage = mSensor->getStreamUsage(newStream->stream_type);
DBG_LOGB("%d, newStream=%p, stream_type=%d, usage=%x, priv=%p, w*h=%dx%d\n",
i, newStream, newStream->stream_type, newStream->usage, newStream->priv, newStream->width, newStream->height);
}
@@ -831,7 +844,7 @@ const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings(
default:
hotPixelMode = ANDROID_HOT_PIXEL_MODE_FAST;
demosaicMode = ANDROID_DEMOSAIC_MODE_FAST;
- noiseMode = ANDROID_NOISE_REDUCTION_MODE_FAST;
+ noiseMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
shadingMode = ANDROID_SHADING_MODE_FAST;
colorMode = ANDROID_COLOR_CORRECTION_MODE_FAST;
tonemapMode = ANDROID_TONEMAP_MODE_FAST;
@@ -901,7 +914,7 @@ const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings(
settings.update(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
static const int32_t thumbnailSize[2] = {
- 160, 120
+ 320, 240
};
settings.update(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
@@ -1068,6 +1081,10 @@ const camera_metadata_t* EmulatedFakeCamera3::constructDefaultRequestSettings(
// aeState, awbState, afState only in frame
+ uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;
+ settings.update(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ &aberrationMode, 1);
+
mDefaultTemplates[type] = settings.release();
return mDefaultTemplates[type];
@@ -1077,7 +1094,7 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
camera3_capture_request *request) {
status_t res;
nsecs_t exposureTime;
- nsecs_t frameDuration;
+ //nsecs_t frameDuration;
uint32_t sensitivity;
uint32_t frameNumber;
bool mHaveThumbnail = false;
@@ -1196,6 +1213,18 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
uint8_t antiBanding = 0;
uint8_t effectMode = 0;
int exposureCmp = 0;
+ int32_t previewFpsRange[2];
+
+ e = settings.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+ if (e.count == 0) {
+ ALOGE("%s: get ANDROID_CONTROL_AE_TARGET_FPS_RANGE failed!", __FUNCTION__);
+ return BAD_VALUE;
+ } else {
+ previewFpsRange[0] = e.data.i32[0];
+ previewFpsRange[1] = e.data.i32[1];
+ mFrameDuration = 1000000000 / previewFpsRange[1];
+ ALOGI("set ANDROID_CONTROL_AE_TARGET_FPS_RANGE :%d,%d", previewFpsRange[0], previewFpsRange[1]);
+ }
e = settings.find(ANDROID_CONTROL_AE_ANTIBANDING_MODE);
if (e.count == 0) {
@@ -1247,12 +1276,6 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
}
}
- uint8_t len[] = {1};
- settings.update(ANDROID_REQUEST_PIPELINE_DEPTH, (uint8_t *)len, 1);
-
- uint8_t maxlen[] = {0};
- settings.update(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, (uint8_t *)maxlen, 1);
-
res = process3A(settings);
if (res != OK) {
ALOGVV("%s: process3A failed!", __FUNCTION__);
@@ -1270,7 +1293,7 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
uint32_t jpegpixelfmt;
exposureTime = settings.find(ANDROID_SENSOR_EXPOSURE_TIME).data.i64[0];
- frameDuration = settings.find(ANDROID_SENSOR_FRAME_DURATION).data.i64[0];
+ //frameDuration = settings.find(ANDROID_SENSOR_FRAME_DURATION).data.i64[0];
sensitivity = settings.find(ANDROID_SENSOR_SENSITIVITY).data.i32[0];
sensorBuffers = new Buffers();
@@ -1482,7 +1505,8 @@ status_t EmulatedFakeCamera3::processCaptureRequest(
* Configure sensor and queue up the request to the readout thread
*/
mSensor->setExposureTime(exposureTime);
- mSensor->setFrameDuration(frameDuration);
+ //mSensor->setFrameDuration(frameDuration);
+ mSensor->setFrameDuration(mFrameDuration);
mSensor->setSensitivity(sensitivity);
mSensor->setDestinationBuffers(sensorBuffers);
mSensor->setFrameNumber(request->frame_number);
@@ -1722,6 +1746,8 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
info.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, lensShadingMapSize,
sizeof(lensShadingMapSize)/sizeof(int32_t));
+ /*lens facing related camera feature*/
+ /*camera feature setting in /device/amlogic/xxx/xxx.mk files*/
uint8_t lensFacing = mFacingBack ?
ANDROID_LENS_FACING_BACK : ANDROID_LENS_FACING_FRONT;
info.update(ANDROID_LENS_FACING, &lensFacing, 1);
@@ -1769,11 +1795,6 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
info.update(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
sensorPhysicalSize, 2);
- info.update(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
- (int32_t*)Sensor::kResolution, 2);
-
- //(int32_t*)Sensor::kResolution, 2);
-
info.update(ANDROID_SENSOR_INFO_WHITE_LEVEL,
(int32_t*)&Sensor::kMaxRawValue, 1);
@@ -1818,8 +1839,8 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
static const uint8_t flashAvailable = 0;
info.update(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1);
- static const uint8_t flashstate = ANDROID_FLASH_STATE_UNAVAILABLE;
- info.update(ANDROID_FLASH_STATE, &flashstate, 1);
+ static const uint8_t flashstate = ANDROID_FLASH_STATE_UNAVAILABLE;
+ info.update(ANDROID_FLASH_STATE, &flashstate, 1);
static const int64_t flashChargeDuration = 0;
info.update(ANDROID_FLASH_INFO_CHARGE_DURATION, &flashChargeDuration, 1);
@@ -1829,13 +1850,19 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
info.update(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, &availableNBModes, 1);
// android.tonemap
+ static const uint8_t availabletonemapModes[] = {
+ ANDROID_TONEMAP_MODE_FAST,
+ ANDROID_TONEMAP_MODE_HIGH_QUALITY
+ };
+ info.update(ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES, availabletonemapModes,
+ sizeof(availabletonemapModes)/sizeof(availabletonemapModes[0]));
static const int32_t tonemapCurvePoints = 128;
info.update(ANDROID_TONEMAP_MAX_CURVE_POINTS, &tonemapCurvePoints, 1);
// android.scaler
- static const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
+ static const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
info.update(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
info.update(ANDROID_SCALER_AVAILABLE_FORMATS,
@@ -1871,9 +1898,13 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
full_size[2] = maxJpegResolution.width;
full_size[3] = maxJpegResolution.height;
}
+ /*activeArray.width <= pixelArraySize.Width && activeArray.height<= pixelArraySize.Height*/
info.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
(int32_t*)full_size,
sizeof(full_size)/sizeof(full_size[0]));
+ info.update(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+ (int32_t*)(&full_size[2]), 2);
+
duration = new int64_t[count];
if (duration == NULL) {
DBG_LOGA("allocate memory for duration failed");
@@ -1881,10 +1912,12 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
} else {
memset(duration,0,sizeof(int64_t)*count);
}
- duration_count = s->getStreamConfigurationDurations(picSizes, duration , count);
-
+ duration_count = s->getStreamConfigurationDurations(picSizes, duration, count, true);
info.update(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
duration, duration_count);
+
+ memset(duration,0,sizeof(int64_t)*count);
+ duration_count = s->getStreamConfigurationDurations(picSizes, duration, count, false);
info.update(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
duration, duration_count);
@@ -1901,6 +1934,7 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
static const int32_t jpegThumbnailSizes[] = {
0, 0,
+ 128, 72,
160, 120,
320, 240
};
@@ -2061,7 +2095,7 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
info.update(ANDROID_CONTROL_AE_COMPENSATION_STEP,
&exposureCompensationStep, 1);
- int32_t exposureCompensationRange[] = {0, 0};
+ int32_t exposureCompensationRange[] = {-6, 6};
info.update(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
exposureCompensationRange,
sizeof(exposureCompensationRange)/sizeof(int32_t));
@@ -2114,10 +2148,11 @@ status_t EmulatedFakeCamera3::constructStaticInfo() {
int32_t android_sync_max_latency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
info.update(ANDROID_SYNC_MAX_LATENCY, &android_sync_max_latency, 1);
- uint8_t len[] = {1};
+ uint8_t len[] = {1};
info.update(ANDROID_REQUEST_PIPELINE_DEPTH, (uint8_t *)len, 1);
- uint8_t maxlen[] = {2};
+ /*for cts BurstCaptureTest ->testYuvBurst */
+ uint8_t maxlen[] = {kMaxBufferCount};
info.update(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, (uint8_t *)maxlen, 1);
uint8_t cap[] = {
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
@@ -2597,8 +2632,10 @@ status_t EmulatedFakeCamera3::doFakeAWB(CameraMetadata &settings) {
case ANDROID_CONTROL_AWB_MODE_DAYLIGHT:
case ANDROID_CONTROL_AWB_MODE_SHADE:
mAwbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; //add for cts
- return mSensor->setAWB(awbMode);
- // OK
+ if (mSensorType == SENSOR_USB)
+ return OK;
+ else
+ return mSensor->setAWB(awbMode);
break;
default:
ALOGE("%s: Emulator doesn't support AWB mode %d",
@@ -2892,6 +2929,10 @@ bool EmulatedFakeCamera3::ReadoutThread::threadLoop() {
mCurrentRequest.settings.update(ANDROID_SENSOR_TIMESTAMP,
&captureTime, 1);
+ const uint8_t pipelineDepth = needJpeg ? kMaxBufferCount : kMaxBufferCount - 1;
+ mCurrentRequest.settings.update(ANDROID_REQUEST_PIPELINE_DEPTH,
+ &pipelineDepth, 1);
+
memset(&result, 0, sizeof(result));
result.frame_number = mCurrentRequest.frameNumber;
result.result = mCurrentRequest.settings.getAndLock();
diff --git a/v3/EmulatedFakeCamera3.h b/v3/EmulatedFakeCamera3.h
index 8428a93..83ea133 100644
--- a/v3/EmulatedFakeCamera3.h
+++ b/v3/EmulatedFakeCamera3.h
@@ -359,6 +359,7 @@ private:
int mZoomMin;
int mZoomMax;
int mZoomStep;
+ int mFrameDuration;
int mAeCounter;
nsecs_t mAeCurrentExposureTime;
diff --git a/v3/EmulatedFakeCamera3Info.cpp b/v3/EmulatedFakeCamera3Info.cpp
index 47d7f1c..5308dc4 100755..100644
--- a/v3/EmulatedFakeCamera3Info.cpp
+++ b/v3/EmulatedFakeCamera3Info.cpp
@@ -128,6 +128,7 @@ const struct EmulatedFakeCamera3::KeyInfo_s EmulatedFakeCamera3::sKeyInfoReq[] =
// {ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, LIMITED , MANUAL_POST_PROCESSING },
// {ANDROID_TONEMAP_CURVE, FULL , MANUAL_POST_PROCESSING },
// {ANDROID_COLOR_CORRECTION_ABERRATION_MODE, FULL , MANUAL_POST_PROCESSING },
+ {ANDROID_COLOR_CORRECTION_ABERRATION_MODE, LEGACY , BC},
// {ANDROID_SENSOR_FRAME_DURATION, LIMITED , MANUAL_SENSOR },
// {ANDROID_SENSOR_EXPOSURE_TIME, LIMITED , MANUAL_SENSOR },
diff --git a/v3/VendorTags.cpp b/v3/VendorTags.cpp
index 8aa1e59..6afe550 100755..100644
--- a/v3/VendorTags.cpp
+++ b/v3/VendorTags.cpp
@@ -67,8 +67,9 @@ enum vendor_tags {
ANDROID_LENS_FOCUS_DISTANCE, // float | public
ANDROID_LENS_OPTICAL_STABILIZATION_MODE, // enum | public
ANDROID_LENS_FACING, // enum | public
- ANDROID_LENS_OPTICAL_AXIS_ANGLE, // float[] | system
+#if PLATFORM_SDK_VERSION <= 22
ANDROID_LENS_POSITION, // float[] | system
+#endif
ANDROID_LENS_FOCUS_RANGE, // float[] | public
ANDROID_LENS_STATE, // enum | public
ANDROID_LENS_END,
@@ -116,10 +117,10 @@ vendor_tag_info_t fakevendor_lens[ANDROID_LENS_END -
{ "opticalStabilizationMode", TYPE_BYTE },
[ ANDROID_LENS_FACING - ANDROID_LENS_START ] =
{ "facing", TYPE_BYTE },
- [ ANDROID_LENS_OPTICAL_AXIS_ANGLE - ANDROID_LENS_START ] =
- { "opticalAxisAngle", TYPE_FLOAT },
+#if PLATFORM_SDK_VERSION <= 22
[ ANDROID_LENS_POSITION - ANDROID_LENS_START ] =
{ "position", TYPE_FLOAT },
+#endif
[ ANDROID_LENS_FOCUS_RANGE - ANDROID_LENS_START ] =
{ "focusRange", TYPE_FLOAT },
[ ANDROID_LENS_STATE - ANDROID_LENS_START ] =
diff --git a/v3/fake-pipeline2/Base.h b/v3/fake-pipeline2/Base.h
index 2437758..31d22e0 100644
--- a/v3/fake-pipeline2/Base.h
+++ b/v3/fake-pipeline2/Base.h
@@ -69,7 +69,7 @@ struct ExifInfo {
double longitude;
double latitude;
double altitude;
- uint8_t gpsProcessingMethod[32];
+ uint8_t gpsProcessingMethod[128];
bool has_longitude;
bool has_latitude;
bool has_altitude;
diff --git a/v3/fake-pipeline2/JpegCompressor.cpp b/v3/fake-pipeline2/JpegCompressor.cpp
index df528f9..6a24882 100644
--- a/v3/fake-pipeline2/JpegCompressor.cpp
+++ b/v3/fake-pipeline2/JpegCompressor.cpp
@@ -33,6 +33,7 @@
#define EXIF_MAKE_DEFAULT "default_make"
#define EXIF_MODEL_DEFAULT "default_model"
#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0]))
+#define FILE_BYTE_ORDER EXIF_BYTE_ORDER_INTEL
const size_t MARKER_LENGTH = 2; // length of a marker
const uint8_t MARK = 0xFF;
@@ -64,6 +65,18 @@ int extraSmallImg(unsigned char* SrcImg,int SrcW,int SrcH,
}
return 1;
}
+
+/* start of JPEG image data section */
+static const unsigned int image_data_offset = 20;
+
+/* raw EXIF header data */
+static const unsigned char exif_header[] = {
+ 0xff, 0xd8, 0xff, 0xe1
+};
+/* length of data in exif_header */
+static const unsigned int exif_header_len = sizeof(exif_header);
+
+
namespace android {
struct string_pair {
@@ -207,6 +220,164 @@ status_t JpegCompressor::readyToRun() {
return OK;
}
+status_t JpegCompressor::Create_Exif_Use_Libjpeg() {
+ ExifElementsTable* exiftable = NULL;
+ struct camera2_jpeg_blob blob;
+ int offset;
+ status_t res;
+ if (mNeedexif) {
+ memset(&blob,0,sizeof(struct camera2_jpeg_blob));
+ exiftable = new ExifElementsTable();
+ GenExif(exiftable);
+ }
+
+ if (mJpegRequest.mNeedThumbnail) {
+ res = thumbcompress();
+ }
+
+ if (exiftable) {
+ uint32_t realjpegsize = 0;
+ Section_t* exif_section = NULL;
+ ExifElementsTable* exif = exiftable;
+ exif->insertExifToJpeg((unsigned char*)mJpegBuffer.img,mMainJpegSize);
+ if ((mJpegRequest.mNeedThumbnail) && (mDstThumbBuffer != NULL)) {
+ exif->insertExifThumbnailImage((const char*)mDstThumbBuffer,mThumbJpegSize);
+ }
+ exif_section = FindSection(M_EXIF);
+ if (exif_section) {
+ exif->saveJpeg((unsigned char*) mJpegBuffer.img, mMainJpegSize + exif_section->Size);
+ }
+ for (uint32_t size = (mMainJpegSize + exif_section->Size - 2); size > 0; size--) {
+ if (checkJpegEnd(mJpegBuffer.img + size)) {
+ realjpegsize = (size + MARKER_LENGTH);
+ break;
+ }
+ }
+ offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
+ blob.jpeg_blob_id = 0x00FF;
+ blob.jpeg_size = realjpegsize;
+ memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
+ }
+
+ if (mNeedexif) {
+ if (exiftable != NULL) {
+ delete exiftable;
+ exiftable = NULL;
+ }
+ }
+ return res;
+}
+
+status_t JpegCompressor::Create_Exif_Use_Libexif() {
+ struct camera2_jpeg_blob blob;
+ int offset;
+ status_t res;
+ memset(&blob,0,sizeof(struct camera2_jpeg_blob));
+ if (mNeedexif) {
+ uint32_t realjpegsize = 0;
+ if (mJpegRequest.mNeedThumbnail) {
+ res = thumbcompress();
+ }
+
+ exif_buffer *sEb = get_exif_buffer();
+ if (sEb != NULL) {
+ if (mJpegRequest.mNeedThumbnail) {
+ uint8_t * mTempJpegBuffer = (uint8_t *)malloc(mMainJpegSize + sEb->size + mThumbJpegSize);
+ memset(mTempJpegBuffer, 0, sizeof(char) * (mMainJpegSize + sEb->size + mThumbJpegSize));
+ memcpy(mTempJpegBuffer, exif_header, exif_header_len);
+ mTempJpegBuffer[exif_header_len] = (sEb->size + mThumbJpegSize + 2) >> 8;
+ mTempJpegBuffer[exif_header_len + 1] = ((sEb->size + mThumbJpegSize + 2) & 0xff);
+ memcpy(mTempJpegBuffer + exif_header_len + 2, sEb->data, sEb->size);
+ memcpy(mTempJpegBuffer + exif_header_len + sEb->size + 2, mDstThumbBuffer, mThumbJpegSize);
+ memcpy(mTempJpegBuffer + exif_header_len + sEb->size + mThumbJpegSize+ 2,
+ mJpegBuffer.img + image_data_offset, mMainJpegSize - image_data_offset);
+ memcpy(mJpegBuffer.img, mTempJpegBuffer, mMainJpegSize + sEb->size + mThumbJpegSize);
+ if (mTempJpegBuffer != NULL) {
+ free(mTempJpegBuffer);
+ mTempJpegBuffer = NULL;
+ }
+ for (uint32_t size = (mMainJpegSize + sEb->size + mThumbJpegSize); size > 0; size--) {
+ if (checkJpegEnd(mJpegBuffer.img + size)) {
+ realjpegsize = (size + MARKER_LENGTH);
+ break;
+ }
+ }
+ offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
+ blob.jpeg_blob_id = 0x00FF;
+ blob.jpeg_size = realjpegsize;
+ memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
+ if (sEb != NULL) {
+ if (sEb->data) {
+ free(sEb->data);
+ sEb->data = NULL;
+ }
+ free(sEb);
+ sEb = NULL;
+ CAMHAL_LOGDA("free malloc sEb buffer");
+ }
+ } else {
+ uint8_t * mTempJpegBuffer = (uint8_t *)malloc(mMainJpegSize + sEb->size);
+ memset(mTempJpegBuffer, 0, sizeof(char) * (mMainJpegSize + sEb->size));
+ memcpy(mTempJpegBuffer, exif_header, exif_header_len);
+ mTempJpegBuffer[exif_header_len] = (sEb->size+2) >> 8;
+ mTempJpegBuffer[exif_header_len + 1] = ((sEb->size+2) & 0xff);
+ memcpy(mTempJpegBuffer + exif_header_len + 2, sEb->data, sEb->size);
+ memcpy(mTempJpegBuffer + exif_header_len + sEb->size + 2, mJpegBuffer.img + image_data_offset,
+ mMainJpegSize - image_data_offset);
+ memcpy(mJpegBuffer.img, mTempJpegBuffer, mMainJpegSize + sEb->size);
+ if (mTempJpegBuffer != NULL) {
+ free(mTempJpegBuffer);
+ mTempJpegBuffer = NULL;
+ }
+ for (uint32_t size = (mMainJpegSize + sEb->size); size > 0; size--) {
+ if (checkJpegEnd(mJpegBuffer.img + size)) {
+ realjpegsize = (size + MARKER_LENGTH);
+ break;
+ }
+ }
+ offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
+ blob.jpeg_blob_id = 0x00FF;
+ blob.jpeg_size = realjpegsize;
+ memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
+ if (sEb != NULL) {
+ if (sEb->data) {
+ free(sEb->data);
+ sEb->data = NULL;
+ }
+ free(sEb);
+ sEb = NULL;
+ CAMHAL_LOGDA("free malloc sEb buffer");
+ }
+ }
+ } else {
+ DBG_LOGA("get exif buffer failed, so only callback Main JPEG data");
+ for (uint32_t size = (mMainJpegSize + sEb->size); size > 0; size--) {
+ if (checkJpegEnd(mJpegBuffer.img + size)) {
+ realjpegsize = (size + MARKER_LENGTH);
+ break;
+ }
+ }
+ offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
+ blob.jpeg_blob_id = 0x00FF;
+ blob.jpeg_size = realjpegsize;
+ memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
+ }
+ } else {
+ uint32_t realjpegsize = 0;
+ for (uint32_t size = (mMainJpegSize); size > 0; size--) {
+ if (checkJpegEnd(mJpegBuffer.img + size)) {
+ realjpegsize = (size + MARKER_LENGTH);
+ break;
+ }
+ }
+ int offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
+ blob.jpeg_blob_id = 0x00FF;
+ blob.jpeg_size = realjpegsize;
+ memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
+ }
+ return res;
+}
+
bool JpegCompressor::threadLoop() {
status_t res;
CaptureRequest* ri = NULL;
@@ -273,61 +444,25 @@ bool JpegCompressor::threadLoop() {
struct timeval mTimeStart,mTimeend;
int intreval;
- ExifElementsTable* exiftable = NULL;
- struct camera2_jpeg_blob blob;
- int offset;
ALOGV("%s: Starting compression thread", __FUNCTION__);
-
gettimeofday(&mTimeStart, NULL);
+
res = compress();
- if (mNeedexif) {
- memset(&blob,0,sizeof(struct camera2_jpeg_blob));
- exiftable = new ExifElementsTable();
- GenExif(exiftable);
- }
- if (mJpegRequest.mNeedThumbnail) {
- res = thumbcompress();
- }
+#if PLATFORM_SDK_VERSION <= 22
+ Create_Exif_Use_Libjpeg();
+#else
+ Create_Exif_Use_Libexif();
+#endif
- if (exiftable) {
- uint32_t realjpegsize = 0;
- Section_t* exif_section = NULL;
- ExifElementsTable* exif = exiftable;
- exif->insertExifToJpeg((unsigned char*)mJpegBuffer.img,mMainJpegSize);
- if ((mJpegRequest.mNeedThumbnail) && (mDstThumbBuffer != NULL)) {
- exif->insertExifThumbnailImage((const char*)mDstThumbBuffer,mThumbJpegSize);
- }
- exif_section = FindSection(M_EXIF);
- if (exif_section) {
- exif->saveJpeg((unsigned char*) mJpegBuffer.img, mMainJpegSize + exif_section->Size);
- }
- for (uint32_t size = (mMainJpegSize + exif_section->Size - 2); size > 0; size--) {
- if (checkJpegEnd(mJpegBuffer.img + size)) {
- realjpegsize = (size + MARKER_LENGTH);
- break;
- }
- }
- int offset = mMaxbufsize-sizeof(struct camera2_jpeg_blob);
- blob.jpeg_blob_id = 0x00FF;
- blob.jpeg_size = realjpegsize;
- memcpy(mJpegBuffer.img+offset, &blob, sizeof(struct camera2_jpeg_blob));
- }
mListener->onJpegDone(mJpegBuffer, res == OK, mJpegRequest);
+
if (ri != NULL) {
if (ri->buf != NULL) {
delete ri->buf;
}
delete ri;
}
-
- if (mNeedexif) {
- if (exiftable != NULL) {
- delete exiftable;
- exiftable = NULL;
- }
- }
-
gettimeofday(&mTimeend, NULL);
intreval = (mTimeend.tv_sec - mTimeStart.tv_sec) * 1000 + ((mTimeend.tv_usec - mTimeStart.tv_usec))/1000;
ALOGD("jpeg compress cost time =%d ms",intreval);
@@ -964,6 +1099,474 @@ int JpegCompressor::GenExif(ExifElementsTable* exiftable)
}
return 1;
}
+
+void JpegCompressor::exif_entry_set_string (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, const char *s)
+{
+ ExifEntry *pE;
+
+ pE = exif_entry_new ();
+ exif_content_add_entry (pEdata->ifd[eEifd], pE);
+ exif_entry_initialize (pE, eEtag);
+ if (pE->data)
+ free (pE->data);
+ pE->components = strlen (s) + 1;
+ pE->size = sizeof (char) * pE->components;
+ pE->data = (unsigned char *) malloc (pE->size);
+ if (!pE->data) {
+ DBG_LOGB("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size);
+ exit (1);
+ }
+ strcpy ((char *) pE->data, (char *) s);
+ exif_entry_fix (pE);
+ exif_entry_unref (pE);
+}
+
+void JpegCompressor::exif_entry_set_short (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifShort n)
+{
+ ExifEntry *pE;
+ ExifByteOrder eO;
+
+ pE = exif_entry_new ();
+ exif_content_add_entry (pEdata->ifd[eEifd], pE);
+ exif_entry_initialize (pE, eEtag);
+ eO = exif_data_get_byte_order (pE->parent->parent);
+ if (pE->data) {
+ exif_set_short (pE->data, eO, n);
+ } else {
+ DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
+ }
+ exif_entry_fix (pE);
+ exif_entry_unref (pE);
+}
+
+void JpegCompressor::exif_entry_set_long (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifLong n)
+{
+ ExifEntry *pE;
+ ExifByteOrder eO;
+
+ pE = exif_entry_new ();
+ exif_content_add_entry (pEdata->ifd[eEifd], pE);
+ exif_entry_initialize (pE, eEtag);
+ eO = exif_data_get_byte_order (pE->parent->parent);
+ if (pE->data) {
+ exif_set_long (pE->data, eO, n);
+ } else {
+ DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
+ }
+ exif_entry_fix (pE);
+ exif_entry_unref (pE);
+}
+
+void JpegCompressor::exif_entry_set_rational (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifRational r)
+{
+ ExifEntry *pE;
+ ExifByteOrder eO;
+
+ pE = exif_entry_new ();
+ exif_content_add_entry (pEdata->ifd[eEifd], pE);
+ exif_entry_initialize (pE, eEtag);
+ eO = exif_data_get_byte_order (pE->parent->parent);
+ if (pE->data) {
+ exif_set_rational (pE->data, eO, r);
+ } else {
+ DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
+ }
+ exif_entry_fix (pE);
+ exif_entry_unref (pE);
+}
+
+void JpegCompressor::exif_entry_set_undefined (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, exif_buffer * buf)
+{
+ ExifEntry *pE;
+ pE = exif_entry_new ();
+ exif_content_add_entry (pEdata->ifd[eEifd], pE);
+ exif_entry_initialize (pE, eEtag);
+ if (buf != NULL) {
+ if (pE->data)
+ free (pE->data);
+ pE->components = buf->size;
+ pE->size = buf->size;
+ pE->data = (unsigned char *) malloc (pE->size);
+ if (!pE->data) {
+ DBG_LOGB("Cannot allocate %d bytes.\nTerminating.\n", (int) pE->size);
+ exit (1);
+ }
+ memcpy ((void *) pE->data, (void *) buf->data, buf->size);
+ }
+ exif_entry_fix (pE);
+ exif_entry_unref (pE);
+}
+
+/****************************************************************************
+ * Public API
+ ***************************************************************************/
+
+/* Get an existing tag, or create one if it doesn't exist */
+ExifEntry* JpegCompressor::init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag)
+{
+ ExifEntry *entry;
+ /* Return an existing tag if one exists */
+ if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) {
+ /* Allocate a new entry */
+ entry = exif_entry_new ();
+ assert(entry != NULL); /* catch an out of memory condition */
+ entry->tag = tag; /* tag must be set before calling
+ exif_content_add_entry */
+
+ /* Attach the ExifEntry to an IFD */
+ exif_content_add_entry (exif->ifd[ifd], entry);
+
+ /* Allocate memory for the entry and fill with default data */
+ exif_entry_initialize (entry, tag);
+
+ /* Ownership of the ExifEntry has now been passed to the IFD.
+ * One must be very careful in accessing a structure after
+ * unref'ing it; in this case, we know "entry" won't be freed
+ * because the reference count was bumped when it was added to
+ * the IFD.
+ */
+ exif_entry_unref(entry);
+ }
+ return entry;
+}
+
+/* Create a brand-new tag with a data field of the given length, in the
+ * given IFD. This is needed when exif_entry_initialize() isn't able to create
+ * this type of tag itself, or the default data length it creates isn't the
+ * correct length.
+ */
+ExifEntry *JpegCompressor::create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len)
+{
+ void *buf;
+ ExifEntry *entry;
+
+ /* Create a memory allocator to manage this ExifEntry */
+ ExifMem *mem = exif_mem_new_default();
+ assert(mem != NULL); /* catch an out of memory condition */
+
+ /* Create a new ExifEntry using our allocator */
+ entry = exif_entry_new_mem (mem);
+ assert(entry != NULL);
+
+ /* Allocate memory to use for holding the tag data */
+ buf = exif_mem_alloc(mem, len);
+ assert(buf != NULL);
+
+ /* Fill in the entry */
+ entry->data = (unsigned char*)buf;
+ entry->size = len;
+ entry->tag = tag;
+ entry->components = len;
+ entry->format = EXIF_FORMAT_UNDEFINED;
+
+ /* Attach the ExifEntry to an IFD */
+ exif_content_add_entry (exif->ifd[ifd], entry);
+
+ /* The ExifMem and ExifEntry are now owned elsewhere */
+ exif_mem_unref(mem);
+ exif_entry_unref(entry);
+
+ return entry;
+}
+
+void JpegCompressor::exif_entry_set_gps_coord(ExifData * pEdata, ExifTag eEtag,
+ ExifRational r1, ExifRational r2, ExifRational r3)
+{
+ ExifEntry *pE;
+ ExifByteOrder eO;
+
+ pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
+ 3 * exif_format_get_size(EXIF_FORMAT_RATIONAL));
+
+ pE->components = 3;
+ pE->format = EXIF_FORMAT_RATIONAL;
+
+ eO = exif_data_get_byte_order (pE->parent->parent);
+
+ if (pE->data) {
+ exif_set_rational (pE->data, eO, r1);
+ exif_set_rational (pE->data + exif_format_get_size (pE->format), eO, r2);
+ exif_set_rational (pE->data + 2 * exif_format_get_size (pE->format), eO, r3);
+ } else {
+ DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
+ }
+}
+
+void JpegCompressor::exif_entry_set_gps_altitude(ExifData * pEdata, ExifTag eEtag, ExifRational r1)
+{
+ ExifEntry *pE;
+ ExifByteOrder eO;
+
+ pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
+ 1 * exif_format_get_size(EXIF_FORMAT_RATIONAL));
+
+ pE->components = 1;
+ pE->format = EXIF_FORMAT_RATIONAL;
+
+ eO = exif_data_get_byte_order (pE->parent->parent);
+ if (pE->data) {
+ exif_set_rational (pE->data, eO, r1);
+ } else {
+ DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
+ }
+}
+
+void JpegCompressor::exif_entry_set_gps_coord_ref(ExifData * pEdata, ExifTag eEtag, const char *s)
+{
+ ExifEntry *pE;
+ ExifByteOrder eO;
+
+ pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
+ (strlen (s) + 1) * exif_format_get_size(EXIF_FORMAT_ASCII));
+
+ pE->components = strlen (s) + 1;
+ pE->format = EXIF_FORMAT_ASCII;
+
+ eO = exif_data_get_byte_order (pE->parent->parent);
+ if (pE->data) {
+ strcpy ((char *) pE->data, s);
+ } else {
+ DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
+ }
+}
+
+void JpegCompressor::exif_entry_set_gps_altitude_ref(ExifData * pEdata, ExifTag eEtag, ExifByte n)
+{
+ ExifEntry *pE;
+ ExifByteOrder eO;
+
+ pE = create_tag(pEdata, EXIF_IFD_GPS, eEtag,
+ 1 * exif_format_get_size(EXIF_FORMAT_BYTE));
+
+ pE->components = 1;
+ pE->format = EXIF_FORMAT_BYTE;
+
+ eO = exif_data_get_byte_order (pE->parent->parent);
+ if (pE->data) {
+ *(pE->data) = n;
+ } else {
+ DBG_LOGB("ERROR: unallocated e->data Tag %d\n", eEtag);
+ }
+}
+
+exif_buffer * JpegCompressor::get_exif_buffer() {
+
+ char exifcontent[256];
+ ExifData *pEd;
+ ExifEntry *entry;
+ exif_buffer *sEb;
+ ExifRational sR;
+ int res;
+ int orientation;
+ struct timeval sTv;
+ time_t times;
+ struct tm tmstruct;
+ char property[PROPERTY_VALUE_MAX];
+
+ sEb = (exif_buffer *) malloc (sizeof (exif_buffer));
+
+ pEd = exif_data_new ();
+
+ if (pEd == NULL)
+ goto EXIT;
+
+ /* Set the image options */
+ exif_data_set_option(pEd, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+ exif_data_set_data_type(pEd, EXIF_DATA_TYPE_COMPRESSED);
+ exif_data_set_byte_order(pEd, FILE_BYTE_ORDER);
+
+ property_get("ro.product.manufacturer", property, EXIF_MAKE_DEFAULT);
+ exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MAKE, property);
+ property_get("ro.product.model", property, EXIF_MODEL_DEFAULT);
+ exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_MODEL, property);
+
+ switch (mInfo.orientation) {
+ case 180:
+ orientation = 3;
+ //orientation = 1;
+ break;
+ case 90:
+ orientation = 6;
+ //orientation = 8;
+ break;
+ case 270:
+ orientation = 8;
+ break;
+ default:
+ orientation = 1;
+ break;
+ }
+
+ exif_entry_set_short(pEd, EXIF_IFD_0, EXIF_TAG_ORIENTATION, (ExifShort)orientation);
+
+ sR.numerator = 1;
+ sR.denominator = 629;
+ exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, sR);
+
+ /* time */
+ /* this sould be last resort */
+ time(&times);
+ tmstruct = *(localtime(&times)); //convert to local time
+ res = gettimeofday (&sTv, NULL);
+ strftime(exifcontent, 20, "%Y:%m:%d %H:%M:%S", &tmstruct);
+ exif_entry_set_string (pEd, EXIF_IFD_0, EXIF_TAG_DATE_TIME, exifcontent);
+ exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, exifcontent);
+ exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, exifcontent);
+
+ sR.numerator = 28;
+ sR.denominator = 10;
+ exif_entry_set_rational (pEd, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, sR);//android 6 is EXIF_TAG_APERTURE_VALUE
+
+ exif_entry_set_short(pEd, EXIF_IFD_EXIF, EXIF_TAG_FLASH, 0);
+
+ sR.numerator = 3299;
+ sR.denominator = 1000;
+ exif_entry_set_rational(pEd, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, sR);
+
+ memset(exifcontent, 0, sizeof(exifcontent));
+ snprintf(exifcontent, 20, "%06d", (int) sTv.tv_usec);
+ exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, exifcontent);
+ exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, exifcontent);
+ exif_entry_set_string (pEd, EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, exifcontent);
+
+ exif_entry_set_short (pEd, EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, 0);
+
+ if (mInfo.has_latitude) {
+ ExifRational r1, r2, r3;
+ int offset = 0;
+ /* gps data */
+ r1.denominator = 1;
+ r2.denominator = 1;
+ r3.denominator = 1;
+
+ float latitude = mInfo.latitude;
+ if (latitude < 0.0) {
+ latitude*= (float)(-1);
+ offset = 1;
+ }
+ r1.numerator = (uint32_t)latitude;
+ float latitudeminuts = (latitude-(float)(r1.numerator))*60;
+ r2.numerator = (uint32_t)latitudeminuts;
+ float latituseconds = (latitudeminuts-(float)(r2.numerator))*60+0.5;
+ r3.numerator = (uint32_t)latituseconds;
+ exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_LATITUDE, r1, r2, r3);
+ exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_LATITUDE_REF, offset == 1 ? "S":"N");
+ }
+
+ if (mInfo.has_longitude) {
+ ExifRational r1, r2, r3;
+ int offset = 0;
+ /* gps data */
+ r1.denominator = 1;
+ r2.denominator = 1;
+ r3.denominator = 1;
+
+ float longitude = mInfo.longitude;
+ if (longitude < 0.0) {
+ longitude*= (float)(-1);
+ offset = 1;
+ }
+ r1.numerator = (uint32_t)longitude;
+ float longitudeminuts = (longitude-(float)(r1.numerator))*60;
+ r2.numerator = (uint32_t)longitudeminuts;
+ float longitudeseconds = (longitudeminuts-(float)(r2.numerator))*60+0.5;
+ r3.numerator = (uint32_t)longitudeseconds;
+ exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_LONGITUDE, r1, r2, r3);
+ exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_LONGITUDE_REF, offset == 1 ? "W":"E");
+ }
+
+ if (mInfo.has_altitude) {
+ ExifRational r1;
+ int offset = 0;
+ float altitude = mInfo.altitude;
+ if (altitude < 0.0) {
+ altitude*= (float)(-1);
+ offset = 1;
+ }
+ r1.denominator = 1;
+ r1.numerator = (uint32_t)altitude;
+ exif_entry_set_gps_altitude(pEd, (ExifTag) EXIF_TAG_GPS_ALTITUDE, r1);
+ exif_entry_set_gps_altitude_ref(pEd, (ExifTag) EXIF_TAG_GPS_ALTITUDE_REF, (ExifByte)offset);
+ }
+
+ if (mInfo.has_gpsTimestamp) {
+ ExifRational r1, r2, r3;
+ time_t times;
+ struct tm tmstruct;
+ times = mInfo.gpsTimestamp;
+
+ r1.denominator = 1;
+ r2.denominator = 1;
+ r3.denominator = 1;
+ memset(exifcontent, 0, sizeof(exifcontent));
+ if (times != -1) {
+ tmstruct = *(gmtime(&times));//convert to standard time
+ strftime(exifcontent, 20, "%Y:%m:%d", &tmstruct);
+ exif_entry_set_gps_coord_ref(pEd, (ExifTag) EXIF_TAG_GPS_DATE_STAMP, exifcontent);
+
+ r1.numerator = tmstruct.tm_hour;
+ r2.numerator = tmstruct.tm_min;
+ r3.numerator = tmstruct.tm_sec;
+ exif_entry_set_gps_coord(pEd, (ExifTag) EXIF_TAG_GPS_TIME_STAMP, r1, r2, r3);
+ }
+ }
+
+ if (mInfo.has_gpsProcessingMethod) {
+ char* processmethod = (char*)mInfo.gpsProcessingMethod;
+ if (processmethod != NULL) {
+ const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };//asicii
+ unsigned char* data = (unsigned char*)malloc(strlen(processmethod) + sizeof(ExifAsciiPrefix));
+ exif_buffer buffer;
+ if (data != NULL)
+ {
+ memcpy(data, ExifAsciiPrefix, sizeof(ExifAsciiPrefix));
+ memcpy(data+sizeof(ExifAsciiPrefix), processmethod, strlen(processmethod));
+ buffer.data = data;
+ buffer.size = strlen(processmethod)+sizeof(ExifAsciiPrefix);
+ exif_entry_set_undefined (pEd, EXIF_IFD_GPS, (ExifTag) EXIF_TAG_GPS_PROCESSING_METHOD, &buffer);
+ free(data);
+ }
+ }
+ }
+
+ //write IDF1 for thumbnail
+ if (mJpegRequest.mNeedThumbnail) {
+ exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, mInfo.thumbwidth);
+ exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, mInfo.thumbheight);
+ exif_entry_set_short(pEd, EXIF_IFD_1, EXIF_TAG_ORIENTATION, (ExifShort)orientation);
+ //fan say need check
+ entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_EXIF_IFD_POINTER);
+ entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
+ entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ exif_set_long(entry->data, FILE_BYTE_ORDER, (long)mThumbJpegSize);
+ entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_COMPRESSION);
+ exif_set_short (entry->data, FILE_BYTE_ORDER, 6);
+ }
+
+ /* copy data to our buffer */
+ exif_data_save_data (pEd, &sEb->data, &sEb->size);
+ assert(sEb->data != NULL);
+
+ if (mJpegRequest.mNeedThumbnail) {
+ entry = init_tag(pEd, EXIF_IFD_1, EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
+ exif_set_long(entry->data, FILE_BYTE_ORDER, (long)(sEb->size + 6 - 0x0c));
+
+ exif_data_save_data(pEd, &sEb->data, &sEb->size);
+ assert(sEb->data != NULL);
+ }
+ DBG_LOGB("total exif data length = %d\n", sEb->size);
+ /* destroy exif structure */
+ exif_data_unref(pEd);
+
+ return sEb;
+
+EXIT:
+ if (sEb != NULL)
+ free(sEb);
+
+ return NULL;
+}
+
const char* ExifElementsTable::degreesToExifOrientation(const char* degrees) {
for (unsigned int i = 0; i < ARRAY_SIZE(degress_to_exif_lut); i++) {
if (!strcmp(degrees, degress_to_exif_lut[i].string1)) {
diff --git a/v3/fake-pipeline2/JpegCompressor.h b/v3/fake-pipeline2/JpegCompressor.h
index 5c61aca..464af4d 100644
--- a/v3/fake-pipeline2/JpegCompressor.h
+++ b/v3/fake-pipeline2/JpegCompressor.h
@@ -32,6 +32,12 @@
#include <utils/List.h>
#include <stdio.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-data.h>
+#include <libexif/exif-ifd.h>
+#include <libexif/exif-loader.h>
+#include <libexif/exif-mem.h>
+
extern "C" {
#include <jpeglib.h>
#include <jhead.h>
@@ -75,6 +81,11 @@ struct CaptureRequest {
bool mNeedThumbnail;
};
+typedef struct _exif_buffer {
+ unsigned char *data;
+ unsigned int size;
+} exif_buffer;
+
class ExifElementsTable {
public:
ExifElementsTable() :
@@ -131,6 +142,21 @@ class JpegCompressor: private Thread, public virtual RefBase {
void SetMaxJpegBufferSize(ssize_t size);
void SetExifInfo(struct ExifInfo info);
int GenExif(ExifElementsTable* exiftable);
+ status_t Create_Exif_Use_Libjpeg();
+ status_t Create_Exif_Use_Libexif();
+ exif_buffer *get_exif_buffer();
+ void exif_entry_set_string (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, const char *s);
+ void exif_entry_set_short (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifShort n);
+ void exif_entry_set_long (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifLong n);
+ void exif_entry_set_rational (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifRational r);
+ void exif_entry_set_undefined (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, exif_buffer * buf);
+ ExifEntry *init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag);
+ ExifEntry *create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len);
+ void exif_entry_set_gps_coord(ExifData * pEdata, ExifTag eEtag,
+ ExifRational r1, ExifRational r2, ExifRational r3);
+ void exif_entry_set_gps_altitude(ExifData * pEdata, ExifTag eEtag, ExifRational r1);
+ void exif_entry_set_gps_coord_ref(ExifData * pEdata, ExifTag eEtag, const char *s);
+ void exif_entry_set_gps_altitude_ref(ExifData * pEdata, ExifTag eEtag, ExifByte n);
// TODO: Measure this
static const size_t kMaxJpegSize = 8000000;
diff --git a/v3/fake-pipeline2/Sensor.cpp b/v3/fake-pipeline2/Sensor.cpp
index ae69b96..f8660de 100644
--- a/v3/fake-pipeline2/Sensor.cpp
+++ b/v3/fake-pipeline2/Sensor.cpp
@@ -51,6 +51,7 @@ const nsecs_t Sensor::kExposureTimeRange[2] =
{1000L, 30000000000L} ; // 1 us - 30 sec
const nsecs_t Sensor::kFrameDurationRange[2] =
{33331760L, 30000000000L}; // ~1/30 s - 30 sec
+
const nsecs_t Sensor::kMinVerticalBlank = 10000L;
const uint8_t Sensor::kColorFilterArrangement =
@@ -109,6 +110,7 @@ const usb_frmsize_discrete_t kUsbAvailablePictureSize[] = {
{960, 720},
{720, 480},
{640, 480},
+ {352, 288},
{320, 240},
};
@@ -1386,9 +1388,8 @@ int Sensor::getStreamConfigurations(uint32_t picSizes[], const int32_t kAvailabl
if (0 != (frmsize.discrete.width%16))
continue;
- if((frmsize.discrete.width > support_w) && (frmsize.discrete.height >support_h))
+ if ((frmsize.discrete.width * frmsize.discrete.height) > (support_w * support_h))
continue;
-
if (count >= size)
break;
@@ -1435,9 +1436,8 @@ int Sensor::getStreamConfigurations(uint32_t picSizes[], const int32_t kAvailabl
if (0 != (frmsize.discrete.width%16))
continue;
- if((frmsize.discrete.width > support_w) && (frmsize.discrete.height >support_h))
+ if ((frmsize.discrete.width * frmsize.discrete.height) > (support_w * support_h))
continue;
-
if (count >= size)
break;
@@ -1600,7 +1600,7 @@ int Sensor::getStreamConfigurations(uint32_t picSizes[], const int32_t kAvailabl
}
-int Sensor::getStreamConfigurationDurations(uint32_t picSizes[], int64_t duration[], int size)
+int Sensor::getStreamConfigurationDurations(uint32_t picSizes[], int64_t duration[], int size, bool flag)
{
int ret=0; int framerate=0; int temp_rate=0;
struct v4l2_frmivalenum fival;
@@ -1669,15 +1669,35 @@ int Sensor::getStreamConfigurationDurations(uint32_t picSizes[], int64_t duratio
duration[count+1] = (int64_t)(picSizes[size-3]);
duration[count+2] = (int64_t)(picSizes[size-2]);
if (framerate == 5) {
- duration[count+3] = (int64_t)200000000L;
+ if ((!flag) && ((duration[count+0] == HAL_PIXEL_FORMAT_YCbCr_420_888)
+ || (duration[count+0] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)))
+ duration[count+3] = 0;
+ else
+ duration[count+3] = (int64_t)200000000L;
} else if (framerate == 10) {
- duration[count+3] = (int64_t)100000000L;
+ if ((!flag) && ((duration[count+0] == HAL_PIXEL_FORMAT_YCbCr_420_888)
+ || (duration[count+0] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)))
+ duration[count+3] = 0;
+ else
+ duration[count+3] = (int64_t)100000000L;
} else if (framerate == 15) {
- duration[count+3] = (int64_t)66666666L;
+ if ((!flag) && ((duration[count+0] == HAL_PIXEL_FORMAT_YCbCr_420_888)
+ || (duration[count+0] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)))
+ duration[count+3] = 0;
+ else
+ duration[count+3] = (int64_t)66666666L;
} else if (framerate == 30) {
- duration[count+3] = (int64_t)33333333L;
+ if ((!flag) && ((duration[count+0] == HAL_PIXEL_FORMAT_YCbCr_420_888)
+ || (duration[count+0] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)))
+ duration[count+3] = 0;
+ else
+ duration[count+3] = (int64_t)33333333L;
} else {
- duration[count+3] = (int64_t)66666666L;
+ if ((!flag) && ((duration[count+0] == HAL_PIXEL_FORMAT_YCbCr_420_888)
+ || (duration[count+0] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)))
+ duration[count+3] = 0;
+ else
+ duration[count+3] = (int64_t)66666666L;
}
count += 4;
break;
@@ -1961,6 +1981,10 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) {
while(1)
{
src = (uint8_t *)get_picture(vinfo);
+ if (NULL == src) {
+ usleep(10000);
+ continue;
+ }
if ((NULL != src) && (vinfo->picture.format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)) {
while (dqTryNum > 0) {
if (NULL != src) {
@@ -1973,6 +1997,7 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) {
}
if (NULL != src) {
+ mSensorWorkFlag = true;
if (vinfo->picture.format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
uint8_t *tmp_buffer = new uint8_t[width * height * 3 / 2];
if ( tmp_buffer == NULL) {
diff --git a/v3/fake-pipeline2/Sensor.h b/v3/fake-pipeline2/Sensor.h
index 1f6e77f..15f9459 100644
--- a/v3/fake-pipeline2/Sensor.h
+++ b/v3/fake-pipeline2/Sensor.h
@@ -198,7 +198,7 @@ class Sensor: private Thread, public virtual RefBase {
int getPictureSizes(int32_t picSizes[], int size, bool preview);
int getStreamConfigurations(uint32_t picSizes[], const int32_t kAvailableFormats[], int size);
int64_t getMinFrameDuration();
- int getStreamConfigurationDurations(uint32_t picSizes[], int64_t duration[], int size);
+ int getStreamConfigurationDurations(uint32_t picSizes[], int64_t duration[], int size, bool flag);
bool isStreaming();
bool isNeedRestart(uint32_t width, uint32_t height, uint32_t pixelformat);
status_t IoctlStateProbe(void);