From 8db828db7f121bcee01fc52c651a0504a5f8b394 Mon Sep 17 00:00:00 2001 From: Guosong Zhou Date: Wed, 15 Mar 2017 02:54:29 +0000 Subject: PD#140856: camera: fix android N camera cts when plug usb camera Change-Id: I7d020f07f48a8e4ae53558d615267b5a45077787 Signed-off-by: Guosong Zhou --- 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(×); + tmstruct = *(localtime(×)); //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(×));//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 #include +#include +#include +#include +#include +#include + extern "C" { #include #include @@ -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); -- cgit