Merge remote-tracking branch 'origin/main'

PtzNew
jxjajs 3 months ago
commit 2e12a1ac84

@ -5,7 +5,7 @@ plugins {
// 10,00,000 major-minor-build // 10,00,000 major-minor-build
def AppMajorVersion = 1 def AppMajorVersion = 1
def AppMinorVersion = 3 def AppMinorVersion = 3
def AppBuildNumber = 63 def AppBuildNumber = 72
def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber
def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber

@ -21,7 +21,7 @@ if(ANDROID_ABI STREQUAL "armeabi-v7a")
add_definitions(-DUSING_N938) add_definitions(-DUSING_N938)
elseif(ANDROID_ABI STREQUAL "arm64-v8a") elseif(ANDROID_ABI STREQUAL "arm64-v8a")
# add_definitions(-DUSING_N938) # add_definitions(-DUSING_N938)
add_definitions(-DUSING_PLZ) # add_definitions(-DUSING_PLZ)
endif() endif()
# OUTPUT_DBG_INFO: # OUTPUT_DBG_INFO:
@ -154,7 +154,7 @@ add_definitions(-DDISABLE_RTTI)
# include_directories( ${HDRPLUS_ROOT}/${ANDROID_ABI}/include/ZLToolKit/src/ ) # include_directories( ${HDRPLUS_ROOT}/${ANDROID_ABI}/include/ZLToolKit/src/ )
# SET(ZLMEDIAKIT_LIBS ${ZLMEDIAKIT_LIBS} zlmediakit zltoolkit) # SET(ZLMEDIAKIT_LIBS ${ZLMEDIAKIT_LIBS} zlmediakit zltoolkit)
SET(STREAMING_SRCS media/RTSPToMP4.cpp media/RTSPRecorder.cpp ) SET(STREAMING_SRCS media/RTSPToMP4.cpp media/RTSPRecorder.cpp media/Streaming.cpp )
SET(HDRPLUS_LIBS raw exiv2 exiv2-xmp expat lcms2 OpenMP::OpenMP_CXX) SET(HDRPLUS_LIBS raw exiv2 exiv2-xmp expat lcms2 OpenMP::OpenMP_CXX)
@ -396,6 +396,9 @@ add_library( # Sets the name of the library.
ncnn/yolov5ncnn.cpp ncnn/yolov5ncnn.cpp
netcamera/httpclient.cpp netcamera/httpclient.cpp
netcamera/VendorCtrl.cpp
netcamera/YuShiCtrl.cpp
netcamera/HangYuCtrl.cpp
${STREAMING_SRCS} ${STREAMING_SRCS}
@ -445,6 +448,7 @@ add_library( # Sets the name of the library.
${TERM_CORE_ROOT}/Client/UpgradeReceiver.cpp ${TERM_CORE_ROOT}/Client/UpgradeReceiver.cpp
${TERM_CORE_ROOT}/Client/Database.cpp ${TERM_CORE_ROOT}/Client/Database.cpp
${TERM_CORE_ROOT}/Client/SimulatorDevice.cpp ${TERM_CORE_ROOT}/Client/SimulatorDevice.cpp
${TERM_CORE_ROOT}/Client/DataController.cpp
) )

@ -496,6 +496,10 @@ void GpioControl::PowerControlThreadProc()
bool GpioControl::Startup() bool GpioControl::Startup()
{ {
if (m_thread.joinable())
{
return true;
}
// if (m_thread.) // if (m_thread.)
m_exitSignal = false; m_exitSignal = false;
m_thread = std::thread(PowerControlThreadProc); m_thread = std::thread(PowerControlThreadProc);

@ -1421,3 +1421,15 @@ Java_com_xypower_mpapp_MicroPhotoService_releasePowerControl(
return JNI_TRUE; return JNI_TRUE;
} }
extern "C"
JNIEXPORT jint JNICALL
Java_com_xypower_mpapp_MicroPhotoService_getCustomAppId(JNIEnv *env, jobject thiz) {
#ifdef USING_N938
return 2;
#elif defined(USING_PLZ)
return 1;
#else
return 0;
#endif
}

@ -9,6 +9,11 @@
#include "CvText.h" #include "CvText.h"
#include "PositionHelper.h" #include "PositionHelper.h"
#include "DngCreator.h" #include "DngCreator.h"
#include "media/Streaming.h"
#include "netcamera/VendorCtrl.h"
#include "netcamera/YuShiCtrl.h"
#include "netcamera/HangYuCtrl.h"
#include "media/RTSPRecorder.h" #include "media/RTSPRecorder.h"
@ -1711,8 +1716,8 @@ bool CPhoneDevice::TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
} }
XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power ON"); XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power ON");
// std::shared_ptr<PowerControl> ethernetPowerCtrl = std::make_shared<EthernetPowerCtrl>(1); std::shared_ptr<PowerControl> ethernetPowerCtrl = std::make_shared<EthernetPowerCtrl>(1);
std::shared_ptr<PowerControl> ethernetPowerCtrl; // std::shared_ptr<PowerControl> ethernetPowerCtrl;
net_handle_t netHandle = GetEthnetHandle(); net_handle_t netHandle = GetEthnetHandle();
if (netHandle == 0) if (netHandle == 0)
@ -1747,64 +1752,37 @@ bool CPhoneDevice::TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
// SetStaticIp(); // SetStaticIp();
std::this_thread::sleep_for(std::chrono::milliseconds(256)); std::this_thread::sleep_for(std::chrono::milliseconds(256));
NET_PHOTO_INFO netPhotoInfo = { netHandle, 0 }; struct in_addr addr;
if (localPhotoInfo.vendor == 1) char ip[32] = { 0 };
{ addr.s_addr = localPhotoInfo.ip;
// Hai Kang strcpy(ip, inet_ntoa(addr));
netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST; // strcpy(netPhotoInfo.outputPath, path.c_str());
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/ISAPI/Streaming/channels/1/picture?");
} VendorCtrl* vendorCtrl = MakeVendorCtrl(localPhotoInfo.vendor, localPhotoInfo.channel, ip, localPhotoInfo.userName, localPhotoInfo.password, netHandle);
else if (localPhotoInfo.vendor == 2) if (vendorCtrl == NULL)
{
// Hang Yu
strcpy(netPhotoInfo.url, "/cgi-bin/snapshot.cgi");
}
else if (localPhotoInfo.vendor == 3)
{
// Yu Shi
netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST;
int streamSid = 0; // should put into config
// rtsp://192.168.0.13:554/media/video1
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/media/video%u", (uint32_t)localPhotoInfo.cameraId);
// strcpy(netPhotoInfo.url, "rtsp://192.168.50.224/live/0");
}
else if (localPhotoInfo.vendor == 5)
{
// Hang Yu - New
netPhotoInfo.authType = HTTP_AUTH_TYPE_BASIC;
// http://192.168.1.46/Snapshot/%u/RemoteImageCapture?ImageFormat=2&HorizontalPixel=1920&VerticalPixel=1080
// http://192.168.1.101/Snapshot/1/2/RemoteImageCaptureV2?ImageFormat=jpg
// http://192.168.1.101/Snapshot/1/1/RemoteImageCaptureV2?ImageFormat=jpg
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/Snapshot/%u/1/RemoteImageCaptureV2?ImageFormat=jpg", (uint32_t)localPhotoInfo.cameraId);
}
else
{ {
XYLOG(XYLOG_SEVERITY_ERROR, "Vendor(%u) not Supported CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.vendor, (uint32_t)localPhotoInfo.channel, (unsigned int)localPhotoInfo.preset, localPhotoInfo.photoId); XYLOG(XYLOG_SEVERITY_ERROR, "Vendor(%u) not Supported CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.vendor, (uint32_t)localPhotoInfo.channel, (unsigned int)localPhotoInfo.preset, localPhotoInfo.photoId);
TakePhotoCb(0, localPhotoInfo, "", 0); TakePhotoCb(0, localPhotoInfo, "", 0);
return false; return false;
} }
struct in_addr addr; std::string streamingUrl = vendorCtrl->GetStreamingUrl(localPhotoInfo.cameraId);
addr.s_addr = localPhotoInfo.ip;
strcpy(netPhotoInfo.ip, inet_ntoa(addr)); if (streamingUrl.empty())
strcpy(netPhotoInfo.outputPath, path.c_str());
if (!localPhotoInfo.userName.empty())
{
size_t len = std::min<size_t>(sizeof(netPhotoInfo.userName) - 1, localPhotoInfo.userName.size());
strncpy(netPhotoInfo.userName, localPhotoInfo.userName.c_str(), len);
}
if (!localPhotoInfo.password.empty())
{ {
size_t len = std::min<size_t>(sizeof(netPhotoInfo.password) - 1, localPhotoInfo.password.size()); XYLOG(XYLOG_SEVERITY_ERROR, "Invalid Streaming URL CH=%u PR=%X PHOTOID=%u", (uint32_t)localPhotoInfo.channel, (unsigned int)localPhotoInfo.preset, localPhotoInfo.photoId);
strncpy(netPhotoInfo.password, localPhotoInfo.password.c_str(), len); TakePhotoCb(0, localPhotoInfo, "", 0);
return false;
} }
// strcpy(netPhotoInfo.outputPath, path.c_str());
// strcpy(netPhotoInfo.interface, "eth0"); // strcpy(netPhotoInfo.interface, "eth0");
localPhotoInfo.photoTime = time(NULL); localPhotoInfo.photoTime = time(NULL);
std::string tmpFile = m_appPath + (APP_PATH_TMP DIR_SEP_STR) + std::to_string(localPhotoInfo.photoId) + ".mp4"; std::string tmpFile = m_appPath + (APP_PATH_TMP DIR_SEP_STR) + std::to_string(localPhotoInfo.photoId) + ".mp4";
// RTSPToMP4 dumper(netPhotoInfo.url, tmpFile.c_str(), localPhotoInfo.duration * 1000); // RTSPToMP4 dumper(netPhotoInfo.url, tmpFile.c_str(), localPhotoInfo.duration * 1000);
// dumper.start(); // dumper.start();
dumpRtspToMp4(netPhotoInfo.url, tmpFile.c_str(), localPhotoInfo.duration * 1000); dumpRtspToMp4(streamingUrl.c_str(), tmpFile.c_str(), localPhotoInfo.duration * 1000, GetEthnetHandle());
ethernetPowerCtrl.reset(); ethernetPowerCtrl.reset();
XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power OFF"); XYLOG(XYLOG_SEVERITY_DEBUG, "Ethernet Power OFF");
@ -1820,7 +1798,7 @@ bool CPhoneDevice::TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
{ {
TakePhotoCb(0, localPhotoInfo, "", 0); TakePhotoCb(0, localPhotoInfo, "", 0);
XYLOG(XYLOG_SEVERITY_ERROR, "Failed to TP on NET Camera CH=%u PR=%X PHOTOID=%u URL=http://%s%s", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset, XYLOG(XYLOG_SEVERITY_ERROR, "Failed to TP on NET Camera CH=%u PR=%X PHOTOID=%u URL=http://%s%s", (uint32_t)localPhotoInfo.channel, (uint32_t)localPhotoInfo.preset,
localPhotoInfo.photoId, netPhotoInfo.ip, netPhotoInfo.url); localPhotoInfo.photoId, ip, streamingUrl.c_str());
} }
// Notify to take next photo // Notify to take next photo
// TakePhotoCb(1, localPhotoInfo, "", takingTime); // TakePhotoCb(1, localPhotoInfo, "", takingTime);
@ -1832,8 +1810,92 @@ bool CPhoneDevice::TakeVideoWithNetCamera(IDevice::PHOTO_INFO& localPhotoInfo, c
return true; return true;
} }
bool CPhoneDevice::StartPushStreaming(IDevice::PHOTO_INFO& localPhotoInfo, const std::string& url, std::vector<IDevice::OSD_INFO>& osds, std::shared_ptr<PowerControl> powerCtrlPtr) bool CPhoneDevice::StartPushStreaming(IDevice::PHOTO_INFO& photoInfo, const std::string& url, std::vector<IDevice::OSD_INFO>& osds, std::shared_ptr<PowerControl> powerCtrlPtr)
{
#if 0
if (photoInfo.mediaType == XY_MEDIA_TYPE_STREAM)
{
std::map<uint8_t, std::shared_ptr<Streaming> >::iterator it = m_streamings.find(photoInfo.channel);
if (it != m_streamings.end())
{
it->second->stop();
it->second.reset();
m_streamings.erase(it);
}
NET_PHOTO_INFO netPhotoInfo = { 0, 0 };
if (photoInfo.vendor == 1)
{
// Hai Kang
netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST;
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/ISAPI/Streaming/channels/1/picture?");
}
else if (photoInfo.vendor == 2)
{
// Hang Yu
strcpy(netPhotoInfo.url, "/cgi-bin/snapshot.cgi");
}
else if (photoInfo.vendor == 3)
{
// Yu Shi
netPhotoInfo.authType = HTTP_AUTH_TYPE_DIGEST;
int streamSid = 0; // should put into config
// rtsp://192.168.0.13:554/media/video1
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/media/video%u", (uint32_t)photoInfo.cameraId);
// strcpy(netPhotoInfo.url, "rtsp://192.168.50.224/live/0");
}
else if (photoInfo.vendor == 5)
{
// Hang Yu - New
netPhotoInfo.authType = HTTP_AUTH_TYPE_BASIC;
// http://192.168.1.46/Snapshot/%u/RemoteImageCapture?ImageFormat=2&HorizontalPixel=1920&VerticalPixel=1080
// http://192.168.1.101/Snapshot/1/2/RemoteImageCaptureV2?ImageFormat=jpg
// http://192.168.1.101/Snapshot/1/1/RemoteImageCaptureV2?ImageFormat=jpg
snprintf(netPhotoInfo.url, sizeof(netPhotoInfo.url), "/Snapshot/%u/1/RemoteImageCaptureV2?ImageFormat=jpg", (uint32_t)photoInfo.cameraId);
}
else
{ {
XYLOG(XYLOG_SEVERITY_ERROR, "Vendor(%u) not Supported CH=%u PR=%X PHOTOID=%u", (uint32_t)photoInfo.vendor, (uint32_t)photoInfo.channel, (unsigned int)photoInfo.preset, photoInfo.photoId);
TakePhotoCb(0, photoInfo, "", 0);
return false;
}
StreamForwarder* forwarder = new StreamForwarder();
m_streamings[photoInfo.channel] = std::shared_ptr<Streaming>((Streaming*)forwarder);
// Initialize with RTSP input and RTMP output
if (!forwarder->initialize(std::string(netPhotoInfo.url), url)) {
std::cerr << "Failed to initialize stream forwarder" << std::endl;
return -1;
}
// Optional: Set callback to process video frames
#if 0
forwarder->setFrameCallback([](uint8_t* data, int linesize, int width, int height) {
// Process frame data here
// Example: Add OSD overlay
});
#endif
// Start forwarding
forwarder->start();
// Wait for user input to stop
// std::cout << "Press Enter to stop streaming..." << std::endl;
// std::cin.get();
// forwarder.stop();
}
else if (photoInfo.mediaType == XY_MEDIA_TYPE_STREAM_OFF)
{
auto it = m_streamings.find(photoInfo.channel);
if (it != m_streamings.end())
{
it->second->stop();
it->second.reset();
m_streamings.erase(it);
}
}
#endif
return true; return true;
} }
@ -2037,7 +2099,7 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
std::this_thread::sleep_for(std::chrono::seconds(5)); std::this_thread::sleep_for(std::chrono::seconds(5));
} }
CameraPhotoCmd(ts, localPhotoInfo.channel, 0, localPhotoInfo.resolution, localPhotoInfo.preset, param.serfile, param.baud, param.addr); CameraPhotoCmd(ts, localPhotoInfo.channel, TAKE_PHOTO, localPhotoInfo.resolution, localPhotoInfo.preset, param.serfile, param.baud, param.addr);
XYLOG(XYLOG_SEVERITY_INFO, "Taking photo over"); XYLOG(XYLOG_SEVERITY_INFO, "Taking photo over");
if(localPhotoInfo.scheduleTime == 0) { if(localPhotoInfo.scheduleTime == 0) {
@ -4097,6 +4159,7 @@ void CPhoneDevice::UpdateSignalLevel(int signalLevel)
{ {
m_signalLevel = signalLevel; m_signalLevel = signalLevel;
m_signalLevelUpdateTime = time(NULL); m_signalLevelUpdateTime = time(NULL);
XYLOG(XYLOG_SEVERITY_DEBUG, "Signal Level Updated: %d", signalLevel);
} }
void CPhoneDevice::UpdateSimcard(const std::string& simcard) void CPhoneDevice::UpdateSimcard(const std::string& simcard)
@ -4957,3 +5020,24 @@ void CPhoneDevice::SetStaticIp()
XYLOG(XYLOG_SEVERITY_WARNING, "No Static IP Confg"); XYLOG(XYLOG_SEVERITY_WARNING, "No Static IP Confg");
} }
} }
VendorCtrl* CPhoneDevice::MakeVendorCtrl(int vendor, uint8_t channel, const std::string& ip, const std::string& userName, const std::string& password, net_handle_t netHandle)
{
VendorCtrl* vendorCtrl = NULL;
switch (vendor)
{
case 1:
// Hai Kang
break;
case 2:
break;
case 3:
// Yu Shi
vendorCtrl = new YuShiCtrl(ip, userName, password, channel, netHandle);
break;
case 5:
// Hang Yu - New
vendorCtrl = new HangYuCtrl(ip, userName, password, channel, netHandle);
}
return vendorCtrl;
}

