diff --git a/app/build.gradle b/app/build.gradle index ffb698ef..fc72301b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,7 +36,7 @@ android { externalNativeBuild { cmake { // cppFlags '-std=c++17 -frtti -fexceptions -Wno-error=format-security' - cppFlags '-std=c++17 -fexceptions -Wno-error=format-security' + cppFlags '-std=c++17 -fexceptions -Wno-error=format-security -fopenmp' // cppFlags '-std=c++17 -Wno-error=format-security' // arguments "-DANDROID_STL=c++_shared" arguments "-DNCNN_DISABLE_EXCEPTION=OFF", "-DTERM_CORE_ROOT=" + coreroot, "-DOpenCV_DIR=" + opencvsdk + "/sdk/native/jni", "-DHDRPLUS_ROOT=" + hdrplusroot, "-DNCNN_ROOT=" + ncnnroot diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index f897506f..3b238683 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -42,6 +42,8 @@ add_definitions(-DENABLE_3V3_ALWAYS) add_definitions(-DUSING_HDRPLUS) +# add_definitions(-DUSING_EXEC_HDRP=1) + #add_definitions(-DUSING_N938) # include_directories(${OpenCV_DIR}/include) @@ -323,6 +325,19 @@ add_library( ${FREETYPE_SRC_FILES} ) + +if(USING_EXEC_HDRP) +add_executable( libhdrp.so + ${HDRPLUS_SOURCES} + hdrplus/bin/hdrplus.cpp ) +target_link_libraries( libhdrp.so PUBLIC -fopenmp -static-openmp + android z + ${OpenCV_LIBS} + # ${LIBRAW_LIBRARY} + ${HDRPLUS_LIBS} + ) +endif() + add_library( # Sets the name of the library. microphoto diff --git a/app/src/main/cpp/MicroPhoto.cpp b/app/src/main/cpp/MicroPhoto.cpp index 45ee32d8..ce8b60be 100644 --- a/app/src/main/cpp/MicroPhoto.cpp +++ b/app/src/main/cpp/MicroPhoto.cpp @@ -281,7 +281,7 @@ Java_com_xypower_mpapp_MicroPhotoService_init( jobject pThis, jstring appPath, jstring ip, jint port, jstring cmdid, jint protocol, jint networkProtocol, jint encryptData, jlong netHandle, jint signalLevel, - jint versionCode, jlong buildTime, jstring simcard, jstring tfCardPath) { + jint versionCode, jlong buildTime, jstring simcard, jstring tfCardPath, jstring nativeLibraryDir) { /* google_breakpad::MinidumpDescriptor descriptor("."); @@ -311,6 +311,7 @@ Java_com_xypower_mpapp_MicroPhotoService_init( const char *cmdidStr = cmdid == NULL ? NULL : env->GetStringUTFChars(cmdid, 0); const char *simcardStr = simcard == NULL ? NULL : env->GetStringUTFChars(simcard, 0); const char *tfCardPathStr = tfCardPath == NULL ? NULL : env->GetStringUTFChars(tfCardPath, 0); + const char *nativeLibraryDirStr = nativeLibraryDir == NULL ? NULL : env->GetStringUTFChars(nativeLibraryDir, 0); JavaVM* vm = NULL; jint ret = env->GetJavaVM(&vm); @@ -321,7 +322,7 @@ Java_com_xypower_mpapp_MicroPhotoService_init( CTerminal* pTerminal = NewTerminal(protocol); - CPhoneDevice* device = new CPhoneDevice(vm, pThis, MakeString(appPathStr), NETID_UNSET, versionCode); + CPhoneDevice* device = new CPhoneDevice(vm, pThis, MakeString(appPathStr), NETID_UNSET, versionCode, MakeString(nativeLibraryDirStr)); device->SetListener(pTerminal); device->UpdateSignalLevel(signalLevel); device->SetBuildTime(buildTime / 1000); @@ -340,6 +341,7 @@ Java_com_xypower_mpapp_MicroPhotoService_init( if (cmdidStr != NULL) env->ReleaseStringUTFChars(cmdid, cmdidStr); if (simcardStr != NULL) env->ReleaseStringUTFChars(simcard, simcardStr); if (tfCardPathStr != NULL) env->ReleaseStringUTFChars(tfCardPath, tfCardPathStr); + if (nativeLibraryDirStr != NULL) env->ReleaseStringUTFChars(nativeLibraryDir, nativeLibraryDirStr); if (!res) { @@ -393,7 +395,7 @@ Java_com_xypower_mpapp_MicroPhotoService_takePhoto( CTerminal::LoadChannelConfig(channel, configFilePathStr, cfg); CTerminal::ConvertChannelConfigToPhotoInfo(cfg, photoOrVideo != JNI_FALSE, photoInfo); - CPhoneDevice* device = new CPhoneDevice(vm, NULL, "", NETID_UNSET, 0); + CPhoneDevice* device = new CPhoneDevice(vm, NULL, "", NETID_UNSET, 0, std::string("")); // device->SetListener(pTerminal); if (photoInfo.usbCamera) @@ -1329,8 +1331,7 @@ Java_com_xypower_mpapp_MicroPhotoService_exportPrivateFile( #ifdef USING_NRSEC - if (env->GetStringUTFLength(outputPath) <= 0) - { + if (env->GetStringUTFLength(outputPath) <= 0) { return JNI_FALSE; } @@ -1341,8 +1342,7 @@ Java_com_xypower_mpapp_MicroPhotoService_exportPrivateFile( GpioControl::setSpiPower(true); NrsecPort nrsec; - if (!nrsec.Open(path)) - { + if (!nrsec.Open(path)) { return JNI_FALSE; } @@ -1355,9 +1355,8 @@ Java_com_xypower_mpapp_MicroPhotoService_exportPrivateFile( GpioControl::setSpiPower(false); CPhoneDevice::TurnOffCameraPower(NULL); - if (res) - { - const char* outputPathStr = env->GetStringUTFChars(outputPath, 0); + if (res) { + const char *outputPathStr = env->GetStringUTFChars(outputPath, 0); res = writeFile(outputPathStr, &data[0], len); env->ReleaseStringUTFChars(outputPath, outputPathStr); } @@ -1366,4 +1365,4 @@ Java_com_xypower_mpapp_MicroPhotoService_exportPrivateFile( #else return JNI_FALSE; #endif -} +} \ No newline at end of file diff --git a/app/src/main/cpp/PhoneDevice.cpp b/app/src/main/cpp/PhoneDevice.cpp index 7224b07f..23ee728d 100644 --- a/app/src/main/cpp/PhoneDevice.cpp +++ b/app/src/main/cpp/PhoneDevice.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace fs = std::filesystem; #define CMD_SET_485_EN_STATE 131 @@ -91,7 +92,13 @@ cv::Mat convert16bit2_8bit_(cv::Mat ans){ return ans; } - +char* MakeArgv(const std::string v) +{ + char* argv = new char[v.size() + 1]; + memset(argv, 0, v.size() + 1); + strcpy(argv, v.c_str()); + return argv; +} static long getFreeMemoryImpl(const char* const sums[], const size_t sumsLen[], size_t num) { @@ -378,7 +385,7 @@ std::mutex CPhoneDevice::m_powerLocker; long CPhoneDevice::mCameraPowerCount = 0; long CPhoneDevice::mOtgCount = 0; -CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPath, unsigned int netId, unsigned int versionCode) : mVersionCode(versionCode) +CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPath, unsigned int netId, unsigned int versionCode, const std::string& nativeLibDir) : mVersionCode(versionCode), m_nativeLibraryDir(nativeLibDir) { mCamera = NULL; m_listener = NULL; @@ -1828,6 +1835,63 @@ bool CPhoneDevice::onBurstCapture(std::shared_ptr characteristi // Notify to take next photo pThis->TakePhotoCb(1, photoInfo, "", takingTime); +#ifdef USING_EXEC_HDRP + // exec() + { + uint64_t uniqueId = pThis->m_uniqueIdFeed.fetch_add(1); + std::string cmd = pThis->m_nativeLibraryDir; + if (!endsWith(cmd, DIR_SEP_STR)) + { + cmd += DIR_SEP_STR; + } + + std::string tmpDir = pThis->m_appPath + (APP_DIR_TMP DIR_SEP_STR) + std::to_string(uniqueId) + DIR_SEP_STR; + EnsureDirectoryPathExists(tmpDir); + cmd += "libhdrp.so"; + + std::vector > localFrames; + localFrames.swap(pByteArrays.get()->byteArrays); + + std::string outputPath = tmpDir + "output.tiff"; + size_t numberOfFrames = localFrames.size(); + size_t argc = numberOfFrames + 4; + char** argv = new char*[argc]; + argv[argc - 1] = NULL; + argv[0] = MakeArgv(std::to_string(photoInfo.orientation)); + argv[1] = MakeArgv(std::to_string(facing == ACAMERA_LENS_FACING_FRONT ? 1 : 0)); + argv[2] = MakeArgv(outputPath); + for (int idx = 0; idx < localFrames.size(); idx++) + { + std::vector& frame = localFrames[idx]; + writeFile(tmpDir + std::to_string(idx) + ".dng", &frame[0], frame.size()); + argv[3 + idx] = MakeArgv(tmpDir + std::to_string(idx) + ".dng"); + } + localFrames.clear(); +#if _DEBUG + const char* psz = cmd.c_str(); +#endif + char* szCmd = MakeArgv(cmd); + + int exitcode = execv(szCmd, argv); + for (int idx = 0; idx < numberOfFrames; idx++) + { + std::remove(argv[3 + idx]); + } + + delete[] szCmd; + for (int idx = 0; idx < argc; idx++) + { + if (argv[idx] != NULL) delete[] argv[idx]; + } + delete[] argv; + + + if (existsFile(outputPath)) + { + + } + } +#else // USING_EXEC_HDRP XYLOG(XYLOG_SEVERITY_ERROR, "Start HDR CH=%u IMGID=%u", (uint32_t)photoInfo.channel, (uint32_t)photoInfo.photoId); hdrplus::hdrplus_pipeline pipeline; std::vector > localFrames; @@ -1868,7 +1932,7 @@ bool CPhoneDevice::onBurstCapture(std::shared_ptr characteristi cv::flip(rgb, rgb, -1); } } - else if (photoInfo.orientation == 4) + else if ((photoInfo.orientation % 4) == 0) { cv::Mat tempPic; cv::transpose(rgb, tempPic); @@ -1878,7 +1942,7 @@ bool CPhoneDevice::onBurstCapture(std::shared_ptr characteristi XYLOG(XYLOG_SEVERITY_ERROR, "Finish rotation CH=%u IMGID=%u", (uint32_t)photoInfo.channel, (uint32_t)photoInfo.photoId); } cv::cvtColor(rgb, rgb, cv::COLOR_RGB2BGR); - +#endif // USING_EXEC_HDRP bool res = pThis->PostProcessPhoto(photoInfo, osds, path, cameraInfo, rgb); if (res) { diff --git a/app/src/main/cpp/PhoneDevice.h b/app/src/main/cpp/PhoneDevice.h index 54bbcb08..c15651e7 100644 --- a/app/src/main/cpp/PhoneDevice.h +++ b/app/src/main/cpp/PhoneDevice.h @@ -194,7 +194,7 @@ public: unsigned long uid; }; - CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPath, unsigned int netId, unsigned int versionCode); + CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPath, unsigned int netId, unsigned int versionCode, const std::string& nativeLibDir); virtual ~CPhoneDevice(); virtual void SetListener(IListener* listener); @@ -305,6 +305,7 @@ protected: jobject m_javaService; std::string m_appPath; std::string m_tfCardPath; + std::string m_nativeLibraryDir; jmethodID mRegisterHeartbeatMid; jmethodID mUpdateCaptureScheduleMid; @@ -333,6 +334,7 @@ protected: atomic_ulong m_timerUidFeed; atomic_ulong m_wakelockIdFeed; + atomic_ulong m_uniqueIdFeed; std::map mTimers; mutable CPhoneCamera* mCamera; diff --git a/app/src/main/cpp/hdrplus/bin/hdrplus.cpp b/app/src/main/cpp/hdrplus/bin/hdrplus.cpp new file mode 100644 index 00000000..4536e347 --- /dev/null +++ b/app/src/main/cpp/hdrplus/bin/hdrplus.cpp @@ -0,0 +1,72 @@ +#include "hdrplus/hdrplus_pipeline.h" + +int main( int argc, char** argv ) +{ + int rotation = atoi(argv[1]); + bool frontCamera = atoi(argv[2]) != 0; + + std::vector paths; + for (int idx = 4; idx < argc; idx++) + { + paths.push_back(argv[idx]); + } + + cv::Mat mat; + + hdrplus::hdrplus_pipeline pipeline; + pipeline.run_pipeline( paths, 0, mat); + + if (mat.empty()) + { + printf("run_pipeline return empty mat"); + } + mat = hdrplus::convert16bit2_8bit_(mat.clone()); + + if (rotation >= 0) + { + if (rotation == 0) + { + cv::Mat tempPic; + cv::transpose(mat, tempPic); + cv::flip(tempPic, mat, 0); + } + else if (rotation == 1) + { + cv::Mat tempPic; + cv::transpose(mat, tempPic); + cv::flip(tempPic, mat, 1); + } + else if (rotation == 2) + { + if (frontCamera) + { + cv::flip(mat, mat, 0); + } + else + { + cv::flip(mat, mat, -1); + } + } + else if (rotation == 3) + { + cv::Mat tempPic; + cv::transpose(mat, tempPic); + cv::flip(tempPic, mat, 0); + } + + } + cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR); + + if (mat.empty()) + { + printf("mat is empty before save"); + } + + bool res = cv::imwrite(argv[3], mat); + if (!res) + { + printf("Failed to write file %s", argv[3]); + } + + return 0; +} \ No newline at end of file diff --git a/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h b/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h index 49e4ca79..17dd789d 100644 --- a/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h +++ b/app/src/main/cpp/hdrplus/include/hdrplus/hdrplus_pipeline.h @@ -10,7 +10,31 @@ namespace hdrplus { -class hdrplus_pipeline + inline cv::Mat convert16bit2_8bit_(cv::Mat ans) { + if(ans.type()==CV_16UC3){ + cv::MatIterator_ it, end; + for( it = ans.begin(), end = ans.end(); it != end; ++it) + { + // std::cout< #ifdef __ANDROID__ -#include +// #include #endif namespace hdrplus @@ -46,25 +46,25 @@ bool hdrplus_pipeline::run_pipeline( \ burst burst_images( burst_paths, reference_image_index ); std::vector>>> alignments; #ifdef __ANDROID__ - ALOGI("Finish loading images"); + // ALOGI("Finish loading images"); #endif // Run align align_module.process( burst_images, alignments ); #ifdef __ANDROID__ - ALOGI("Finish align"); + // ALOGI("Finish align"); #endif // Run merging merge_module.process( burst_images, alignments ); #ifdef __ANDROID__ - ALOGI("Finish merging"); + // ALOGI("Finish merging"); #endif // Run finishing finish_module.process( burst_images, finalImg); #ifdef __ANDROID__ - ALOGI("Finish process"); + // ALOGI("Finish process"); #endif return true; @@ -78,25 +78,25 @@ bool hdrplus_pipeline::run_pipeline( \ burst burst_images( burst_contents, reference_image_index ); std::vector>>> alignments; #ifdef __ANDROID__ - ALOGI("Finish loading images"); + // ALOGI("Finish loading images"); #endif // Run align align_module.process( burst_images, alignments ); #ifdef __ANDROID__ - ALOGI("Finish align"); + // ALOGI("Finish align"); #endif // Run merging merge_module.process( burst_images, alignments ); #ifdef __ANDROID__ - ALOGI("Finish merging"); + // ALOGI("Finish merging"); #endif // Run finishing finish_module.process( burst_images, finalImg); #ifdef __ANDROID__ - ALOGI("Finish process"); + // ALOGI("Finish process"); #endif return true; @@ -111,25 +111,25 @@ bool hdrplus_pipeline::run_pipeline( \ burst burst_images( burst_files, reference_image_index ); std::vector>>> alignments; #ifdef __ANDROID__ - ALOGI("Finish loading images"); + // ALOGI("Finish loading images"); #endif // Run align align_module.process( burst_images, alignments ); #ifdef __ANDROID__ - ALOGI("Finish align"); + // ALOGI("Finish align"); #endif // Run merging merge_module.process( burst_images, alignments ); #ifdef __ANDROID__ - ALOGI("Finish merging"); + // ALOGI("Finish merging"); #endif // Run finishing finish_module.process( burst_images, finalImg); #ifdef __ANDROID__ - ALOGI("Finish process"); + // ALOGI("Finish process"); #endif return true; diff --git a/app/src/main/java/com/xypower/mpapp/BridgeProvider.java b/app/src/main/java/com/xypower/mpapp/BridgeProvider.java index f5bd9f21..87ad2a67 100644 --- a/app/src/main/java/com/xypower/mpapp/BridgeProvider.java +++ b/app/src/main/java/com/xypower/mpapp/BridgeProvider.java @@ -5,6 +5,8 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.UriMatcher; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; @@ -18,7 +20,13 @@ import com.xypower.common.MicroPhotoContext; import org.json.JSONObject; +import java.io.BufferedReader; import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; public class BridgeProvider extends ContentProvider { @@ -34,6 +42,8 @@ public class BridgeProvider extends ContentProvider { private final static String PATH_TAKE_PHOTO = "/takePhoto"; private final static String PATH_TAKE_VIDEO = "/takeVideo"; + private final static String PATH_HDRPLUS = "/hdrplus"; + private final static String PATH_RECOG_PIC = "/recogPic"; public BridgeProvider() { @@ -106,6 +116,7 @@ public class BridgeProvider extends ContentProvider { matcher.addURI(AUTHORITY, PATH_GEN_CERT_REQ, 4); matcher.addURI(AUTHORITY, PATH_TAKE_PHOTO, 5); matcher.addURI(AUTHORITY, PATH_TAKE_VIDEO, 6); + matcher.addURI(AUTHORITY, PATH_HDRPLUS, 7); int res = 0; int matched = matcher.match(uri); @@ -128,6 +139,9 @@ public class BridgeProvider extends ContentProvider { case 6: res = takeVideo(uri, values); break; + case 7: + res = hdrPlus(uri, values); + break; default: break; } @@ -416,4 +430,73 @@ public class BridgeProvider extends ContentProvider { return 1; } + + private int hdrPlus(Uri uri, ContentValues values) { + int rotation = values.containsKey("rotation") ? values.getAsInteger("rotation").intValue() : -1; + int frontCamera = values.containsKey("front") ? values.getAsInteger("front").intValue() : 0; + String outputPath = values.containsKey("output") ? values.getAsString("output") : null; + int numberOfCaptures = values.containsKey("captures") ? values.getAsInteger("captures").intValue() : 0; + List paths = new ArrayList<>(); + for (int idx = 0; idx < numberOfCaptures; idx++) { + String key = "path" + Integer.toString(idx + 1); + String path = values.containsKey(key) ? values.getAsString(key) : null; + if (!TextUtils.isEmpty(path)) { + paths.add(path); + } + } + + + + ApplicationInfo applicationInfo = null; + Context context = getContext(); + try { + applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_SHARED_LIBRARY_FILES); + } catch (Exception ex) { + + } + + Log.d(TAG, "nativeLibraryDir= " + applicationInfo.nativeLibraryDir); + String exeFilePath = applicationInfo.nativeLibraryDir + '/' + "libhdrp.so"; + File hdrpFile = new File(exeFilePath); + if (!hdrpFile.exists()) { + return 0; + } + + String cmd = exeFilePath + " " + Integer.toString(rotation) + " "; + cmd += Integer.toString(frontCamera) + " "; + cmd += outputPath + " " + TextUtils.join(" ", paths); + + String[] params = new String[]{""}; + File workDir = context.getFilesDir(); + int exitCode = 0; + + try { + Process process = Runtime.getRuntime().exec(cmd, params, workDir.getAbsoluteFile()); + // Intrinsics.checkNotNullExpressionValue(process, "process"); + InputStream inputStream = process.getInputStream(); + BufferedReader reader = new BufferedReader((Reader)(new InputStreamReader(inputStream))); + + // StringBuilder stringBuilder = new StringBuilder(); + while(true) { + String line = reader.readLine(); + if (line == null) { + exitCode = process.exitValue(); + reader.close(); + process.destroy(); + break; + } + + if (line != null) { + // this.outputCallback.invoke(var5); + Log.d("HDRPlus", line); + // stringBuilder.append(line); + // stringBuilder.append("\r\n"); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + + return 1; + } } \ No newline at end of file diff --git a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java index 202dcb50..54c7a6bf 100644 --- a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java +++ b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java @@ -14,6 +14,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.ImageDecoder; @@ -918,9 +920,18 @@ public class MicroPhotoService extends Service { } String tfCardPath = MicroPhotoContext.getSecondaryStoragePath(context); + String nativeLibraryDir = null; + ApplicationInfo applicationInfo = null; + try { + applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_SHARED_LIBRARY_FILES); + nativeLibraryDir = applicationInfo.nativeLibraryDir; + } catch (Exception ex) { + ex.printStackTrace(); + } + service.mNativeHandle = init(appPath, server, port, cmdid, protocol, networkProtocol, encryptData, 0, service.getSignalLevel(), versionCode, - BuildConfig.BUILD_TIMESTAMP, simcard, tfCardPath); + BuildConfig.BUILD_TIMESTAMP, simcard, tfCardPath, nativeLibraryDir); if (service.mNativeHandle != 0) { isRunning = true; @@ -1394,7 +1405,7 @@ cellSignalStrengthGsm.getDbm(); protected native long init(String appPath, String ip, int port, String cmdid, int protocol, int networkProtocl, int encryptData, long netHandle, int signalLevel, - int versionCode, long buildTime, String simcard, String tfCardPath); + int versionCode, long buildTime, String simcard, String tfCardPath, String nativeLibraryDir); protected native long getHeartbeatDuration(long handler); protected native long[] getPhotoTimeData(long handler, long startTime); protected native long[] getPhotoTimeData2(long handler);