|
|
|
@ -47,6 +47,67 @@ namespace fs = std::filesystem;
|
|
|
|
|
|
|
|
|
|
extern bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool makeHdr(vector<float>& times, std::vector<std::string>& paths, cv::Mat& rgb)
|
|
|
|
|
{
|
|
|
|
|
// Read images and exposure times
|
|
|
|
|
vector<cv::Mat> images;
|
|
|
|
|
|
|
|
|
|
for (auto it = paths.cbegin(); it != paths.cend(); ++it)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat im = cv::imread((*it).c_str());
|
|
|
|
|
images.push_back(im);
|
|
|
|
|
}
|
|
|
|
|
// Align input images
|
|
|
|
|
// cout << "Aligning images ... " << endl;
|
|
|
|
|
cv::Ptr<cv::AlignMTB> alignMTB = cv::createAlignMTB();
|
|
|
|
|
#if 0
|
|
|
|
|
alignMTB->process(images, images);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Obtain Camera Response Function (CRF)
|
|
|
|
|
// cout << "Calculating Camera Response Function (CRF) ... " << endl;
|
|
|
|
|
cv::Mat responseDebevec;
|
|
|
|
|
cv::Ptr<cv::CalibrateDebevec> calibrateDebevec = cv::createCalibrateDebevec();
|
|
|
|
|
calibrateDebevec->process(images, responseDebevec, times);
|
|
|
|
|
|
|
|
|
|
// Merge images into an HDR linear image
|
|
|
|
|
// cout << "Merging images into one HDR image ... ";
|
|
|
|
|
cv::Mat hdrDebevec;
|
|
|
|
|
cv::Ptr<cv::MergeDebevec> mergeDebevec = cv::createMergeDebevec();
|
|
|
|
|
mergeDebevec->process(images, hdrDebevec, times, responseDebevec);
|
|
|
|
|
// Save HDR image.
|
|
|
|
|
// imwrite((OUTPUT_DIR "hdrDebevec.hdr"), hdrDebevec);
|
|
|
|
|
// cout << "saved hdrDebevec.hdr " << endl;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> empty;
|
|
|
|
|
empty.swap(images);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tonemap using Reinhard's method to obtain 24-bit color image
|
|
|
|
|
// cout << "Tonemaping using Reinhard's method ... ";
|
|
|
|
|
cv::Mat ldrReinhard;
|
|
|
|
|
cv::Ptr<cv::TonemapReinhard> tonemapReinhard = cv::createTonemapReinhard(1.5, 0, 0, 0);
|
|
|
|
|
tonemapReinhard->process(hdrDebevec, ldrReinhard);
|
|
|
|
|
hdrDebevec.release();
|
|
|
|
|
|
|
|
|
|
int type = ldrReinhard.type();
|
|
|
|
|
ldrReinhard = ldrReinhard * 255;
|
|
|
|
|
|
|
|
|
|
ldrReinhard.convertTo(rgb, CV_8U);
|
|
|
|
|
ldrReinhard.release();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AndroidBitmap_CompressWriteFile(void *userContext, const void *data, size_t size)
|
|
|
|
|
{
|
|
|
|
|
FILE* file = (FILE*)userContext;
|
|
|
|
|
int bytesWritten = fwrite(data, 1, size, file);
|
|
|
|
|
return bytesWritten == size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define WAKELOCK_NAME "NDK_WK_"
|
|
|
|
|
// This value is 2 ^ 18 - 1, and is used to clamp the RGB values before their
|
|
|
|
|
// ranges
|
|
|
|
@ -478,6 +539,8 @@ CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPa
|
|
|
|
|
|
|
|
|
|
mSetStaticIpMid = env->GetMethodID(classService, "setStaticNetwork", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
|
|
|
|
|
|
|
|
|
mConvertDngToPngMid = env->GetMethodID(classService, "convertDngToPng", "(Ljava/lang/String;Ljava/lang/String;)V");
|
|
|
|
|
|
|
|
|
|
mCallSysCameraMid = env->GetMethodID(classService, "callSystemCamera", "(IJ)V");
|
|
|
|
|
|
|
|
|
|
env->DeleteLocalRef(classService);
|
|
|
|
@ -784,7 +847,7 @@ int CPhoneDevice::QueryBatteryVoltage(int retries)
|
|
|
|
|
for (int idx = 0; idx < retries; idx++)
|
|
|
|
|
{
|
|
|
|
|
val = GpioControl::getBatteryBusVoltage(); // // BatVol
|
|
|
|
|
if (val >= 0)
|
|
|
|
|
if (val >= 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -1508,6 +1571,7 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
|
|
|
|
|
params.requestTemplate = mPhotoInfo.requestTemplate;
|
|
|
|
|
params.awbMode = mPhotoInfo.awbMode;
|
|
|
|
|
params.wait3ALocked = mPhotoInfo.wait3ALocked;
|
|
|
|
|
params.customHdr = mPhotoInfo.customHdr;
|
|
|
|
|
params.burstRawCapture = mPhotoInfo.usingRawFormat;
|
|
|
|
|
params.burstCaptures = mPhotoInfo.burstCaptures;
|
|
|
|
|
if (params.requestTemplate <= 0 || params.requestTemplate > 5)
|
|
|
|
@ -2340,35 +2404,105 @@ bool CPhoneDevice::onBurstCapture(std::shared_ptr<ACameraMetadata> characteristi
|
|
|
|
|
|
|
|
|
|
std::vector<std::vector<uint8_t> > localFrames;
|
|
|
|
|
localFrames.swap(pByteArrays.get()->byteArrays);
|
|
|
|
|
|
|
|
|
|
std::string outputPath = tmpDir + "output.bmp";
|
|
|
|
|
size_t numberOfFrames = localFrames.size();
|
|
|
|
|
std::vector<std::string> imagePaths;
|
|
|
|
|
for (int idx = 0; idx < localFrames.size(); idx++)
|
|
|
|
|
|
|
|
|
|
if (photoInfo.customHdr)
|
|
|
|
|
{
|
|
|
|
|
std::string imagePath = tmpDir + std::to_string(idx) + ".dng";
|
|
|
|
|
std::vector<uint8_t>& frame = localFrames[idx];
|
|
|
|
|
if (writeFile(imagePath, &frame[0], frame.size()))
|
|
|
|
|
std::vector<std::string> imagePaths;
|
|
|
|
|
std::vector<float> exposureTimes;
|
|
|
|
|
|
|
|
|
|
for (int idx = 0; idx < localFrames.size(); idx++)
|
|
|
|
|
{
|
|
|
|
|
imagePaths.push_back(imagePath);
|
|
|
|
|
ACameraMetadata_const_entry val = { 0 };
|
|
|
|
|
camera_status_t status = ACameraMetadata_getConstEntry(results[idx].get(), ACAMERA_SENSOR_EXPOSURE_TIME, &val);
|
|
|
|
|
int64_t exTime = (status == ACAMERA_OK) ? val.data.i64[0] : -1;
|
|
|
|
|
|
|
|
|
|
exposureTimes.push_back(exTime / 1000000000.0);
|
|
|
|
|
|
|
|
|
|
std::string imagePath = tmpDir + std::to_string(idx) + ".dng";
|
|
|
|
|
std::vector<uint8_t>& frame = localFrames[idx];
|
|
|
|
|
if (writeFile(imagePath, &frame[0], frame.size()))
|
|
|
|
|
{
|
|
|
|
|
std::vector<uint8_t> empty;
|
|
|
|
|
empty.swap(frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string pngPath = imagePath + ".png";
|
|
|
|
|
|
|
|
|
|
pThis->ConvertDngToPng(imagePath, pngPath);
|
|
|
|
|
imagePaths.push_back(pngPath);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
AImageDecoder* imageDecoder = NULL;
|
|
|
|
|
AImageDecoder_createFromBuffer(&frame[0], frame.size(), &imageDecoder);
|
|
|
|
|
|
|
|
|
|
const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(imageDecoder);
|
|
|
|
|
AndroidBitmapInfo bmpInfo = { 0 };
|
|
|
|
|
bmpInfo.flags = AImageDecoderHeaderInfo_getAlphaFlags(info);
|
|
|
|
|
bmpInfo.width = AImageDecoderHeaderInfo_getWidth(info);
|
|
|
|
|
bmpInfo.height = AImageDecoderHeaderInfo_getHeight(info);
|
|
|
|
|
bmpInfo.format = (AndroidBitmapFormat) AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
|
|
|
|
|
bmpInfo.stride = AImageDecoder_getMinimumStride(imageDecoder); // Image decoder does not
|
|
|
|
|
// use padding by default
|
|
|
|
|
int32_t fmt = ANDROID_BITMAP_FORMAT_RGBA_8888;
|
|
|
|
|
size_t stride = photoInfo.width * 4;
|
|
|
|
|
size_t size = stride * photoInfo.height;
|
|
|
|
|
|
|
|
|
|
int32_t dataSpace = AImageDecoderHeaderInfo_getDataSpace(info);
|
|
|
|
|
|
|
|
|
|
frame.resize(size);
|
|
|
|
|
|
|
|
|
|
int result = AImageDecoder_decodeImage(imageDecoder, (void *)(&frame[0]), bmpInfo.stride, size);
|
|
|
|
|
AImageDecoder_delete(imageDecoder);
|
|
|
|
|
|
|
|
|
|
if (result != ANDROID_IMAGE_DECODER_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
imagePath += ".png";
|
|
|
|
|
FILE* file = fopen(imagePath.c_str(), "wb");
|
|
|
|
|
AndroidBitmap_compress(&bmpInfo, dataSpace, &frame[0], ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, file, AndroidBitmap_CompressWriteFile);
|
|
|
|
|
fclose(file);
|
|
|
|
|
std::vector<uint8_t> empty;
|
|
|
|
|
empty.swap(frame);
|
|
|
|
|
|
|
|
|
|
imagePaths.push_back(imagePath);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
localFrames.clear();
|
|
|
|
|
localFrames.clear();
|
|
|
|
|
|
|
|
|
|
int exitCode = pThis->CallExecv(photoInfo.orientation, facing == ACAMERA_LENS_FACING_FRONT ? 1 : 0, outputPath, imagePaths);
|
|
|
|
|
for (auto it = imagePaths.cbegin(); it != imagePaths.cend(); ++it)
|
|
|
|
|
{
|
|
|
|
|
std::remove((*it).c_str());
|
|
|
|
|
makeHdr(exposureTimes, imagePaths, rgb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (existsFile(outputPath))
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rgb = cv::imread(outputPath);
|
|
|
|
|
std::remove(outputPath.c_str());
|
|
|
|
|
std::string outputPath = tmpDir + "output.bmp";
|
|
|
|
|
size_t numberOfFrames = localFrames.size();
|
|
|
|
|
std::vector<std::string> imagePaths;
|
|
|
|
|
for (int idx = 0; idx < localFrames.size(); idx++)
|
|
|
|
|
{
|
|
|
|
|
std::string imagePath = tmpDir + std::to_string(idx) + ".dng";
|
|
|
|
|
std::vector<uint8_t>& frame = localFrames[idx];
|
|
|
|
|
if (writeFile(imagePath, &frame[0], frame.size()))
|
|
|
|
|
{
|
|
|
|
|
imagePaths.push_back(imagePath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
localFrames.clear();
|
|
|
|
|
|
|
|
|
|
int exitCode = pThis->CallExecv(photoInfo.orientation, facing == ACAMERA_LENS_FACING_FRONT ? 1 : 0, outputPath, imagePaths);
|
|
|
|
|
for (auto it = imagePaths.cbegin(); it != imagePaths.cend(); ++it)
|
|
|
|
|
{
|
|
|
|
|
std::remove((*it).c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (existsFile(outputPath))
|
|
|
|
|
{
|
|
|
|
|
rgb = cv::imread(outputPath);
|
|
|
|
|
std::remove(outputPath.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::error_code errCode;
|
|
|
|
|
fs::remove_all(fs::path(tmpDir), errCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::error_code errCode;
|
|
|
|
|
fs::remove_all(fs::path(tmpDir), errCode);
|
|
|
|
|
}
|
|
|
|
|
#else // USING_EXEC_HDRP
|
|
|
|
|
XYLOG(XYLOG_SEVERITY_ERROR, "Start HDR CH=%u IMGID=%u", (uint32_t)photoInfo.channel, (uint32_t)photoInfo.photoId);
|
|
|
|
@ -3527,6 +3661,27 @@ void CPhoneDevice::SetStaticIp(const std::string& iface, const std::string& ip,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CPhoneDevice::ConvertDngToPng(const std::string& dngPath, const std::string& pngPath)
|
|
|
|
|
{
|
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
|
jboolean ret = JNI_FALSE;
|
|
|
|
|
bool didAttachThread = false;
|
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
|
if (!res)
|
|
|
|
|
{
|
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jstring jdngPath = env->NewStringUTF(dngPath.c_str());
|
|
|
|
|
jstring jpngPath = env->NewStringUTF(pngPath.c_str());
|
|
|
|
|
env->CallVoidMethod(m_javaService, mConvertDngToPngMid, jdngPath, jpngPath);
|
|
|
|
|
|
|
|
|
|
if (didAttachThread)
|
|
|
|
|
{
|
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CPhoneDevice::GetIceData(IDevice::ICE_INFO *iceInfo, IDevice::ICE_TAIL *iceTail, SENSOR_PARAM *sensorParam)
|
|
|
|
|
{
|
|
|
|
|
m_tempData.instantaneous_windspeed = 0xff;
|
|
|
|
|