@ -154,6 +154,8 @@ void MatToBitmap(JNIEnv *env, cv::Mat& mat, jobject& bitmap) {
#endif #endif
class PowerControl; class PowerControl;
class VendorCtrl;
class Streaming;
class CPhoneDevice : public IDevice class CPhoneDevice : public IDevice
{ {
@ -231,6 +233,8 @@ public:
virtual uint64_t RequestWakelock(uint64_t timeout); virtual uint64_t RequestWakelock(uint64_t timeout);
virtual bool ReleaseWakelock(uint64_t wakelock); virtual bool ReleaseWakelock(uint64_t wakelock);
virtual std::string GetVersion() const;
virtual int GetWData(WEATHER_INFO *weatherInfo, D_SENSOR_PARAM *sensorParam); virtual int GetWData(WEATHER_INFO *weatherInfo, D_SENSOR_PARAM *sensorParam);
virtual int GetIceData(ICE_INFO *iceInfo, ICE_TAIL *icetail, D_SENSOR_PARAM *sensorParam); virtual int GetIceData(ICE_INFO *iceInfo, ICE_TAIL *icetail, D_SENSOR_PARAM *sensorParam);
virtual bool OpenSensors(int sensortype); virtual bool OpenSensors(int sensortype);
@ -264,10 +268,12 @@ public:
net_handle_t GetEthnetHandle() const; net_handle_t GetEthnetHandle() const;
VendorCtrl* MakeVendorCtrl(int vendor, uint8_t channel, const std::string& ip, const std::string& userName, const std::string& password, net_handle_t netHandle);
protected: protected:
std::string GetFileName() const; std::string GetFileName() const;
std::string GetVersion() const;
bool SendBroadcastMessage(std::string action, int value); bool SendBroadcastMessage(std::string action, int value);
// bool MatchCaptureSizeRequest(ACameraManager *cameraManager, const char *selectedCameraId, unsigned int width, unsigned int height, uint32_t cameraOrientation_, // bool MatchCaptureSizeRequest(ACameraManager *cameraManager, const char *selectedCameraId, unsigned int width, unsigned int height, uint32_t cameraOrientation_,
@ -420,6 +426,8 @@ protected:
std::atomic<bool> m_collecting; std::atomic<bool> m_collecting;
unsigned long long localDelayTime; unsigned long long localDelayTime;
std::map<uint8_t, std::shared_ptr<Streaming> > m_streamings;
}; };

@ -106,7 +106,7 @@
#define D_OPEN_MODULE_POWER 0x0009000C /* 打开机芯电源(1 有效)*/ #define D_OPEN_MODULE_POWER 0x0009000C /* 打开机芯电源(1 有效)*/
/* 摄像机下发命令宏定义*/ /* 摄像机下发命令宏定义*/
#define TAKE_PHOTO 0 /* 拍照*/ #define TAKE_PHOTO 20000 /* 拍照*/
#define SET_BAUD 10000 /* 设置球机波特率*/ #define SET_BAUD 10000 /* 设置球机波特率*/
#define STOP_CMD 10005 /* 取消或停止指令*/ #define STOP_CMD 10005 /* 取消或停止指令*/
#define AUTO_SCAN 10006 /* 自动扫描功能控制(1/0 打开/关闭该功能)*/ #define AUTO_SCAN 10006 /* 自动扫描功能控制(1/0 打开/关闭该功能)*/

@ -6,6 +6,7 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <android/log.h> #include <android/log.h>
#include <errno.h>
extern "C" { extern "C" {
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
@ -21,15 +22,17 @@ extern "C" {
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration) void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle)
{ {
AVFormatContext* inputFormatContext = nullptr; AVFormatContext* inputFormatContext = nullptr;
AVFormatContext* outputFormatContext = nullptr; AVFormatContext* outputFormatContext = nullptr;
AVPacket packet; AVPacket packet;
AVDictionary *options = NULL;
av_register_all(); av_register_all();
avformat_network_init(); avformat_network_init();
// Open input RTMP stream // Open input RTMP stream
if (avformat_open_input(&inputFormatContext, rtmpUrl, nullptr, nullptr) != 0) { if (avformat_open_input(&inputFormatContext, rtmpUrl, nullptr, nullptr) != 0) {
fprintf(stderr, "Could not open input file '%s'\n", rtmpUrl); fprintf(stderr, "Could not open input file '%s'\n", rtmpUrl);
@ -126,28 +129,61 @@ void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duratio
} }
void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration) void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle)
{ {
AVFormatContext* inputFormatContext = nullptr; AVFormatContext* inputFormatContext = nullptr;
AVFormatContext* outputFormatContext = nullptr; AVFormatContext* outputFormatContext = nullptr;
AVPacket packet; AVPacket packet;
AVDictionary *options = NULL;
int res = 0;
av_register_all(); av_register_all();
avformat_network_init(); avformat_network_init();
// Set RTSP transport protocol option before opening
av_dict_set(&options, "rtsp_transport", "tcp", 0);
// Set custom socket options via protocol whitelist and options
inputFormatContext->protocol_whitelist = av_strdup("file,udp,rtp,tcp,rtsp");
// Open input RTSP stream // Open input RTSP stream
if (avformat_open_input(&inputFormatContext, rtspUrl, nullptr, nullptr) != 0) { if (avformat_open_input(&inputFormatContext, rtspUrl, nullptr, nullptr) != 0) {
fprintf(stderr, "Could not open input file '%s'\n", rtspUrl); // fprintf(stderr, "Could not open input file '%s'\n", rtspUrl);
return; return;
} }
// Retrieve input stream information // Retrieve input stream information
if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) { if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) {
fprintf(stderr, "Could not find stream information\n"); // fprintf(stderr, "Could not find stream information\n");
avformat_close_input(&inputFormatContext); avformat_close_input(&inputFormatContext);
return; return;
} }
// Get socket file descriptor
if (NETWORK_UNSPECIFIED != netHandle)
{
int fd = -1;
if (inputFormatContext->pb) {
AVIOContext *io_ctx = inputFormatContext->pb;
// const char *url = io_ctx->filename;
// You can access socket options using av_opt API
res = av_opt_get_int(io_ctx, "fd", AV_OPT_SEARCH_CHILDREN, (int64_t*)&fd);
if (res >= 0 && fd >= 0) {
// printf("Socket file descriptor: %d\n", fd);
int res = android_setsocknetwork(netHandle, fd);
if (res == -1)
{
int errcode = errno;
// printf("android_setsocknetwork errno=%d", errcode);
// XYLOG(XYLOG_SEVERITY_ERROR,"setsocknetwork -1, errcode=%d",errcode);
}
}
}
}
// Open output MP4 file // Open output MP4 file
if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) { if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) {
fprintf(stderr, "Could not create output context\n"); fprintf(stderr, "Could not create output context\n");

@ -6,10 +6,11 @@
#define MICROPHOTO_RTSPRECORDER_H #define MICROPHOTO_RTSPRECORDER_H
#include <string> #include <string>
#include <android/multinetwork.h>
// void dumpRtspToMp4(const std::string &rtspUrl, const std::string &outputPath, uint32_t durationInMs); // void dumpRtspToMp4(const std::string &rtspUrl, const std::string &outputPath, uint32_t durationInMs);
void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration); void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle);
void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration); void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle);
class RTSPRecorder { class RTSPRecorder {

@ -0,0 +1,159 @@
//
// Created by Matthew on 2025/3/11.
//
#include "Streaming.h"
#include <android/api-level.h>
#include <android/log.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#if 0
StreamForwarder::~StreamForwarder() {
stop();
if (inputCtx) {
avformat_close_input(&inputCtx);
}
if (outputCtx) {
if (outputCtx->pb) {
avio_closep(&outputCtx->pb);
}
avformat_free_context(outputCtx);
}
}
bool StreamForwarder::initialize(const std::string& inputUrl, const std::string& outputUrl) {
if (!openInput(inputUrl)) {
return false;
}
if (!openOutput(outputUrl)) {
return false;
}
return true;
}
bool StreamForwarder::openInput(const std::string& inputUrl) {
inputCtx = avformat_alloc_context();
if (!inputCtx) {
return false;
}
if (avformat_open_input(&inputCtx, inputUrl.c_str(), nullptr, nullptr) < 0) {
return false;
}
if (avformat_find_stream_info(inputCtx, nullptr) < 0) {
return false;
}
return true;
}
bool StreamForwarder::openOutput(const std::string& outputUrl) {
int ret = avformat_alloc_output_context2(&outputCtx, nullptr, "flv", outputUrl.c_str());
if (ret < 0) {
return false;
}
// Copy streams from input to output
for (unsigned int i = 0; i < inputCtx->nb_streams; i++) {
AVStream* inStream = inputCtx->streams[i];
AVStream* outStream = avformat_new_stream(outputCtx, inStream->codec->codec);
if (!outStream) {
return false;
}
ret = avcodec_copy_context(outStream->codec, inStream->codec);
if (ret < 0) {
return false;
}
}
// Open output file
if (!(outputCtx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&outputCtx->pb, outputUrl.c_str(), AVIO_FLAG_WRITE);
if (ret < 0) {
return false;
}
}
// Write header
ret = avformat_write_header(outputCtx, nullptr);
if (ret < 0) {
return false;
}
return true;
}
void StreamForwarder::setFrameCallback(std::function<void(uint8_t*, int, int, int)> callback) {
frameCallback = callback;
}
void StreamForwarder::start() {
isRunning = true;
forwardPackets();
}
void StreamForwarder::stop() {
isRunning = false;
}
void StreamForwarder::forwardPackets() {
AVPacket packet;
AVFrame* frame = av_frame_alloc();
while (isRunning) {
if (av_read_frame(inputCtx, &packet) < 0) {
break;
}
// Process video frames if callback is set
if (frameCallback && packet.stream_index == 0) { // Assuming video is stream 0
AVCodecContext* codecCtx = inputCtx->streams[packet.stream_index]->codec;
int ret = avcodec_send_packet(codecCtx, &packet);
if (ret < 0) {
continue;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codecCtx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
goto end;
}
processFrame(frame);
}
}
// Forward packet
av_packet_rescale_ts(&packet,
inputCtx->streams[packet.stream_index]->time_base,
outputCtx->streams[packet.stream_index]->time_base);
int ret = av_interleaved_write_frame(outputCtx, &packet);
if (ret < 0) {
break;
}
av_packet_unref(&packet);
}
end:
av_frame_free(&frame);
av_write_trailer(outputCtx);
}
void StreamForwarder::processFrame(AVFrame* frame) {
if (frameCallback) {
frameCallback(frame->data[0], frame->linesize[0],
frame->width, frame->height);
}
}
#endif

@ -0,0 +1,50 @@
//
// Created by Matthew on 2025/3/11.
//
#ifndef MICROPHOTO_STREAMING_H
#define MICROPHOTO_STREAMING_H
#include <string>
#include <memory>
#include <android/multinetwork.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
}
class Streaming
{
public:
virtual ~Streaming() {}
virtual void start() {}
virtual void stop() {}
};
#if 0
class StreamForwarder : public Streaming
{
private:
AVFormatContext* inputCtx = nullptr;
AVFormatContext* outputCtx = nullptr;
bool isRunning = false;
public:
StreamForwarder() = default;
virtual ~StreamForwarder();
bool initialize(const std::string& inputUrl, const std::string& outputUrl);
virtual void start();
virtual void stop();
private:
bool openInput(const std::string& inputUrl);
bool openOutput(const std::string& outputUrl);
void forwardPackets();
};
#endif
#endif //MICROPHOTO_STREAMING_H

