|
|
|
#include "TerminalDevice.h"
|
|
|
|
|
|
|
|
#include <AndroidHelper.h>
|
|
|
|
#include "PhoneDevice.h"
|
|
|
|
#include <Client/Terminal.h>
|
|
|
|
#include <Utils.h>
|
|
|
|
#include <LogThread.h>
|
|
|
|
#include "ncnn/yolov5ncnn.h"
|
|
|
|
#include "GPIOControl.h"
|
|
|
|
|
|
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
#include <opencv2/core.hpp>
|
|
|
|
#include <opencv2/imgproc.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
#include <opencv2/core/types.hpp>
|
|
|
|
#include <opencv2/core/core.hpp>
|
|
|
|
#include <opencv2/imgproc/imgproc.hpp>
|
|
|
|
|
|
|
|
#include <android/log.h>
|
|
|
|
#include <android/thermal.h>
|
|
|
|
#include <sys/system_properties.h>
|
|
|
|
#include <Mat.h>
|
|
|
|
|
|
|
|
#include <filesystem>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
|
|
|
#define CMD_SET_485_EN_STATE 131
|
|
|
|
#define CMD_SET_CAM_3V3_EN_STATE 132
|
|
|
|
#define CMD_SET_12V_EN_STATE 133
|
|
|
|
|
|
|
|
extern bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread);
|
|
|
|
|
|
|
|
#define WAKELOCK_NAME "NDK_WK_"
|
|
|
|
// This value is 2 ^ 18 - 1, and is used to clamp the RGB values before their
|
|
|
|
// ranges
|
|
|
|
// are normalized to eight bits.
|
|
|
|
static const int kMaxChannelValue = 262143;
|
|
|
|
|
|
|
|
static long getFreeMemoryImpl(const char* const sums[], const size_t sumsLen[], size_t num)
|
|
|
|
{
|
|
|
|
int fd = open("/proc/meminfo", O_RDONLY | O_CLOEXEC);
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
ALOGW("Unable to open /proc/meminfo");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buffer[2048];
|
|
|
|
const int len = read(fd, buffer, sizeof(buffer)-1);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (len < 0) {
|
|
|
|
ALOGW("Unable to read /proc/meminfo");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
buffer[len] = 0;
|
|
|
|
|
|
|
|
size_t numFound = 0;
|
|
|
|
jlong mem = 0;
|
|
|
|
|
|
|
|
char* p = buffer;
|
|
|
|
while (*p && numFound < num) {
|
|
|
|
int i = 0;
|
|
|
|
while (sums[i]) {
|
|
|
|
if (strncmp(p, sums[i], sumsLen[i]) == 0) {
|
|
|
|
p += sumsLen[i];
|
|
|
|
while (*p == ' ') p++;
|
|
|
|
char* num = p;
|
|
|
|
while (*p >= '0' && *p <= '9') p++;
|
|
|
|
if (*p != 0) {
|
|
|
|
*p = 0;
|
|
|
|
p++;
|
|
|
|
if (*p == 0) p--;
|
|
|
|
}
|
|
|
|
mem += atoll(num) * 1024;
|
|
|
|
numFound++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return numFound > 0 ? mem : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static jlong android_os_Process_getFreeMemory()
|
|
|
|
{
|
|
|
|
static const char* const sums[] = { "MemFree:", "Cached:", NULL };
|
|
|
|
static const size_t sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 };
|
|
|
|
return getFreeMemoryImpl(sums, sumsLen, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static jlong android_os_Process_getTotalMemory()
|
|
|
|
{
|
|
|
|
static const char* const sums[] = { "MemTotal:", NULL };
|
|
|
|
static const size_t sumsLen[] = { strlen("MemTotal:"), 0 };
|
|
|
|
return getFreeMemoryImpl(sums, sumsLen, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint32_t YUV2RGB(int nY, int nU, int nV) {
|
|
|
|
nY -= 16;
|
|
|
|
nU -= 128;
|
|
|
|
nV -= 128;
|
|
|
|
if (nY < 0) nY = 0;
|
|
|
|
|
|
|
|
// This is the floating point equivalent. We do the conversion in integer
|
|
|
|
// because some Android devices do not have floating point in hardware.
|
|
|
|
// nR = (int)(1.164 * nY + 1.596 * nV);
|
|
|
|
// nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
|
|
|
|
// nB = (int)(1.164 * nY + 2.018 * nU);
|
|
|
|
|
|
|
|
int nR = (int)(1192 * nY + 1634 * nV);
|
|
|
|
int nG = (int)(1192 * nY - 833 * nV - 400 * nU);
|
|
|
|
int nB = (int)(1192 * nY + 2066 * nU);
|
|
|
|
|
|
|
|
nR = std::min(kMaxChannelValue, std::max(0, nR));
|
|
|
|
nG = std::min(kMaxChannelValue, std::max(0, nG));
|
|
|
|
nB = std::min(kMaxChannelValue, std::max(0, nB));
|
|
|
|
|
|
|
|
nR = (nR >> 10) & 0xff;
|
|
|
|
nG = (nG >> 10) & 0xff;
|
|
|
|
nB = (nB >> 10) & 0xff;
|
|
|
|
|
|
|
|
return 0xff000000 | (nR << 16) | (nG << 8) | nB;
|
|
|
|
}
|
|
|
|
|
|
|
|
CPhoneDevice::CPhoneCamera::CPhoneCamera(CPhoneDevice* dev, int32_t width, int32_t height, const NdkCamera::CAMERA_PARAMS& params) : NdkCamera(width, height, params), m_dev(dev)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CPhoneDevice::CPhoneCamera::~CPhoneCamera()
|
|
|
|
{
|
|
|
|
m_dev = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::CPhoneCamera::on_image(cv::Mat& rgb)
|
|
|
|
{
|
|
|
|
if (m_dev != NULL)
|
|
|
|
{
|
|
|
|
return m_dev->OnImageReady(rgb);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::CPhoneCamera::on_error(const std::string& msg)
|
|
|
|
{
|
|
|
|
if (m_dev != NULL)
|
|
|
|
{
|
|
|
|
m_dev->onError(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPath, unsigned int netId) : mCameraPowerCount(0), mOtgCount(0)
|
|
|
|
{
|
|
|
|
mCamera = NULL;
|
|
|
|
m_listener = NULL;
|
|
|
|
m_pRecognizationCfg = NULL;
|
|
|
|
mHeartbeatStartTime = 0;
|
|
|
|
mHeartbeatDuration = 0;
|
|
|
|
m_javaService = NULL;
|
|
|
|
m_appPath = appPath;
|
|
|
|
|
|
|
|
mNetId = netId;
|
|
|
|
|
|
|
|
m_sysApiClass = NULL;
|
|
|
|
|
|
|
|
RegisterHandlerForSignal(SIGUSR2);
|
|
|
|
|
|
|
|
m_vm = vm;
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
}
|
|
|
|
m_javaService = env->NewGlobalRef(service);
|
|
|
|
|
|
|
|
jclass classService = env->GetObjectClass(m_javaService);
|
|
|
|
mRegisterHeartbeatMid = env->GetMethodID(classService, "registerHeartbeatTimer", "(I)V");
|
|
|
|
mUpdateTimeMid = env->GetMethodID(classService, "updateTime", "(J)Z");
|
|
|
|
mUpdateCaptureScheduleMid = env->GetMethodID(classService, "updateCaptureSchedule", "(JJ)Z");
|
|
|
|
mStartRecordingMid = env->GetMethodID(classService, "startRecording", "(IJIIII)V");
|
|
|
|
|
|
|
|
mRequestWakelockMid = env->GetMethodID(classService, "requestWakelock", "(Ljava/lang/String;J)V");
|
|
|
|
mReleaseWakelockMid = env->GetMethodID(classService, "releaseWakelock", "(Ljava/lang/String;)V");
|
|
|
|
|
|
|
|
mGetSystemInfoMid = env->GetMethodID(classService, "getSystemInfo", "()Ljava/lang/String;");
|
|
|
|
mRebootMid = env->GetMethodID(classService, "reboot", "(I)V");
|
|
|
|
mEnableGpsMid = env->GetMethodID(classService, "enableGps", "(Z)V");
|
|
|
|
mRequestPositionMid = env->GetMethodID(classService, "requestPosition", "()Z");
|
|
|
|
|
|
|
|
env->DeleteLocalRef(classService);
|
|
|
|
|
|
|
|
jclass classSysApi = env->FindClass("com/dev/devapi/api/SysApi");
|
|
|
|
if(classSysApi != NULL)
|
|
|
|
{
|
|
|
|
m_sysApiClass = (jclass)env->NewGlobalRef(classSysApi);
|
|
|
|
|
|
|
|
mTurnOtgMid = env->GetStaticMethodID(classSysApi, "setOtgState", "(Z)V");
|
|
|
|
mSetCam3V3EnableMid = env->GetStaticMethodID(classSysApi, "setCam3V3Enable", "(Z)V");
|
|
|
|
env->DeleteLocalRef(classSysApi);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_timerUidFeed = time(NULL) * 1000;
|
|
|
|
m_wakelockIdFeed = (unsigned long)m_timerUidFeed;
|
|
|
|
}
|
|
|
|
|
|
|
|
CPhoneDevice::~CPhoneDevice()
|
|
|
|
{
|
|
|
|
for (auto it = mTimers.begin(); it != mTimers.end(); ++it)
|
|
|
|
{
|
|
|
|
timer_delete((timer_t)it->first);
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
mTimers.clear();
|
|
|
|
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
}
|
|
|
|
env->DeleteGlobalRef(m_javaService);
|
|
|
|
if (m_sysApiClass != NULL)
|
|
|
|
{
|
|
|
|
env->DeleteGlobalRef(m_sysApiClass);
|
|
|
|
}
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
m_javaService = NULL;
|
|
|
|
m_sysApiClass = NULL;
|
|
|
|
|
|
|
|
if (m_pRecognizationCfg != NULL)
|
|
|
|
{
|
|
|
|
ncnn_uninit();
|
|
|
|
m_pRecognizationCfg = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::SetListener(IListener* listener)
|
|
|
|
{
|
|
|
|
m_listener = listener;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::SetRecognizationCfg(const IDevice::CFG_RECOGNIZATION* pRecognizationCfg)
|
|
|
|
{
|
|
|
|
if (m_pRecognizationCfg == NULL && pRecognizationCfg != NULL && (pRecognizationCfg->enabled != 0))
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
ncnn_init();
|
|
|
|
std::string paramFile = m_appPath + (APP_PATH_RECOG_PARAM);
|
|
|
|
std::string binFile = m_appPath + (APP_PATH_RECOG_BIN);
|
|
|
|
bool res = YoloV5Ncnn_Init(paramFile, binFile);
|
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
XYLOG(XYLOG_SEVERITY_INFO, "Succeeded to Init NCNN");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
XYLOG(XYLOG_SEVERITY_ERROR, "Failed to Init NCNN");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pRecognizationCfg = pRecognizationCfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::BindNetwork(int sock)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::UpdateTime(time_t ts)
|
|
|
|
{
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
jlong timeInMillis = ((jlong)ts) * 1000;
|
|
|
|
ret = env->CallBooleanMethod(m_javaService, mUpdateTimeMid, timeInMillis);
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret == JNI_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::UpdateSchedules()
|
|
|
|
{
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
time_t ts = time(NULL);
|
|
|
|
time_t zeroPoint = GetTimeOfZeroPoint(ts);
|
|
|
|
ret = env->CallBooleanMethod(m_javaService, mUpdateCaptureScheduleMid, zeroPoint, ts - zeroPoint);
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret == JNI_TRUE);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::QuerySystemProperties(std::map<std::string, std::string>& properties)
|
|
|
|
{
|
|
|
|
char value[PROP_VALUE_MAX] = { 0 };
|
|
|
|
std::map<std::string, std::string> powerInfo;
|
|
|
|
|
|
|
|
for (std::map<std::string, std::string>::iterator it = properties.begin(); it != properties.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it->first == PROP_EQUIP_NAME)
|
|
|
|
{
|
|
|
|
__system_property_get("ro.product.name", value);
|
|
|
|
it->second = value;
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_MODEL)
|
|
|
|
{
|
|
|
|
__system_property_get("ro.product.model", value);
|
|
|
|
it->second = value;
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_BS_MANU)
|
|
|
|
{
|
|
|
|
__system_property_get("ro.product.manufacturer", value);
|
|
|
|
it->second = value;
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_VERSION) {
|
|
|
|
__system_property_get("ro.build.version.release", value);
|
|
|
|
it->second = value;
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_PROD_DATE) {
|
|
|
|
__system_property_get("ro.build.date.utc", value);
|
|
|
|
it->second = value;
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_SN)
|
|
|
|
{
|
|
|
|
__system_property_get("ro.serialno", value);
|
|
|
|
it->second = value;
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_IMEI)
|
|
|
|
{
|
|
|
|
__system_property_get("phone.imei", value);
|
|
|
|
it->second = value;
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_OPERATION_TEMP)
|
|
|
|
{
|
|
|
|
it->second = QueryCpuTemperature();
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_BS_ID)
|
|
|
|
{
|
|
|
|
it->second = "SHXY";
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_FREE_ROM)
|
|
|
|
{
|
|
|
|
fs::space_info si = fs::space("/data");
|
|
|
|
it->second = std::to_string(si.available);
|
|
|
|
}
|
|
|
|
else if (it->first == PROP_TOTAL_ROM)
|
|
|
|
{
|
|
|
|
fs::space_info si = fs::space("/data");
|
|
|
|
it->second = std::to_string(si.capacity);
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_CHARGING_VOLTAGE))
|
|
|
|
{
|
|
|
|
double val = GpioControl::getChargingVoltage() / 200.0; // ChargeVol *5/1000
|
|
|
|
char str[32] = { 0 };
|
|
|
|
snprintf(str, sizeof(str), "%.1f", val);
|
|
|
|
it->second = str;
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_CHARGING_CURRENT))
|
|
|
|
{
|
|
|
|
it->second = std::to_string(GpioControl::getChargingCurrent());
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_CHARGING_POWER))
|
|
|
|
{
|
|
|
|
it->second = std::to_string(GpioControl::getChargingPower());
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_CHARGING_BUS_VOL))
|
|
|
|
{
|
|
|
|
it->second = std::to_string(GpioControl::getChargingBusVoltage());
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_BATTERY_VOLTAGE))
|
|
|
|
{
|
|
|
|
// double val = GpioControl::getBatteryVoltage() * 3.0 / 1000.0; // // BatVol
|
|
|
|
double val = GpioControl::getBatteryVoltage() / 1000.0; // // BatVol
|
|
|
|
char str[32] = { 0 };
|
|
|
|
snprintf(str, sizeof(str), "%.1f", val);
|
|
|
|
it->second = str;
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_BATTERY_CURRENT))
|
|
|
|
{
|
|
|
|
it->second = std::to_string(GpioControl::getBatteryCurrent());
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_BATTERY_POWER))
|
|
|
|
{
|
|
|
|
it->second = std::to_string(GpioControl::getBatteryPower());
|
|
|
|
}
|
|
|
|
else if (it->first == (PROP_BATTERY_BUS_VOL))
|
|
|
|
{
|
|
|
|
it->second = std::to_string(GpioControl::getBatteryBusVoltage());
|
|
|
|
}
|
|
|
|
else if (startsWith(it->first, PROP_JAVA_PREFIX))
|
|
|
|
{
|
|
|
|
if (powerInfo.empty())
|
|
|
|
{
|
|
|
|
QueryPowerInfo(powerInfo);
|
|
|
|
}
|
|
|
|
auto it2 = powerInfo.find(it->first);
|
|
|
|
if (it2 != powerInfo.cend())
|
|
|
|
{
|
|
|
|
it->second = it2->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// __system_property_get("ro.telephony.default_network", value);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CPhoneDevice::QueryCpuTemperature()
|
|
|
|
{
|
|
|
|
// /sys/devices/virtual/thermal/thermal_zone0/temp
|
|
|
|
std::vector<unsigned char> data;
|
|
|
|
if (readFile("/sys/devices/virtual/thermal/thermal_zone0/temp", data) && !data.empty())
|
|
|
|
{
|
|
|
|
data.push_back(0);
|
|
|
|
int temp = atoi((const char*)(&data[0]));
|
|
|
|
return std::to_string(temp / 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::QueryPowerInfo(std::map<std::string, std::string>& powerInfo)
|
|
|
|
{
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
jobject jobj = env->CallObjectMethod(m_javaService, mGetSystemInfoMid);
|
|
|
|
std::string str = jstring2string(env, (jstring)jobj);
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!str.empty())
|
|
|
|
{
|
|
|
|
std::map<std::string, std::string> queries = parseQuery(str);
|
|
|
|
powerInfo.swap(queries);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::GetNextScheduleItem(uint32_t tsBasedZero, uint32_t scheduleTime, vector<uint32_t>& items)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::Reboot(int resetType)
|
|
|
|
{
|
|
|
|
if (resetType == 1)
|
|
|
|
{
|
|
|
|
// reboot the device
|
|
|
|
GpioControl::reboot();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
}
|
|
|
|
env->CallVoidMethod(m_javaService, mRebootMid, resetType);
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::EnableGPS(bool enabled)
|
|
|
|
{
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
jboolean jenabled = enabled ? JNI_TRUE : JNI_FALSE;
|
|
|
|
env->CallVoidMethod(m_javaService, mEnableGpsMid, jenabled);
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::RequestPosition()
|
|
|
|
{
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jboolean ret = env->CallBooleanMethod(m_javaService, mRequestPositionMid);
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret == JNI_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::handleSignal(int sig, siginfo_t *si, void *uc)
|
|
|
|
{
|
|
|
|
TIMER_CONTEXT* context = (TIMER_CONTEXT*)(si->si_value.sival_ptr);
|
|
|
|
context->device->handleTimerImpl(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::RegisterHandlerForSignal(int sig)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
// Establish handler for timer signal
|
|
|
|
struct sigaction sa;
|
|
|
|
sigset_t mask;
|
|
|
|
|
|
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sa.sa_sigaction = CPhoneDevice::handleSignal;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
if (sigaction(sig, &sa, NULL) == -1)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
// Block timer signal temporarily
|
|
|
|
|
|
|
|
// printf("Blocking signal %d\n", SIG);
|
|
|
|
sigemptyset(&mask);
|
|
|
|
sigaddset(&mask, sig);
|
|
|
|
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::handleTimer(union sigval v)
|
|
|
|
{
|
|
|
|
TIMER_CONTEXT* context = (TIMER_CONTEXT*)(v.sival_ptr);
|
|
|
|
context->device->handleTimerImpl(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::handleTimerImpl(CPhoneDevice::TIMER_CONTEXT* context)
|
|
|
|
{
|
|
|
|
context->times++;
|
|
|
|
if (context->expectedTimes == 0 || context->times <= context->expectedTimes)
|
|
|
|
{
|
|
|
|
if (m_listener != NULL)
|
|
|
|
{
|
|
|
|
m_listener->OnTimeout(context->uid, context->timerType, context->data, context->times);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IDevice::timer_uid_t CPhoneDevice::RegisterTimer(unsigned int timerType, unsigned int timeout, void* data, unsigned long times/* = 0*/)
|
|
|
|
{
|
|
|
|
struct sigevent evp = { 0 };
|
|
|
|
struct itimerspec ts = { 0 };
|
|
|
|
timer_t timer;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
TIMER_CONTEXT* context = new TIMER_CONTEXT();
|
|
|
|
context->device = this;
|
|
|
|
context->data = data;
|
|
|
|
context->timerType = timerType;
|
|
|
|
context->expectedTimes = times;
|
|
|
|
|
|
|
|
evp.sigev_value.sival_ptr = context;
|
|
|
|
evp.sigev_notify = SIGEV_THREAD; //SIGEV_THREAD_ID;
|
|
|
|
evp.sigev_notify_function = CPhoneDevice::handleTimer;
|
|
|
|
// evp.sigev_notify_thread_id = gettid();
|
|
|
|
// evp.sigev_notify = SIGEV_SIGNAL;
|
|
|
|
// evp.sigev_signo = SIGUSR2;
|
|
|
|
|
|
|
|
ret = timer_create(CLOCK_REALTIME, &evp, &timer);
|
|
|
|
if( ret)
|
|
|
|
{
|
|
|
|
int err = errno;
|
|
|
|
delete context;
|
|
|
|
return INVALID_TIMER_UID;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->uid = (unsigned long)timer;
|
|
|
|
ts.it_value.tv_sec = (timeout / 1000);
|
|
|
|
ts.it_value.tv_nsec = (timeout % 1000) * 1000;
|
|
|
|
if (times != 1)
|
|
|
|
{
|
|
|
|
ts.it_interval.tv_sec = ts.it_value.tv_sec;
|
|
|
|
ts.it_interval.tv_nsec = ts.it_value.tv_nsec;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = timer_settime(timer, 0, &ts, NULL);
|
|
|
|
|
|
|
|
if(ret)
|
|
|
|
{
|
|
|
|
timer_delete(timer);
|
|
|
|
delete context;
|
|
|
|
return INVALID_TIMER_UID;
|
|
|
|
}
|
|
|
|
|
|
|
|
mTimers.insert(mTimers.end(), std::pair<IDevice::timer_uid_t, TIMER_CONTEXT*>((IDevice::timer_uid_t)timer, context));
|
|
|
|
return (IDevice::timer_uid_t)timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::UnregisterTimer(IDevice::timer_uid_t uid)
|
|
|
|
{
|
|
|
|
timer_t timer = (timer_t)uid;
|
|
|
|
int res = timer_delete(timer);
|
|
|
|
|
|
|
|
std::map<IDevice::timer_uid_t, TIMER_CONTEXT*>::iterator it = mTimers.find(uid);
|
|
|
|
if (it != mTimers.end())
|
|
|
|
{
|
|
|
|
delete it->second;
|
|
|
|
mTimers.erase(it);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long CPhoneDevice::RequestWakelock(unsigned long timeout)
|
|
|
|
{
|
|
|
|
unsigned long wakelockId = m_wakelockIdFeed.fetch_add(1);
|
|
|
|
std::string name = WAKELOCK_NAME;
|
|
|
|
name += to_string(wakelockId);
|
|
|
|
|
|
|
|
// ALOGI("RequestWakelock=%lld",wakelockId);
|
|
|
|
|
|
|
|
jboolean ret = JNI_FALSE;
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
jstring jname = env->NewStringUTF(name.c_str());
|
|
|
|
jlong jtimeout = (jlong)timeout;
|
|
|
|
|
|
|
|
env->CallVoidMethod(m_javaService, mRequestWakelockMid, jname, jtimeout);
|
|
|
|
// env->ReleaseStringUTFChars(jname, name.c_str());
|
|
|
|
env->DeleteLocalRef(jname);
|
|
|
|
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return wakelockId;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::ReleaseWakelock(unsigned long wakelock)
|
|
|
|
{
|
|
|
|
// ALOGI("ReleaseWakelock=%lld", wakelock);
|
|
|
|
std::string name = WAKELOCK_NAME;
|
|
|
|
name += to_string(wakelock);
|
|
|
|
|
|
|
|
jboolean ret = JNI_FALSE;
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
jstring jname = env->NewStringUTF(name.c_str());
|
|
|
|
|
|
|
|
env->CallVoidMethod(m_javaService, mReleaseWakelockMid, jname);
|
|
|
|
env->DeleteLocalRef(jname);
|
|
|
|
// env->ReleaseStringUTFChars(jname, name.c_str());
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
IDevice::timer_uid_t CPhoneDevice::RegisterHeartbeat(unsigned int timerType, unsigned int timeout)
|
|
|
|
{
|
|
|
|
mHeartbeatStartTime = time(NULL);
|
|
|
|
mHeartbeatDuration = timeout;
|
|
|
|
|
|
|
|
IDevice::timer_uid_t uid = m_timerUidFeed.fetch_add(1);
|
|
|
|
|
|
|
|
jboolean ret = JNI_FALSE;
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
bool res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
env->CallVoidMethod(m_javaService, mRegisterHeartbeatMid, (jint)timeout);
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<OSD_INFO>& osds, const std::string& path)
|
|
|
|
{
|
|
|
|
if (m_threadClose.joinable())
|
|
|
|
{
|
|
|
|
m_threadClose.join();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mCamera != NULL)
|
|
|
|
{
|
|
|
|
delete mCamera;
|
|
|
|
mCamera = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
XYLOG(XYLOG_SEVERITY_INFO, "TAKE_PHOTO: CH=%u PR=%u PHOTOID=%u\n", (unsigned int)photoInfo.channel, (unsigned int)photoInfo.preset, photoInfo.photoId);
|
|
|
|
mPhotoInfo = photoInfo;
|
|
|
|
mPath = path;
|
|
|
|
mOsds = osds;
|
|
|
|
|
|
|
|
NdkCamera::CAMERA_PARAMS params;
|
|
|
|
params.hdrMode = mPhotoInfo.hdrMode;
|
|
|
|
params.nightMode = mPhotoInfo.nightMode;
|
|
|
|
params.autoFocus = mPhotoInfo.autoFocus;
|
|
|
|
params.autoExposure = mPhotoInfo.autoExposure;
|
|
|
|
params.exposureTime = mPhotoInfo.exposureTime;
|
|
|
|
params.sensibility = mPhotoInfo.sensibility;
|
|
|
|
params.orientation = mPhotoInfo.orientation;
|
|
|
|
|
|
|
|
// GpioControl::EnableGpio(CMD_SET_CAM_3V3_EN_STATE, true);
|
|
|
|
bool res = false;
|
|
|
|
JNIEnv* env = NULL;
|
|
|
|
bool didAttachThread = false;
|
|
|
|
res = GetJniEnv(m_vm, &env, didAttachThread);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
ALOGE("Failed to get JNI Env");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (photoInfo.usbCamera)
|
|
|
|
{
|
|
|
|
TurnOnOtg(env);
|
|
|
|
}
|
|
|
|
TurnOnCameraPower(env);
|
|
|
|
|
|
|
|
res = true;
|
|
|
|
if (mPhotoInfo.mediaType == 0)
|
|
|
|
{
|
|
|
|
mCamera = new CPhoneCamera(this, photoInfo.width, photoInfo.height, params);
|
|
|
|
if (mCamera->open(to_string(mPhotoInfo.cameraId)) == 0)
|
|
|
|
{
|
|
|
|
XYLOG(XYLOG_SEVERITY_DEBUG, "TP: Succeeded to OpenCamera CH=%u PR=%u PHOTOID=%u\n", (unsigned int)photoInfo.channel, (unsigned int)photoInfo.preset, photoInfo.photoId);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
XYLOG(XYLOG_SEVERITY_DEBUG, "TP: Failed to OpenCamera CH=%u PR=%u PHOTOID=%u\n", (unsigned int)photoInfo.channel, (unsigned int)photoInfo.preset, photoInfo.photoId);
|
|
|
|
delete mCamera;
|
|
|
|
mCamera = NULL;
|
|
|
|
res = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
env->CallVoidMethod(m_javaService, mStartRecordingMid, mPhotoInfo.cameraId, (unsigned long)mPhotoInfo.photoId, mPhotoInfo.duration, mPhotoInfo.width, mPhotoInfo.height, mPhotoInfo.duration);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (didAttachThread)
|
|
|
|
{
|
|
|
|
m_vm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::CloseCamera()
|
|
|
|
{
|
|
|
|
if (mCamera != NULL)
|
|
|
|
{
|
|
|
|
auto camera = mCamera;
|
|
|
|
mCamera = NULL;
|
|
|
|
|
|
|
|
camera->close();
|
|
|
|
delete camera;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::CloseCamera2(CPhoneDevice::CPhoneCamera* camera, unsigned int photoId, bool turnOffOtg)
|
|
|
|
{
|
|
|
|
XYLOG(XYLOG_SEVERITY_DEBUG, "TP: CloseCamera PHOTOID=%u", photoId);
|
|
|
|
|
|
|
|
// std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
|
|
|
if (camera != NULL)
|
|
|
|
{
|
|
|
|
camera->close();
|
|
|
|
delete camera;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (turnOffOtg)
|
|
|
|
{
|
|
|
|
TurnOffOtg(NULL);
|
|
|
|
}
|
|
|
|
TurnOffCameraPower(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void visualize(const char* filename, const ncnn::Mat& m)
|
|
|
|
{
|
|
|
|
cv::Mat a(m.h, m.w, CV_8UC3);
|
|
|
|
m.to_pixels(a.data, ncnn::Mat::PIXEL_BGR2RGB);
|
|
|
|
|
|
|
|
cv::imwrite(filename, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DrawOutlineText(cv::Mat& mat, const std::string& str, cv::Point startPoint, double fontScale, cv::Scalar clr1, cv::Scalar clr2, int thickness1, int thickness2)
|
|
|
|
{
|
|
|
|
std::vector<std::string> chars;
|
|
|
|
splitUtf8Str(str, chars);
|
|
|
|
int lineHeight = 0;
|
|
|
|
cv::Point pt = startPoint;
|
|
|
|
cv::Size textSize, textSize2;
|
|
|
|
int baseline = 0;
|
|
|
|
cv::Point pt2;
|
|
|
|
|
|
|
|
for (std::vector<std::string>::const_iterator it = chars.cbegin(); it != chars.cend(); ++it )
|
|
|
|
{
|
|
|
|
if (it->compare("\n") == 0)
|
|
|
|
{
|
|
|
|
pt.x = startPoint.x;
|
|
|
|
pt.y += lineHeight > 0 ? (lineHeight + 2) : 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
textSize = cv::getTextSize(*it, cv::FONT_HERSHEY_COMPLEX, fontScale, thickness1, &baseline);
|
|
|
|
textSize2 = cv::getTextSize(*it, cv::FONT_HERSHEY_COMPLEX, fontScale, thickness2, &baseline);
|
|
|
|
|
|
|
|
lineHeight = std::max(lineHeight, std::max(textSize.height, textSize2.height));
|
|
|
|
|
|
|
|
if (it->compare(" ") != 0)
|
|
|
|
{
|
|
|
|
// cv2.putText(image,"text",(180,150),cv2.FONT_HERSHEY_COMPLEX,3,(255,255,255),16,cv2.LINE_AA)
|
|
|
|
// cv2.putText(image,"text",(180,150),cv2.FONT_HERSHEY_COMPLEX,3,(0,0,0),4,cv2.LINE
|
|
|
|
|
|
|
|
// balck
|
|
|
|
|
|
|
|
cv::putText(mat, *it, pt, cv::FONT_HERSHEY_COMPLEX, fontScale, clr1, thickness1, cv::LINE_AA);
|
|
|
|
// white
|
|
|
|
pt2 = pt;
|
|
|
|
// pt2.y += 1;
|
|
|
|
cv::putText(mat, *it, pt2, cv::FONT_HERSHEY_COMPLEX, fontScale, clr2, thickness2, cv::LINE_AA);
|
|
|
|
}
|
|
|
|
|
|
|
|
pt.x += std::max(textSize.width, textSize2.width);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::OnImageReady(cv::Mat& mat)
|
|
|
|
{
|
|
|
|
if (mCamera == NULL)
|
|
|
|
{
|
|
|
|
int aa = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mPhotoInfo.photoTime = time(NULL);
|
|
|
|
int baseline = 0;
|
|
|
|
cv::Size textSize, textSize2;
|
|
|
|
double fontScale = 1; // base 1024
|
|
|
|
double height = mat.size().height;
|
|
|
|
double width = mat.size().width;
|
|
|
|
// double ratio = std::min(height / 1024, width / 1920);
|
|
|
|
double ratio = std::sqrt((height * width) / (1024.0 * 1920.0));
|
|
|
|
fontScale = fontScale * ratio;
|
|
|
|
|
|
|
|
// cv::Rect rc(0, 0, mat.cols, mat.rows);
|
|
|
|
// cv::rectangle (mat, rc, cv::Scalar(255, 255, 255), cv::FILLED);
|
|
|
|
std::vector<IDevice::RECOG_OBJECT> objs;
|
|
|
|
|
|
|
|
if ((m_pRecognizationCfg != NULL) && (m_pRecognizationCfg->enabled != 0) && (mPhotoInfo.recognization != 0))
|
|
|
|
{
|
|
|
|
// visualize(ncnnPath.c_str(), in);
|
|
|
|
#ifdef _DEBUG
|
|
|
|
double startTime = ncnn::get_current_time();
|
|
|
|
#endif // _DEBUG
|
|
|
|
|
|
|
|
bool detected = YoloV5NcnnDetect(mat, true, m_pRecognizationCfg->blobName8, m_pRecognizationCfg->blobName16, m_pRecognizationCfg->blobName32, objs);
|
|
|
|
#ifdef _DEBUG
|
|
|
|
double elasped = ncnn::get_current_time() - startTime;
|
|
|
|
// __android_log_print(ANDROID_LOG_DEBUG, "YoloV5Ncnn", "%.2fms detect", elasped);
|
|
|
|
#endif // _DEBUG
|
|
|
|
#ifdef _DEBUG
|
|
|
|
ALOGI( "NCNN recognization: %.2fms res=%d", elasped, ((detected && !objs.empty()) ? 1 : 0));
|
|
|
|
#endif
|
|
|
|
if (detected && !objs.empty())
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
static const char* class_names[] = {
|
|
|
|
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
|
|
|
|
"fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
|
|
|
|
"elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
|
|
|
|
"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
|
|
|
|
"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
|
|
|
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
|
|
|
|
"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
|
|
|
|
"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
|
|
|
|
"hair drier", "toothbrush"
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
cv::Scalar borderColor(m_pRecognizationCfg->borderColor & 0xFF, (m_pRecognizationCfg->borderColor & 0xFF00) >> 8, (m_pRecognizationCfg->borderColor & 0xFF0000) >> 16);
|
|
|
|
for (std::vector<IDevice::RECOG_OBJECT>::const_iterator it = objs.cbegin(); it != objs.cend(); ++it)
|
|
|
|
{
|
|
|
|
if (it->label >= m_pRecognizationCfg->items.size())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const IDevice::CFG_RECOGNIZATION::ITEM& item = m_pRecognizationCfg->items[it->label];
|
|
|
|
if (item.enabled == 0 || it->prob < item.prob)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
ALOGD("Label: %d=%s (%f,%f)-(%f,%f)", it->label, item.name.c_str(), it->x, it->y, it->w, it->h);
|
|
|
|
#endif
|
|
|
|
cv::Rect rc(it->x, it->y, it->w, it->h);
|
|
|
|
cv::rectangle(mat, rc, borderColor, m_pRecognizationCfg->thickness);
|
|
|
|
// putText
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int thickness2 = 4 * ratio;
|
|
|
|
if (thickness2 < 2) thickness2 = 2;
|
|
|
|
int thickness1 = 2 * ratio;
|
|
|
|
if (thickness1 < 1) thickness1 = 1;
|
|
|
|
|
|
|
|
cv::Scalar scalar1(0, 0, 0); // black
|
|
|
|
cv::Scalar scalar2(255, 255, 255); // white
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
|
|
|
cv::Scalar scalar(0, 0, 255); // white
|
|
|
|
|
|
|
|
NdkCamera::CAPTURE_RESULT captureResult = mCamera->getCaptureResult();
|
|
|
|
char str[128] = { 0 };
|
|
|
|
snprintf(str, sizeof(str), "AE=%u EXPS=%ums ISO=%d AF=%u FD=%.3f HDR=%d", captureResult.autoExposure,
|
|
|
|
(unsigned int)(captureResult.exposureTime / 1000000),
|
|
|
|
captureResult.sensitibity,
|
|
|
|
captureResult.autoFocus,
|
|
|
|
isnan(captureResult.FocusDistance) ? 0 : captureResult.FocusDistance,
|
|
|
|
captureResult.hdrMode);
|
|
|
|
cv::putText(mat, str, cv::Point(0, mat.rows - 20), cv::FONT_HERSHEY_COMPLEX, fontScale, scalar, thickness1, cv::LINE_AA);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
cv::Point pt1, pt2;
|
|
|
|
for (vector<OSD_INFO>::const_iterator it = mOsds.cbegin(); it != mOsds.cend(); ++it)
|
|
|
|
{
|
|
|
|
if (it->text.empty())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
textSize = cv::getTextSize(it->text, cv::FONT_HERSHEY_TRIPLEX, fontScale, thickness1, &baseline);
|
|
|
|
textSize2 = cv::getTextSize(it->text, cv::FONT_HERSHEY_TRIPLEX, fontScale, thickness2, &baseline);
|
|
|
|
|
|
|
|
if (it->alignment == OSD_ALIGNMENT_TOP_LEFT)
|
|
|
|
{
|
|
|
|
pt1.x = it->x * ratio;
|
|
|
|
pt1.y = it->y * ratio + textSize.height;
|
|
|
|
}
|
|
|
|
else if (it->alignment == OSD_ALIGNMENT_TOP_RIGHT)
|
|
|
|
{
|
|
|
|
pt1.x = width - textSize.width - it->x * ratio;
|
|
|
|
pt1.y= it->y * ratio + textSize.height;
|
|
|
|
}
|
|
|
|
else if (it->alignment == OSD_ALIGNMENT_BOTTOM_RIGHT)
|
|
|
|
{
|
|
|
|
pt1.x = width - textSize.width - it->x * ratio;
|
|
|
|
pt1.y = height - it->y * ratio;
|
|
|
|
}
|
|
|
|
else if (it->alignment == OSD_ALIGNMENT_BOTTOM_LEFT)
|
|
|
|
{
|
|
|
|
pt1.x = it->x * ratio;
|
|
|
|
pt1.y = height - it->y * ratio;
|
|
|
|
}
|
|
|
|
|
|
|
|
cv::Point pt = pt1;
|
|
|
|
pt.x += textSize.width;
|
|
|
|
pt.y -= textSize.height;
|
|
|
|
|
|
|
|
// cv::rectangle(mat, pt1, pt, scalar2, -1);
|
|
|
|
pt2 = pt1;
|
|
|
|
pt2.y += textSize.height;
|
|
|
|
|
|
|
|
DrawOutlineText(mat, it->text, pt1, fontScale, scalar1, scalar2, thickness1, thickness2);
|
|
|
|
}
|
|
|
|
|
|
|
|
vector <int> params;
|
|
|
|
params.push_back(cv::IMWRITE_JPEG_QUALITY);
|
|
|
|
params.push_back(mPhotoInfo.quality);
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
std::string fullPath = mPath + CTerminal::BuildPhotoFileName(mPhotoInfo);
|
|
|
|
if (!std::filesystem::exists(std::filesystem::path(fullPath)))
|
|
|
|
{
|
|
|
|
bool res = cv::imwrite(fullPath.c_str(), mat, params);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
XYLOG(XYLOG_SEVERITY_ERROR, "Failed to write photo: %s", fullPath.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
XYLOG(XYLOG_SEVERITY_INFO, "Succeeded to write photo: %s", fullPath.c_str());
|
|
|
|
}
|
|
|
|
TakePhotoCb(res, mPhotoInfo, fullPath, time(NULL), objs);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALOGI("Photo file exists: %s", mPath.c_str());
|
|
|
|
}
|
|
|
|
CPhoneCamera* pCamera = mCamera;
|
|
|
|
mCamera = NULL;
|
|
|
|
|
|
|
|
bool turnOffOtg = (mPhotoInfo.usbCamera != 0);
|
|
|
|
std::thread closeThread(&CPhoneDevice::CloseCamera2, this, pCamera, mPhotoInfo.photoId, turnOffOtg);
|
|
|
|
m_threadClose.swap(closeThread);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CPhoneDevice::OnVideoReady(bool result, const char* path, unsigned int photoId)
|
|
|
|
{
|
|
|
|
mPhotoInfo.photoTime = time(NULL);
|
|
|
|
|
|
|
|
CPhoneCamera* pCamera = NULL;
|
|
|
|
std::vector<IDevice::RECOG_OBJECT> objs;
|
|
|
|
std::string fullPath = mPath + CTerminal::BuildPhotoFileName(mPhotoInfo);
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
std::rename(path, fullPath.c_str());
|
|
|
|
}
|
|
|
|
TakePhotoCb(result, mPhotoInfo, fullPath, time(NULL), objs);
|
|
|
|
|
|
|
|
bool turnOffOtg = (mPhotoInfo.usbCamera != 0);
|
|
|
|
std::thread closeThread(&CPhoneDevice::CloseCamera2, this, pCamera, mPhotoInfo.photoId, turnOffOtg);
|
|
|
|
m_threadClose.swap(closeThread);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::onError(const std::string& msg)
|
|
|
|
{
|
|
|
|
if (mCamera == NULL)
|
|
|
|
{
|
|
|
|
int aa = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
XYLOG(XYLOG_SEVERITY_ERROR, "Failed to Take Photo (IMGID=%u): %s", mPhotoInfo.photoId, msg.c_str());
|
|
|
|
|
|
|
|
CPhoneCamera* pCamera = mCamera;
|
|
|
|
mCamera = NULL;
|
|
|
|
|
|
|
|
TakePhotoCb(false, mPhotoInfo, mPath, 0);
|
|
|
|
|
|
|
|
bool turnOffOtg = (mPhotoInfo.usbCamera != 0);
|
|
|
|
std::thread closeThread(&CPhoneDevice::CloseCamera2, this, pCamera, mPhotoInfo.photoId, turnOffOtg);
|
|
|
|
closeThread.detach();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CPhoneDevice::GetFileName() const
|
|
|
|
{
|
|
|
|
return mPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::UpdatePosition(double lon, double lat, time_t ts)
|
|
|
|
{
|
|
|
|
if (m_listener != NULL)
|
|
|
|
{
|
|
|
|
return m_listener->OnPositionDataArrived(lon, lat, ts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::TurnOnCameraPower(JNIEnv* env)
|
|
|
|
{
|
|
|
|
mCameraPowerLocker.lock();
|
|
|
|
if (mCameraPowerCount == 0)
|
|
|
|
{
|
|
|
|
GpioControl::setCam3V3Enable(true);
|
|
|
|
}
|
|
|
|
mCameraPowerCount++;
|
|
|
|
mCameraPowerLocker.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::TurnOffCameraPower(JNIEnv* env)
|
|
|
|
{
|
|
|
|
mCameraPowerLocker.lock();
|
|
|
|
if (mCameraPowerCount > 0)
|
|
|
|
{
|
|
|
|
mCameraPowerCount--;
|
|
|
|
if (mCameraPowerCount == 0)
|
|
|
|
{
|
|
|
|
GpioControl::setCam3V3Enable(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mCameraPowerLocker.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::TurnOnOtg(JNIEnv* env)
|
|
|
|
{
|
|
|
|
mCameraPowerLocker.lock();
|
|
|
|
if (mOtgCount == 0)
|
|
|
|
{
|
|
|
|
ALOGD("setOtgState 1");
|
|
|
|
GpioControl::setOtgState(true);
|
|
|
|
}
|
|
|
|
mOtgCount++;
|
|
|
|
mCameraPowerLocker.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPhoneDevice::TurnOffOtg(JNIEnv* env)
|
|
|
|
{
|
|
|
|
mCameraPowerLocker.lock();
|
|
|
|
if (mOtgCount > 0)
|
|
|
|
{
|
|
|
|
mOtgCount--;
|
|
|
|
if (mOtgCount == 0)
|
|
|
|
{
|
|
|
|
ALOGD("setOtgState 0");
|
|
|
|
GpioControl::setOtgState(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mCameraPowerLocker.unlock();
|
|
|
|
}
|