@ -0,0 +1,95 @@
//
// Created by Matthew on 2025/3/4.
//
#include "HangYuCtrl.h"
#include "netcamera.h"
#include "httpclient.h"
#include <cstring>
HangYuCtrl::~HangYuCtrl()
{
}
bool HangYuCtrl::SetOsd()
{
// /LAPI/V1.0/Channels/<ID>/Media/OSDs/Contents
}
void HangYuCtrl::EnableOsd(bool enable)
{
// return false;
}
std::string HangYuCtrl::GetStreamingUrl(uint8_t channel)
{
// /LAPI/V1.0/Channels/<ID>/Media/Video/Streams/<ID>/LiveStreamURL?TransType=<Tran
// sType>&TransProtocol=<TransProtocol>
char url[128] = { 0 };
snprintf(url, sizeof(url), "http://%s/Streams/%u/1/Transport", m_ip.c_str(), (uint32_t)channel);
std::vector<uint8_t> resData;
int res = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
if (res != 0 || resData.empty())
{
return "";
}
resData.push_back(0);
const char* start = strstr((const char*)&resData[0], "<RTSPURI>");
if (start == NULL)
{
return "";
}
start += 9;
const char* end = strstr(start, "</RTSPURI>");
if (end == NULL)
{
return "";
}
return std::string(start, end);
}
bool HangYuCtrl::UpdateTime(time_t ts)
{
// /LAPI/V1.0/System/Time
// <?xml version="1.0" encoding="utf-8"?>
//<Time>
//<DateTimeFormat>
//<!--req,string,YYYYMMDDWhhmmss,YYYYMMDDhhmmss,MMDDYYYYWhhmmss,MMD
// DYYYYhhmmss,DDMMYYYYWhhmmss,DDMMYYYYhhmmss-->
//</DateTimeFormat>
//<TimeFormat><!--req,xs:string,12hour,24hour--></TimeFormat>
//<SystemTime><!--req,xs:datetime,” 20040503T173008+08”--></SystemTime>
//<SyncNTPFlag><!--req,xs:string,"Sync,NoSync"--></SyncNTPFlag>
//</Time>
std::string reqData = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Time><SystemTime>"
+ FormatLocalDateTime("%d%02d%02dT%02d%02d%02d") + "+08</SystemTime></Time>";
std::string url = "http://" + m_ip + " /System/Time";
std::vector<uint8_t> resData;
int res = DoPutRequest(url.c_str(), HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, reqData.c_str(), resData);
if (res != 0)
{
return false;
}
return true;
}
bool HangYuCtrl::TakePhoto(std::vector<uint8_t>& img)
{
return false;
}
bool HangYuCtrl::TakeVideo(uint32_t duration, std::string path)
{
}

@ -0,0 +1,28 @@
//
// Created by Matthew on 2025/3/4.
//
#ifndef __MICROPHOTO_HANGYUCTRL_H__
#define __MICROPHOTO_HANGYUCTRL_H__
#include "VendorCtrl.h"
class HangYuCtrl : public VendorCtrl
{
public:
using VendorCtrl::VendorCtrl;
virtual ~HangYuCtrl();
virtual bool SetOsd();
virtual void EnableOsd(bool enable);
virtual std::string GetStreamingUrl(uint8_t channel);
virtual bool UpdateTime(time_t ts);
virtual bool TakePhoto(std::vector<uint8_t>& img);
virtual bool TakeVideo(uint32_t duration, std::string path);
private:
};
#endif //__MICROPHOTO_HANGYUCTRL_H__

@ -3,8 +3,8 @@
// //
#include "VendorCtrl.h" #include "VendorCtrl.h"
VendorCtrl::VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password) : VendorCtrl::VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password, uint8_t channel, net_handle_t netHandle) :
m_ip(ip), m_userName(userName), m_password(password), m_channel(channel) m_ip(ip), m_userName(userName), m_password(password), m_channel(channel), m_netHandle(netHandle)
{ {
} }
std::string VendorCtrl::CvtJSONToString(const Json::Value& data) std::string VendorCtrl::CvtJSONToString(const Json::Value& data)

@ -7,17 +7,19 @@
#include <string> #include <string>
#include <json/json.h> #include <json/json.h>
#include <android/multinetwork.h>
class VendorCtrl { class VendorCtrl {
public: public:
VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password, uint8_t channel); VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password, uint8_t channel, net_handle_t netHandle);
virtual ~VendorCtrl() = 0; virtual ~VendorCtrl() {}
virtual bool SetOsd() = 0; virtual bool SetOsd() = 0;
virtual void EnableOsd(bool enable) = 0; virtual void EnableOsd(bool enable) = 0;
virtual std::string GetStreamingUrl(uint8_t channel) = 0; virtual std::string GetStreamingUrl(uint8_t channel) = 0;
virtual bool UpdateTime(time_t ts) = 0; virtual bool UpdateTime(time_t ts) = 0;
virtual bool TakePhoto(std::vector<uint8_t>& img) = 0; virtual bool TakePhoto(std::vector<uint8_t>& img) = 0;
virtual bool TakeVideo(uint32_t duration, std::string path) = 0;
protected: protected:
@ -28,6 +30,7 @@ protected:
std::string m_userName; std::string m_userName;
std::string m_password; std::string m_password;
uint8_t m_channel; uint8_t m_channel;
net_handle_t m_netHandle;
}; };

@ -17,10 +17,10 @@ bool YuShiCtrl::SetOsd()
void YuShiCtrl::EnableOsd(bool enable) void YuShiCtrl::EnableOsd(bool enable)
{ {
return false; // return false;
} }
std::string GetStreamingUrl(uint8_t channel) std::string YuShiCtrl::GetStreamingUrl(uint8_t channel)
{ {
// /LAPI/V1.0/Channels/<ID>/Media/Video/Streams/<ID>/LiveStreamURL?TransType=<Tran // /LAPI/V1.0/Channels/<ID>/Media/Video/Streams/<ID>/LiveStreamURL?TransType=<Tran
// sType>&TransProtocol=<TransProtocol> // sType>&TransProtocol=<TransProtocol>
@ -29,12 +29,12 @@ std::string GetStreamingUrl(uint8_t channel)
bool YuShiCtrl::UpdateTime(time_t ts) bool YuShiCtrl::UpdateTime(time_t ts)
{ {
/LAPI/V1.0/System/Time // /LAPI/V1.0/System/Time
Json::Value jsonData(Json::objectValue); Json::Value jsonData(Json::objectValue);
jsonData["TimeZone"] = "GMT+08:00"; jsonData["TimeZone"] = "GMT+08:00";
jsonData["DeviceTime"] = ts; jsonData["DeviceTime"] = (int64_t)ts;
jsonData["DateFormat"] = 0; // YYYY-MM-DD jsonData["DateFormat"] = 0; // YYYY-MM-DD
jsonData["HourFormat"] = 1; // 24H jsonData["HourFormat"] = 1; // 24H
@ -45,3 +45,8 @@ bool YuShiCtrl::TakePhoto(std::vector<uint8_t>& img)
{ {
return false; return false;
} }
bool YuShiCtrl::TakeVideo(uint32_t duration, std::string path)
{
}

@ -18,6 +18,7 @@ public:
virtual std::string GetStreamingUrl(uint8_t channel); virtual std::string GetStreamingUrl(uint8_t channel);
virtual bool UpdateTime(time_t ts); virtual bool UpdateTime(time_t ts);
virtual bool TakePhoto(std::vector<uint8_t>& img); virtual bool TakePhoto(std::vector<uint8_t>& img);
virtual bool TakeVideo(uint32_t duration, std::string path);
private: private:

@ -119,7 +119,7 @@ int DoGetRequest(const char* url, int authType, const char* userName, const char
return ((0 == nRet) && (responseCode == 200)) ? 0 : 1; return ((0 == nRet) && (responseCode == 200)) ? 0 : 1;
} }
int DoPutRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, const char* contents, char* data) int DoPutRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, const char* contents, std::vector<uint8_t>& data)
{ {
std::string auth; std::string auth;
@ -239,10 +239,11 @@ int UniviewResolutionSet(const NET_PHOTO_INFO& photoInfo, int channel, unsigned
Json::StreamWriterBuilder writer; Json::StreamWriterBuilder writer;
std::string sendbuf = Json::writeString(writer, outdata); std::string sendbuf = Json::writeString(writer, outdata);
char respContent[1024]; std::vector<uint8_t> respContent;
DoPutRequest(path.c_str(), photoInfo.authType, photoInfo.userName, photoInfo.password, photoInfo.netHandle, sendbuf.c_str(), respContent); DoPutRequest(path.c_str(), photoInfo.authType, photoInfo.userName, photoInfo.password, photoInfo.netHandle, sendbuf.c_str(), respContent);
XYLOG(XYLOG_SEVERITY_DEBUG, "Sendlen= %zu, respContent=%s", sendbuf.size(), respContent); // respContent.push_back(0);
// XYLOG(XYLOG_SEVERITY_DEBUG, "Sendlen= %zu, respContent=%s", sendbuf.size(), (const char*)&respContent[0]);
return 0; return 0;
} }

@ -19,6 +19,6 @@
bool setIPAddress(const char *if_name, const char *ip_addr, const char *net_mask, const char *gateway_addr); bool setIPAddress(const char *if_name, const char *ip_addr, const char *net_mask, const char *gateway_addr);
int DoGetRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, std::vector<uint8_t>& data); int DoGetRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, std::vector<uint8_t>& data);
int DoPutRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, const char* contents, char* data); int DoPutRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, const char* contents, std::vector<uint8_t>& data);
#endif // __HTTP_CLIENT__ #endif // __HTTP_CLIENT__

@ -72,7 +72,18 @@ public class MainActivity extends AppCompatActivity {
Date date = new Date(BuildConfig.BUILD_TIMESTAMP); Date date = new Date(BuildConfig.BUILD_TIMESTAMP);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String caption = actionBar.getTitle().toString() + " v" + MicroPhotoContext.getVersionName(getApplicationContext()) + " " + sdf.format(date); String caption = "MP";
switch (MicroPhotoService.getCustomAppId()) {
case 1:
caption = "RP";
break;
case 2:
caption = "N938";
break;
default:
break;
}
caption += " v" + MicroPhotoContext.getVersionName(getApplicationContext()) + " " + sdf.format(date);
sdf = new SimpleDateFormat("MM-dd HH:mm"); sdf = new SimpleDateFormat("MM-dd HH:mm");
caption += " / " + sdf.format(new Date()); caption += " / " + sdf.format(new Date());
actionBar.setTitle(caption); actionBar.setTitle(caption);
@ -629,4 +640,6 @@ public class MainActivity extends AppCompatActivity {
} }
} }

@ -56,6 +56,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import android.widget.Toast; import android.widget.Toast;
@ -162,8 +163,6 @@ public class MicroPhotoService extends Service {
private ServiceHandler mHander = null; private ServiceHandler mHander = null;
private Messenger mMessenger = null; private Messenger mMessenger = null;
private static AtomicInteger mPendingIntentFeed = new AtomicInteger();
private String mModelName = null; private String mModelName = null;
public static boolean isRunning = false; public static boolean isRunning = false;
@ -531,8 +530,7 @@ public class MicroPhotoService extends Service {
} }
// Register Next Photo Timer // Register Next Photo Timer
Date date = new Date(); long startTime = (ts == 0) ? (((new Date()).getTime() + 999) / 1000 + 1) : (ts + 1); // Add one second
long startTime = (date.getTime() + 999) / 1000 + 1; // Add one second
mService.updateCaptureSchedule(startTime); mService.updateCaptureSchedule(startTime);
} else if (TextUtils.equals(ACTION_HEARTBEAT_MANUALLY, action)) { } else if (TextUtils.equals(ACTION_HEARTBEAT_MANUALLY, action)) {
Log.i(TAG, "HB Timer Fired ACTION=" + action); Log.i(TAG, "HB Timer Fired ACTION=" + action);
@ -1240,7 +1238,9 @@ public class MicroPhotoService extends Service {
new Runnable() { new Runnable() {
public void run() { public void run() {
// Log.d(TAG, "Bluetooth Low Energy device is connected!!"); // Log.d(TAG, "Bluetooth Low Energy device is connected!!");
Toast.makeText(getApplicationContext(), "MP Connected!", Toast.LENGTH_SHORT).show(); Toast toast = Toast.makeText(getApplicationContext(), "MP Connected!", Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP, 0, 0);
toast.show();
mStateService = STATE_SERVICE.CONNECTED; mStateService = STATE_SERVICE.CONNECTED;
startForeground(NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification()); startForeground(NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());
} }
@ -1527,7 +1527,7 @@ public class MicroPhotoService extends Service {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_GPS_TIMEOUT); intent.setAction(ACTION_GPS_TIMEOUT);
mPreviousGpsTimer = PendingIntent.getBroadcast(this, mPendingIntentFeed.getAndIncrement(), intent, 0); mPreviousGpsTimer = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE_GPS, intent, 0);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + mGpsTimeout, mPreviousGpsTimer); alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + mGpsTimeout, mPreviousGpsTimer);
} catch (Exception ex) { } catch (Exception ex) {
@ -1683,6 +1683,8 @@ cellSignalStrengthGsm.getDbm();
public static native long requestPowerControl(int type); public static native long requestPowerControl(int type);
public static native boolean releasePowerControl(long powerControlHandle); public static native boolean releasePowerControl(long powerControlHandle);
public static native int getCustomAppId();
////////////////////////GPS//////////////////// ////////////////////////GPS////////////////////
// private static final String GPS_LOCATION_NAME = android.location.LocationManager.GPS_PROVIDER; // private static final String GPS_LOCATION_NAME = android.location.LocationManager.GPS_PROVIDER;
private LocationManager mLocationManager; private LocationManager mLocationManager;

@ -6,6 +6,7 @@ import java.io.BufferedInputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -92,8 +93,22 @@ public class FileUploader {
} }
request.writeBytes(this.CRLF); request.writeBytes(this.CRLF);
byte[] bytes = Files.readAllBytes(uploadFile.toPath()); FileInputStream fis = null;
request.write(bytes); try {
fis = new FileInputStream(uploadFile);
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int length = -1;
while ((length = fis.read(buffer)) != -1) {
request.write(buffer, 0, length);
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
FilesUtils.closeFriendly(fis);
}
// byte[] bytes = Files.readAllBytes(uploadFile.toPath());
// request.write(bytes);
} }
/** /**

@ -4,7 +4,7 @@ plugins {
def AppMajorVersion = 1 def AppMajorVersion = 1
def AppMinorVersion = 1 def AppMinorVersion = 1
def AppBuildNumber = 8 def AppBuildNumber = 9
def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber
def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber

Loading…
Cancel
Save