mirror of
https://github.com/gtxaspec/wz_mini_hacks.git
synced 2024-11-22 13:37:19 +00:00
rtsp fixes
This commit is contained in:
parent
cea324226e
commit
26af3aa7bc
13
README.md
13
README.md
@ -33,6 +33,7 @@ Using this project can potentially expose your device to the open internet depen
|
||||
* Tethering to android phones via RNDIS
|
||||
* USB Mass storage enabled, mount USB SSD/HDD/flash drives
|
||||
* CIFS Supported
|
||||
* Play .WAV files using "aplay <file> <vol>" command
|
||||
|
||||
* Inspired by HclX and WyzeHacks! Bless you for all your work! You are the master!
|
||||
|
||||
@ -40,7 +41,6 @@ Using this project can potentially expose your device to the open internet depen
|
||||
* ???
|
||||
|
||||
## How you can help!
|
||||
* RTSP Server: Live view in the app doesn't work when set to "HD" or "SD", need to check libcallback sources to see why this happens, if you can help with this, check it out.
|
||||
* Vertical Tilt on the PANv2 doesn't work properly. Only does this on the modified kernel. Need investigation why this happens.
|
||||
|
||||
## Prerequisites
|
||||
@ -52,11 +52,7 @@ Using this project can potentially expose your device to the open internet depen
|
||||
## What Works / What Doesn't Work
|
||||
* Everything works except:
|
||||
|
||||
1. v3/Pan V2: RTSP support is experimental and has several drawbacks:
|
||||
- Live view in the app only works at 360p
|
||||
- Recording to microsd card doesn't work properly
|
||||
- RTSP playback only works properly via VLC
|
||||
2. PAN v2:
|
||||
1. PAN v2:
|
||||
- Tilt (Vertical) only works at motor speed 9
|
||||
|
||||
## Setup
|
||||
@ -163,8 +159,6 @@ ENABLE_CIFS="false"
|
||||
```
|
||||
|
||||
---
|
||||
__WARNING: RTSP support is experimental and I consider it to be broken. Use it only if you know what you are doing! The outdated stock RTSP firmware works much better at the moment.__
|
||||
|
||||
To enable RTSP streaming, change the following lines, you can choose to enable or disable audio. Set your login credentials here, you can also change the port the server listens on.
|
||||
|
||||
```
|
||||
@ -178,12 +172,11 @@ the stream will be located at ```rtsp://login:password@IP_ADDRESS:8554/unicast``
|
||||
|
||||
Note: If you don't set the password, then the password will be the unique MAC address of the camera, in all uppercase, including the colons... for example:. AA:BB:CC:00:11:22. It's typically printed on the camera. VLC seems to work fine for playback, ffmpeg and others have severe artifacts in the stream during playback. Huge credit to @mnakada for his libcallback library: [https://github.com/mnakada/atomcam_tools](https://github.com/mnakada/atomcam_tools)
|
||||
|
||||
__WARNING__: If using the wyze app to view the live stream, viewing in "HD" or "SD" will not work. Select 360p to view the live stram in the app. Recording to micro sd is also broken.
|
||||
|
||||
---
|
||||
|
||||
## Latest Updates
|
||||
|
||||
* 05-07-22: RTSP Server fixed, ported latest full libcallback from @mnakada with modifications.
|
||||
* 05-01-22: Removed dropbearmulti, replaced with individual binaries. dropbear dbclient dropbearkey dropbearconvert scp now included.
|
||||
* 04-30-22: Recompiled uClibc with LD_DEBUG enabled. Enable in v3_post.sh, for debugging.
|
||||
* 04-30-22: Move built-in kernel stuff to modules, usb_direct kernel no longer needed, modules now included. Added usb-storage support for usb hdd/ssd/flash drive, cifs support, and rndis support for tethering camera directly to a mobile device.
|
||||
|
2
SD_ROOT/wz_mini/bin/cmd
Executable file
2
SD_ROOT/wz_mini/bin/cmd
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
echo "$*" | /opt/wz_mini/bin/busybox nc localhost 4000
|
Binary file not shown.
@ -189,6 +189,8 @@ if [[ "$RTSP_ENABLED" == "true" ]]; then
|
||||
swap_enable
|
||||
mkdir /tmp/alsa
|
||||
cp /media/mmc/wz_mini/etc/alsa.conf /tmp/alsa
|
||||
/opt/wz_mini/bin/cmd video on
|
||||
/opt/wz_mini/bin/cmd audio on
|
||||
|
||||
if [[ "$RTSP_PASSWORD" = "" ]]; then
|
||||
RTSP_PASSWORD=$(cat /opt/wz_mini/tmp/wlan0_mac)
|
||||
|
@ -1,11 +0,0 @@
|
||||
# libcallback.so
|
||||
|
||||
CC = /openmiko/build/mips-gcc472-glibc216-64bit/bin/mips-linux-uclibc-gnu-gcc
|
||||
CFLAGS = -fPIC -std=gnu99 -shared -ldl -lm
|
||||
CC_SRCS = video_callback.c audio_callback.c
|
||||
TARGET = libcallback.so
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${CC_SRCS}
|
||||
${CC} ${CFLAGS} -o ${TARGET} ${CC_SRCS}
|
Binary file not shown.
11
libcallback_wz_mod/Makefile
Normal file
11
libcallback_wz_mod/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# libcallback.so
|
||||
|
||||
CC = /openmiko/build/mips-gcc472-glibc216-64bit/bin/mips-linux-uclibc-gnu-gcc
|
||||
CFLAGS = -fPIC -std=gnu99 -shared -ldl -ltinyalsa -lm -pthread
|
||||
CC_SRCS = video_callback.c audio_callback.c jpeg.c setlinebuf.c mmc_format.c curl.c freopen.c opendir.c remove.c motor.c command.c gmtime_r.c wait_motion.c irled.c audio_play.c
|
||||
TARGET = libcallback.so
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: ${CC_SRCS}
|
||||
${CC} ${CFLAGS} -o ${TARGET} ${CC_SRCS}
|
@ -17,7 +17,24 @@ typedef int (* framecb)(struct frames_st *);
|
||||
|
||||
static uint32_t (*real_local_sdk_audio_set_pcm_frame_callback)(int ch, void *callback);
|
||||
static void *audio_pcm_cb = NULL;
|
||||
static int AudioCaptureEnable = 1;
|
||||
static int AudioCaptureEnable = 0;
|
||||
|
||||
char *AudioCapture(int fd, char *tokenPtr) {
|
||||
|
||||
char *p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
if(!p) return AudioCaptureEnable ? "on" : "off";
|
||||
if(!strcmp(p, "on")) {
|
||||
AudioCaptureEnable = 1;
|
||||
fprintf(stderr, "[command] audio capute on\n", p);
|
||||
return "ok";
|
||||
}
|
||||
if(!strcmp(p, "off")) {
|
||||
AudioCaptureEnable = 0;
|
||||
fprintf(stderr, "[command] audio capute off\n", p);
|
||||
return "ok";
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
static uint32_t audio_pcm_capture(struct frames_st *frames) {
|
||||
|
107
libcallback_wz_mod/audio_play.c
Normal file
107
libcallback_wz_mod/audio_play.c
Normal file
@ -0,0 +1,107 @@
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern void local_sdk_speaker_set_pa_mode(int mode);
|
||||
extern void local_sdk_speaker_clean_buf_data();
|
||||
extern void local_sdk_speaker_set_volume(int volume);
|
||||
extern int local_sdk_speaker_feed_pcm_data(unsigned char *buf, int size);
|
||||
extern void local_sdk_speaker_finish_buf_data();
|
||||
extern void CommandResponse(int fd, const char *res);
|
||||
|
||||
static pthread_mutex_t AudioPlayMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int AudioPlayFd = -1;
|
||||
static char waveFile[256];
|
||||
static int Volume = 0;
|
||||
|
||||
int PlayPCM(char *file, int vol) {
|
||||
|
||||
static const int waveHeaderLength = 44;
|
||||
static const int bufLength = 640;
|
||||
unsigned char buf[bufLength];
|
||||
const unsigned char cmp[] = {
|
||||
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20,
|
||||
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x80, 0x3e, 0x00, 0x00,
|
||||
0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61
|
||||
};
|
||||
|
||||
fprintf(stderr, "[command] aplay: file:%s\n", file);
|
||||
FILE *fp = fopen(file, "rb");
|
||||
if(fp == NULL) {
|
||||
fprintf(stderr, "[command] aplay err: fopen %s failed!\n", file);
|
||||
return -1;
|
||||
} else {
|
||||
size_t size = fread(buf, 1, waveHeaderLength, fp);
|
||||
if(size != waveHeaderLength) {
|
||||
fprintf(stderr, "[command] aplay err: header size error\n");
|
||||
}
|
||||
buf[4] = buf[5] = buf[6] = buf[7] = 0;
|
||||
if(memcmp(buf, cmp, waveHeaderLength - 4)) {
|
||||
fprintf(stderr, "[command] aplay err: header error\n");
|
||||
}
|
||||
local_sdk_speaker_clean_buf_data();
|
||||
local_sdk_speaker_set_volume(vol);
|
||||
local_sdk_speaker_set_pa_mode(3);
|
||||
|
||||
while(!feof(fp)) {
|
||||
size = fread(buf, 1, bufLength, fp);
|
||||
if (size <= 0) break;
|
||||
while(local_sdk_speaker_feed_pcm_data(buf, size)) usleep(100 * 1000);
|
||||
}
|
||||
fclose(fp);
|
||||
usleep(2 * 1000 * 1000);
|
||||
local_sdk_speaker_finish_buf_data();
|
||||
local_sdk_speaker_set_volume(0);
|
||||
local_sdk_speaker_set_pa_mode(0);
|
||||
}
|
||||
fprintf(stderr, "[command] aplay: finish\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *AudioPlayThread() {
|
||||
|
||||
while(1) {
|
||||
pthread_mutex_lock(&AudioPlayMutex);
|
||||
if(AudioPlayFd >= 0) {
|
||||
int res = PlayPCM(waveFile, Volume);
|
||||
CommandResponse(AudioPlayFd, res ? "error" : "ok");
|
||||
}
|
||||
AudioPlayFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
char *AudioPlay(int fd, char *tokenPtr) {
|
||||
|
||||
if(AudioPlayFd >= 0) {
|
||||
fprintf(stderr, "[command] aplay err: Previous file is still playing. %d %d\n", AudioPlayFd, fd);
|
||||
return "error";
|
||||
}
|
||||
|
||||
char *p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
if(!p) {
|
||||
fprintf(stderr, "[command] aplay err: usage : aplay <wave file> [<volume>]\n");
|
||||
return "error";
|
||||
}
|
||||
strncpy(waveFile, p, 255);
|
||||
|
||||
p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
Volume = 40;
|
||||
if(p) Volume = atoi(p);
|
||||
|
||||
AudioPlayFd = fd;
|
||||
pthread_mutex_unlock(&AudioPlayMutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __attribute ((constructor)) AudioPlayInit(void) {
|
||||
|
||||
pthread_mutex_lock(&AudioPlayMutex);
|
||||
pthread_t thread;
|
||||
if(pthread_create(&thread, NULL, AudioPlayThread, NULL)) {
|
||||
fprintf(stderr, "pthread_create error\n");
|
||||
pthread_mutex_unlock(&AudioPlayMutex);
|
||||
return;
|
||||
}
|
||||
}
|
192
libcallback_wz_mod/command.c
Normal file
192
libcallback_wz_mod/command.c
Normal file
@ -0,0 +1,192 @@
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const unsigned short CommandPort = 4000;
|
||||
static int SelfPipe[2];
|
||||
|
||||
extern char *JpegCapture(int fd, char *tokenPtr);
|
||||
extern char *VideoCapture(int fd, char *tokenPtr);
|
||||
extern char *AudioCapture(int fd, char *tokenPtr);
|
||||
extern char *MotorMove(int fd, char *tokenPtr);
|
||||
extern char *WaitMotion(int fd, char *tokenPtr);
|
||||
extern char *IrLed(int fd, char *tokenPtr);
|
||||
extern char *AudioPlay(int fd, char *tokenPtr);
|
||||
|
||||
struct CommandTableSt {
|
||||
const char *cmd;
|
||||
char * (*func)(int, char *);
|
||||
};
|
||||
|
||||
struct CommandTableSt CommandTable[] = {
|
||||
{ "video", &VideoCapture },
|
||||
{ "audio", &AudioCapture },
|
||||
{ "jpeg", &JpegCapture },
|
||||
{ "move", &MotorMove },
|
||||
{ "waitMotion", &WaitMotion },
|
||||
{ "irled", &IrLed },
|
||||
{ "aplay", &AudioPlay },
|
||||
};
|
||||
|
||||
void CommandResponse(int fd, const char *res) {
|
||||
|
||||
unsigned char buf[256];
|
||||
buf[0] = strlen(res) + 1;
|
||||
buf[1] = fd;
|
||||
strncpy((char *)buf + 2, res, 253);
|
||||
write(SelfPipe[1], &buf, buf[0] + 2);
|
||||
}
|
||||
|
||||
static void *CommandThread(void *arg) {
|
||||
|
||||
static const int MaxConnect = 255;
|
||||
int maxFd = 0;
|
||||
fd_set targetFd;
|
||||
|
||||
int listenSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(listenSocket < 0) {
|
||||
fprintf(stderr, "socket : %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
int sock_optval = 1;
|
||||
if(setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR,
|
||||
&sock_optval, sizeof(sock_optval)) == -1) {
|
||||
fprintf(stderr, "setsockopt : %s\n", strerror(errno));
|
||||
close(listenSocket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sockaddr_in saddr;
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(CommandPort);
|
||||
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
if(bind(listenSocket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
|
||||
fprintf(stderr, "bind : %s\n", strerror(errno));
|
||||
close(listenSocket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(listen(listenSocket, MaxConnect) == -1) {
|
||||
fprintf(stderr, "listen : %s\n", strerror(errno));
|
||||
close(listenSocket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FD_ZERO(&targetFd);
|
||||
FD_SET(listenSocket, &targetFd);
|
||||
maxFd = listenSocket;
|
||||
FD_SET(SelfPipe[0], &targetFd);
|
||||
maxFd = (SelfPipe[0] > maxFd) ? SelfPipe[0] : maxFd;
|
||||
if(maxFd >= MaxConnect) maxFd = MaxConnect - 1;
|
||||
|
||||
while(1) {
|
||||
fd_set checkFDs;
|
||||
memcpy(&checkFDs, &targetFd, sizeof(targetFd));
|
||||
if(select(maxFd + 1, &checkFDs, NULL, NULL, NULL) == -1) {
|
||||
fprintf(stderr, "select error : %s\n", strerror(errno));
|
||||
} else {
|
||||
for(int fd = maxFd; fd >= 0; fd--) {
|
||||
if(FD_ISSET(fd, &checkFDs)) {
|
||||
if(fd == SelfPipe[0]) {
|
||||
while(1) {
|
||||
unsigned char buf[256];
|
||||
int length = read(SelfPipe[0], buf, 2);
|
||||
if(length <= 1) break;
|
||||
int resSize = buf[0];
|
||||
int resFd = buf[1];
|
||||
length = read(SelfPipe[0], buf, resSize);
|
||||
if(length < resSize) break;
|
||||
char *res = (char *)buf;
|
||||
if(strlen(res)) {
|
||||
strcat(res, "\n");
|
||||
send(resFd, res, strlen(res) + 1, 0);
|
||||
}
|
||||
close(resFd);
|
||||
FD_CLR(resFd, &targetFd);
|
||||
}
|
||||
} else if(fd == listenSocket) {
|
||||
struct sockaddr_in dstAddr;
|
||||
int len = sizeof(dstAddr);
|
||||
int newSocket = accept(fd, (struct sockaddr *)&dstAddr, (socklen_t *)&len);
|
||||
if(newSocket < 0) {
|
||||
fprintf(stderr, "Socket::Accept Error\n");
|
||||
continue;
|
||||
}
|
||||
if(strcmp(inet_ntoa(dstAddr.sin_addr), "127.0.0.1")) {
|
||||
fprintf(stderr, "Rejected request from %s\n", inet_ntoa(dstAddr.sin_addr));
|
||||
close(newSocket);
|
||||
continue;
|
||||
}
|
||||
int flag = fcntl(newSocket, F_GETFL, 0);
|
||||
fcntl(newSocket, F_SETFL, O_NONBLOCK|flag);
|
||||
FD_SET(newSocket, &targetFd);
|
||||
maxFd = (newSocket > maxFd) ? newSocket : maxFd;
|
||||
if(maxFd >= MaxConnect) maxFd = MaxConnect - 1;
|
||||
} else {
|
||||
char buf[256];
|
||||
int size = recv(fd, buf, 255, 0);
|
||||
if(!size) {
|
||||
FD_CLR(fd, &targetFd);
|
||||
break;
|
||||
}
|
||||
if(size < 0) {
|
||||
close(fd);
|
||||
FD_CLR(fd, &targetFd);
|
||||
break;
|
||||
}
|
||||
buf[size] = 0;
|
||||
char *tokenPtr;
|
||||
char *p = strtok_r(buf, " \t\r\n", &tokenPtr);
|
||||
if(!p) continue;
|
||||
int executed = 0;
|
||||
for(int i = 0; i < sizeof(CommandTable) / sizeof(struct CommandTableSt); i++) {
|
||||
if(!strcasecmp(p, CommandTable[i].cmd)) {
|
||||
char *res = (*CommandTable[i].func)(fd, tokenPtr);
|
||||
if(res) {
|
||||
send(fd, res, strlen(res) + 1, 0);
|
||||
char cr = '\n';
|
||||
send(fd, &cr, 1, 0);
|
||||
close(fd);
|
||||
FD_CLR(fd, &targetFd);
|
||||
}
|
||||
executed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!executed) {
|
||||
char *res = "error";
|
||||
send(fd, res, strlen(res) + 1, 0);
|
||||
close(fd);
|
||||
FD_CLR(fd, &targetFd);
|
||||
fprintf(stderr, "command error : %s\n", p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute ((constructor)) command_init(void) {
|
||||
|
||||
if(pipe(SelfPipe)) {
|
||||
fprintf(stderr, "pipe error\n");
|
||||
return;
|
||||
}
|
||||
int flag = fcntl(SelfPipe[0], F_GETFL, 0);
|
||||
fcntl(SelfPipe[0], F_SETFL, O_NONBLOCK|flag);
|
||||
flag = fcntl(SelfPipe[1], F_GETFL, 0);
|
||||
fcntl(SelfPipe[1], F_SETFL, O_NONBLOCK|flag);
|
||||
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, NULL, CommandThread, NULL);
|
||||
}
|
125
libcallback_wz_mod/curl.c
Normal file
125
libcallback_wz_mod/curl.c
Normal file
@ -0,0 +1,125 @@
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
typedef void CURL;
|
||||
typedef int CURLcode;
|
||||
typedef long long curl_off_t;
|
||||
typedef enum {
|
||||
HTTPREQ_NONE,
|
||||
HTTPREQ_GET,
|
||||
HTTPREQ_POST,
|
||||
HTTPREQ_POST_FORM,
|
||||
HTTPREQ_POST_MIME,
|
||||
HTTPREQ_PUT,
|
||||
HTTPREQ_HEAD,
|
||||
HTTPREQ_OPTIONS,
|
||||
HTTPREQ_LAST
|
||||
} Curl_HttpReq;
|
||||
|
||||
static const int CURL_OK = 0;
|
||||
const char *methods[] = {
|
||||
"NONE", "GET", "POST", "POST_FORM", "POST_MIME", "PUT", "HEAD", "OPTIONS", "LAST", ""
|
||||
};
|
||||
static const char *AlarmPath = "/device/v1/alarm/add";
|
||||
static const char *DummyRes = "{\"ts\":1641390551000,\"code\":\"1\",\"msg\":\"\",\"data\":{\"alarm_file_list\":[{\"file_type\":1,\"file_suffix\":\"jpg\",\"file_url\":\"https://localhost/hoge.jpg\",\"encryption_algorithm\":0,\"encryption_password\":\"\"},{\"file_type\":2,\"file_suffix\":\"mp4\",\"file_url\":\"https://localhost/fuga.mp4\",\"encryption_algorithm\":0,\"encryption_password\":\"\"}]}}";
|
||||
static const char *DummyHost = "https://localhost/";
|
||||
|
||||
typedef int (*curl_seek_callback)(void *instream, int offset, int origin);
|
||||
typedef int (*curl_write_callback)(char *buffer, int size, int nitems, void *outstream);
|
||||
|
||||
struct SessionHandle {
|
||||
unsigned char padding0[1392];
|
||||
unsigned char padding1[16];
|
||||
void *out; // offset 1392 + 16
|
||||
unsigned char padding2[40];
|
||||
void *postfields; // offset 1392 + 60
|
||||
unsigned char padding3[8];
|
||||
curl_off_t postfieldsize; // offset offset 1392 + 72
|
||||
unsigned char padding4[8];
|
||||
curl_write_callback fwrite_func; // offset 1392 + 88
|
||||
unsigned char padding5[568];
|
||||
Curl_HttpReq httpreq; // offset 1392 + 660
|
||||
unsigned char padding6[664];
|
||||
char *url; // offset 2720 + 0
|
||||
unsigned char padding7[16];
|
||||
unsigned char padding8[988];
|
||||
int httpcode; // offset 3728 + 0
|
||||
};
|
||||
|
||||
static CURLcode (*original_curl_easy_perform)(CURL *curl);
|
||||
static int curl_hook_enable = 0;
|
||||
|
||||
static void __attribute ((constructor)) curl_hook_init(void) {
|
||||
original_curl_easy_perform = dlsym(dlopen("/thirdlib/libcurl.so", RTLD_LAZY), "curl_easy_perform");
|
||||
char *p = getenv("MINIMIZE_ALARM_CYCLE");
|
||||
curl_hook_enable = p && !strcmp(p, "on");
|
||||
}
|
||||
|
||||
static void Dump(const char *str, void *start, int size) {
|
||||
printf("[curl-debug] Dump %s\n", str);
|
||||
for(int i = 0; i < size; i+= 16) {
|
||||
char buf1[256];
|
||||
char buf2[256];
|
||||
sprintf(buf1, "%08x : ", start + i);
|
||||
for(int j = 0; j < 16; j++) {
|
||||
if(i + j >= size) break;
|
||||
unsigned char d = ((unsigned char *)start)[i + j];
|
||||
sprintf(buf1 + strlen(buf1), "%02x ", d);
|
||||
if((d < 0x20) || (d > 0x7f)) d = '.';
|
||||
sprintf(buf2 + j, "%c", d);
|
||||
}
|
||||
printf("%s %s\n", buf1, buf2);
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode curl_easy_perform(struct SessionHandle *data) {
|
||||
|
||||
if(!curl_hook_enable) return original_curl_easy_perform(data);
|
||||
|
||||
unsigned int ra = 0;
|
||||
asm volatile(
|
||||
"ori %0, $31, 0\n"
|
||||
: "=r"(ra)
|
||||
);
|
||||
|
||||
int method = data->httpreq;
|
||||
if(method > HTTPREQ_LAST) method = HTTPREQ_LAST;
|
||||
printf("[curl-debug] %s %s ra=0x%08x\n", methods[method], data->url, ra);
|
||||
if(data->postfields) {
|
||||
if(data->postfieldsize > 0) {
|
||||
Dump("[curl-debug] post", data->postfields, data->postfieldsize);
|
||||
} else {
|
||||
printf("[curl-debug] post : %s\n", data->postfields);
|
||||
}
|
||||
}
|
||||
|
||||
if(data->url && !strcmp(data->url + strlen(data->url) - strlen(AlarmPath), AlarmPath)) {
|
||||
static time_t lastAccess = 0;
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if(now.tv_sec - lastAccess < 300) {
|
||||
printf("[curl-debug] Dismiss short cycle alarms.\n");
|
||||
memcpy(data->out, DummyRes, strlen(DummyRes));
|
||||
data->httpcode = 200;
|
||||
return CURL_OK;
|
||||
}
|
||||
CURLcode res = original_curl_easy_perform(data);
|
||||
printf("[curl-debug] res=%d\n", res);
|
||||
if(!res) lastAccess = now.tv_sec;
|
||||
return res;
|
||||
}
|
||||
|
||||
if(data->url && !strncmp(data->url, DummyHost, strlen(DummyHost))) {
|
||||
printf("[curl-debug] skip http-post.\n");
|
||||
data->httpcode = 200;
|
||||
return CURL_OK;
|
||||
}
|
||||
|
||||
CURLcode res = original_curl_easy_perform(data);
|
||||
if(data->out) printf("[curl-debug] res : %s\n", data->out);
|
||||
printf("[curl-debug] ret: %d\n", res);
|
||||
return res;
|
||||
}
|
18
libcallback_wz_mod/freopen.c
Normal file
18
libcallback_wz_mod/freopen.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
static FILE * (*original_freopen)(const char *pathname, const char *mode, FILE *stream);
|
||||
|
||||
static void __attribute ((constructor)) freopen_hook_init(void) {
|
||||
|
||||
original_freopen = dlsym(dlopen ("/lib/libc.so.0", RTLD_LAZY), "freopen");
|
||||
}
|
||||
|
||||
FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
|
||||
|
||||
if(stream == stdout) return stdout;
|
||||
return original_freopen(pathname, mode, stream);
|
||||
}
|
||||
|
||||
|
25
libcallback_wz_mod/gmtime_r.c
Normal file
25
libcallback_wz_mod/gmtime_r.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
extern int MotorFd;
|
||||
extern struct timeval MotorLastMovedTime;
|
||||
|
||||
static struct tm *(*original_gmtime_r)(const time_t *timep, struct tm *result);
|
||||
|
||||
static void __attribute ((constructor)) gmtime_r_hook_init(void) {
|
||||
|
||||
original_gmtime_r = dlsym(dlopen ("/lib/libc.so.0", RTLD_LAZY), "gmtime_r");
|
||||
}
|
||||
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result) {
|
||||
|
||||
original_gmtime_r(timep, result);
|
||||
// While the camera is moving, the AI process is disabled by returning a day of the week that does not exist when motion is detected.
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
timersub(&tv, &MotorLastMovedTime, &tv);
|
||||
if(MotorFd || !tv.tv_sec) result->tm_wday = 8;
|
||||
return result;
|
||||
}
|
24
libcallback_wz_mod/irled.c
Normal file
24
libcallback_wz_mod/irled.c
Normal file
@ -0,0 +1,24 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int local_sdk_close_night_light();
|
||||
extern int local_sdk_open_night_light();
|
||||
extern int local_sdk_auto_night_light();
|
||||
extern void CommandResponse(int fd, const char *res);
|
||||
|
||||
char *IrLed(int fd, char *tokenPtr) {
|
||||
|
||||
char *p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
if(!p) return "error";
|
||||
if(!strcmp(p, "on")) {
|
||||
local_sdk_open_night_light();
|
||||
} else if(!strcmp(p, "off")) {
|
||||
local_sdk_close_night_light();
|
||||
} else if(!strcmp(p, "auto")) {
|
||||
local_sdk_auto_night_light();
|
||||
} else {
|
||||
return "error";
|
||||
}
|
||||
return "ok";
|
||||
}
|
118
libcallback_wz_mod/jpeg.c
Normal file
118
libcallback_wz_mod/jpeg.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
struct channelConfigSt {
|
||||
uint dummy[4];
|
||||
int state;
|
||||
int encoder;
|
||||
};
|
||||
extern struct channelConfigSt *get_enc_chn_config(int ch);
|
||||
extern int get_video_run_state(int ch);
|
||||
extern void video_param_set_mutex_lock();
|
||||
extern int IMP_Encoder_StartRecvPic(int ch);
|
||||
extern int IMP_Encoder_PollingStream(int ch, int timeoutMSec);
|
||||
extern int IMP_Encoder_GetStream(int ch, uint *stream, int);
|
||||
extern int IMP_Encoder_ReleaseStream(int ch, int *stream);
|
||||
extern int IMP_Encoder_StopRecvPic(int ch);
|
||||
extern int save_jpeg(int fd, int *stream);
|
||||
extern void video_param_set_mutex_unlock();
|
||||
extern void CommandResponse(int fd, const char *res);
|
||||
|
||||
static const char *HttpResHeader = "Cache-Control: no-cache\nContent-Type: image/jpeg\n\n";
|
||||
static const char *HttpErrorHeader = "Cache-Control: no-cache\nStatus: 503\n\n";
|
||||
static pthread_mutex_t JpegDataMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int JpegCaptureFd = -1;
|
||||
|
||||
char *JpegCapture(int fd, char *tokenPtr) {
|
||||
|
||||
if(JpegCaptureFd >= 0) {
|
||||
fprintf(stderr, "[command] jpeg capture error %d %d\n", JpegCaptureFd, fd);
|
||||
write(fd, HttpErrorHeader, strlen(HttpErrorHeader));
|
||||
CommandResponse(fd, "error : jpeg capture error");
|
||||
return NULL;
|
||||
}
|
||||
JpegCaptureFd = fd;
|
||||
pthread_mutex_unlock(&JpegDataMutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int GetJpegData(int fd) {
|
||||
|
||||
struct channelConfigSt *chConfig = get_enc_chn_config(0);
|
||||
if (!chConfig->state) {
|
||||
fprintf(stderr, "[command] jpeg err: ch0 is not enable jpeg!\n");
|
||||
return -1;
|
||||
}
|
||||
int state = get_video_run_state(0);
|
||||
if (state < 5) {
|
||||
fprintf(stderr, "[command] jpeg err: U should call 'video_run' before this func\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
video_param_set_mutex_lock(1);
|
||||
int encoder = chConfig->encoder;
|
||||
int ret = 0;
|
||||
|
||||
if(IMP_Encoder_StartRecvPic(encoder) < 0) {
|
||||
fprintf(stderr, "[command] jpeg err: IMP_Encoder_StartRecvPic(%d) failed\n", encoder);
|
||||
ret = -1;
|
||||
goto error1;
|
||||
}
|
||||
|
||||
if(IMP_Encoder_PollingStream(encoder, 2000) < 0) {
|
||||
fprintf(stderr, "[command] jpeg err: Polling stream(chn%d) timeout\n", encoder);
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
uint stream[17];
|
||||
memset(stream, 0, 60);
|
||||
if(IMP_Encoder_GetStream(encoder, stream, 1) < 0) {
|
||||
fprintf(stderr, "[command] jpeg err: IMP_Encoder_GetStream(chn%d) failed\n", encoder);
|
||||
ret = -1;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
write(JpegCaptureFd, HttpResHeader, strlen(HttpResHeader));
|
||||
if(save_jpeg(fd, stream) < 0) {
|
||||
fprintf(stderr, "[command] jpeg err: save_jpeg(%d) failed\n", fd);
|
||||
ret = -2;
|
||||
}
|
||||
IMP_Encoder_ReleaseStream(encoder, stream);
|
||||
|
||||
error2:
|
||||
if(IMP_Encoder_StopRecvPic(encoder) < 0) {
|
||||
fprintf(stderr, "[command] jpeg err: IMP_Encoder_StopRecvPic(chn%d) failed\n", encoder);
|
||||
}
|
||||
|
||||
error1:
|
||||
video_param_set_mutex_unlock(1);
|
||||
if(ret == -1) write(JpegCaptureFd, HttpErrorHeader, strlen(HttpErrorHeader));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *JpegCaptureThread() {
|
||||
|
||||
while(1) {
|
||||
pthread_mutex_lock(&JpegDataMutex);
|
||||
if(JpegCaptureFd >= 0) {
|
||||
int res = GetJpegData(JpegCaptureFd);
|
||||
CommandResponse(JpegCaptureFd, res >= 0 ? "" : "error : buffer size error");
|
||||
}
|
||||
JpegCaptureFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute ((constructor)) JpegInit(void) {
|
||||
|
||||
pthread_mutex_lock(&JpegDataMutex);
|
||||
pthread_t thread;
|
||||
if(pthread_create(&thread, NULL, JpegCaptureThread, NULL)) {
|
||||
fprintf(stderr, "pthread_create error\n");
|
||||
pthread_mutex_unlock(&JpegDataMutex);
|
||||
return;
|
||||
}
|
||||
}
|
BIN
libcallback_wz_mod/libcallback.so
Executable file
BIN
libcallback_wz_mod/libcallback.so
Executable file
Binary file not shown.
7
libcallback_wz_mod/mmc_format.c
Normal file
7
libcallback_wz_mod/mmc_format.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
// disable mmc format
|
||||
int local_sdk_device_mmc_format() {
|
||||
printf("skip local_sdk_device_mmc_format\n");
|
||||
return 0;
|
||||
}
|
68
libcallback_wz_mod/motor.c
Normal file
68
libcallback_wz_mod/motor.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
extern int local_sdk_motor_get_position(float *step,float *angle);
|
||||
extern int local_sdk_motor_move_abs_angle(float pan, float tilt, int speed, void (*done)(float a, float b), void (*canceled)(void), int mode);
|
||||
extern void CommandResponse(int fd, const char *res);
|
||||
|
||||
int MotorFd = 0;
|
||||
struct timeval MotorLastMovedTime = { 0, 0 };
|
||||
|
||||
static void motor_move_done(float pan, float tilt) {
|
||||
|
||||
if(MotorFd) {
|
||||
static char motorResBuf[256];
|
||||
sprintf(motorResBuf, "%f %f\n", pan, tilt);
|
||||
CommandResponse(MotorFd, motorResBuf);
|
||||
}
|
||||
MotorFd = 0;
|
||||
struct timeval tv;
|
||||
gettimeofday(&MotorLastMovedTime, NULL);
|
||||
}
|
||||
|
||||
static void motor_move_canceled() {
|
||||
|
||||
if(MotorFd) CommandResponse(MotorFd, "error");
|
||||
MotorFd = 0;
|
||||
gettimeofday(&MotorLastMovedTime, NULL);
|
||||
}
|
||||
|
||||
char *MotorMove(int fd, char *tokenPtr) {
|
||||
|
||||
char *p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
if(!p) {
|
||||
float pan; // 0-355
|
||||
float tilt; // 0-180
|
||||
int ret = local_sdk_motor_get_position(&pan, &tilt);
|
||||
static char motorResBuf[256];
|
||||
if(!ret) {
|
||||
sprintf(motorResBuf, "%f %f\n", pan, tilt);
|
||||
} else {
|
||||
sprintf(motorResBuf, "- -\n");
|
||||
}
|
||||
return motorResBuf;
|
||||
}
|
||||
float pan = atof(p); // 0-355
|
||||
if((pan < 0.0) || (pan > 355.0)) return "error";
|
||||
|
||||
p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
if(!p) return "error";
|
||||
float tilt = atof(p); // 0-180
|
||||
if((tilt < 0.0) || (tilt > 180.0)) return "error";
|
||||
|
||||
p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
int pri = 2; // 0: high - 3: low
|
||||
if(p) pri = atoi(p);
|
||||
if(pri < 0) pri = 0;
|
||||
if(pri > 3) pri = 3;
|
||||
|
||||
if(MotorFd) return "error";
|
||||
MotorFd = fd;
|
||||
|
||||
int speed = 9;
|
||||
int res = local_sdk_motor_move_abs_angle(pan, tilt, speed, &motor_move_done, &motor_move_canceled, pri);
|
||||
return NULL;
|
||||
}
|
24
libcallback_wz_mod/opendir.c
Normal file
24
libcallback_wz_mod/opendir.c
Normal file
@ -0,0 +1,24 @@
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
static DIR * (*original_opendir)(const char *pathname);
|
||||
static const char *HookPath = "/media/mmc/time_lapse/time_Task_";
|
||||
static const char *MediaPath = "/media/mmc/";
|
||||
char TimeLapsePath[256];
|
||||
|
||||
static void __attribute ((constructor)) opendir_hook_init(void) {
|
||||
|
||||
original_opendir = dlsym(dlopen ("/lib/libc.so.0", RTLD_LAZY), "opendir");
|
||||
}
|
||||
|
||||
DIR *opendir(const char *pathname) {
|
||||
|
||||
if(!strncmp(pathname, HookPath, strlen(HookPath))) {
|
||||
strncpy(TimeLapsePath, pathname + strlen(MediaPath), 255);
|
||||
printf("[webhook] time_lapse_event %s\n", TimeLapsePath);
|
||||
}
|
||||
return original_opendir(pathname);
|
||||
}
|
20
libcallback_wz_mod/remove.c
Normal file
20
libcallback_wz_mod/remove.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
static int (*original_remove)(const char *pathname);
|
||||
static const char *HookPath = "/media/mmc/time_lapse/.setup";
|
||||
extern char TimeLapsePath[256];
|
||||
|
||||
static void __attribute ((constructor)) remove_hook_init(void) {
|
||||
|
||||
original_remove = dlsym(dlopen ("/lib/libc.so.0", RTLD_LAZY), "remove");
|
||||
}
|
||||
|
||||
int remove(const char *pathname) {
|
||||
|
||||
if(!strncmp(pathname, HookPath, strlen(HookPath))) printf("[webhook] time_lapse_finish %s\n", TimeLapsePath);
|
||||
return original_remove(pathname);
|
||||
}
|
||||
|
||||
|
5
libcallback_wz_mod/setlinebuf.c
Normal file
5
libcallback_wz_mod/setlinebuf.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
static void __attribute ((constructor)) setStdoutLineBuffer(void) {
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
}
|
@ -19,7 +19,24 @@ typedef int (* framecb)(struct frames_st *);
|
||||
|
||||
static int (*real_local_sdk_video_set_encode_frame_callback)(int ch, void *callback);
|
||||
static void *video_encode_cb = NULL;
|
||||
static int VideoCaptureEnable = 1;
|
||||
static int VideoCaptureEnable = 0;
|
||||
|
||||
char *VideoCapture(int fd, char *tokenPtr) {
|
||||
|
||||
char *p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
if(!p) return VideoCaptureEnable ? "on" : "off";
|
||||
if(!strcmp(p, "on")) {
|
||||
VideoCaptureEnable = 1;
|
||||
fprintf(stderr, "[command] video capute on\n", p);
|
||||
return "ok";
|
||||
}
|
||||
if(!strcmp(p, "off")) {
|
||||
VideoCaptureEnable = 0;
|
||||
fprintf(stderr, "[command] video capute off\n", p);
|
||||
return "ok";
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
static uint32_t video_encode_capture(struct frames_st *frames) {
|
||||
|
||||
@ -60,7 +77,7 @@ static uint32_t video_encode_capture(struct frames_st *frames) {
|
||||
int local_sdk_video_set_encode_frame_callback(int ch, void *callback) {
|
||||
|
||||
fprintf(stderr, "local_sdk_video_set_encode_frame_callback streamChId=%d, callback=0x%x\n", ch, callback);
|
||||
if(ch == 0) {
|
||||
if( (ch == 0) && callback == 0x48cc50) {
|
||||
video_encode_cb = callback;
|
||||
fprintf(stderr,"enc func injection save video_encode_cb=0x%x\n", video_encode_cb);
|
||||
callback = video_encode_capture;
|
111
libcallback_wz_mod/wait_motion.c
Normal file
111
libcallback_wz_mod/wait_motion.c
Normal file
@ -0,0 +1,111 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
extern void CommandResponse(int fd, const char *res);
|
||||
extern int local_sdk_motor_get_position(float *step,float *angle);
|
||||
extern int MotorFd;
|
||||
extern struct timeval MotorLastMovedTime;
|
||||
|
||||
struct RectInfoSt {
|
||||
int left;
|
||||
int right;
|
||||
int top;
|
||||
int bottom;
|
||||
int dummy1;
|
||||
int dummt2;
|
||||
};
|
||||
|
||||
static int (*original_local_sdk_video_osd_update_rect)(int ch, int display, struct RectInfoSt *rectInfo);
|
||||
static int WaitMotionFd = -1;
|
||||
static int Timeout = -1;
|
||||
static pthread_mutex_t WaitMotionMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t WaitMotionCond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
char *WaitMotion(int fd, char *tokenPtr) {
|
||||
|
||||
if(WaitMotionFd >= 0) {
|
||||
fprintf(stderr, "[command] wait motion error %d %d\n", WaitMotionFd, fd);
|
||||
return "error : wait motion error";
|
||||
}
|
||||
char *p = strtok_r(NULL, " \t\r\n", &tokenPtr);
|
||||
Timeout = p ? atoi(p) : 0;
|
||||
if(Timeout < 10) {
|
||||
fprintf(stderr, "[command] wait motion timeout error timeout = %d\n", Timeout);
|
||||
return "error : wait motion timeout value error";
|
||||
}
|
||||
|
||||
WaitMotionFd = fd;
|
||||
pthread_mutex_unlock(&WaitMotionMutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int local_sdk_video_osd_update_rect(int ch, int display, struct RectInfoSt *rectInfo) {
|
||||
|
||||
if((WaitMotionFd >= 0) && (MotorFd <= 0) && !ch) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
timersub(&tv, &MotorLastMovedTime, &tv);
|
||||
if(tv.tv_sec || (tv.tv_usec >= 500000)) {
|
||||
if(display) {
|
||||
float pan; // 0-355
|
||||
float tilt; // 0-180
|
||||
int ret = local_sdk_motor_get_position(&pan, &tilt);
|
||||
static char waitMotionResBuf[256];
|
||||
if(!ret) {
|
||||
pan += (rectInfo->left + rectInfo->right - 320 * 2) * 85 / (2 * 640);
|
||||
if(pan < 0.0) pan = 0.0;
|
||||
if(pan > 355.0) pan = 355;
|
||||
tilt -= (rectInfo->top + rectInfo->bottom - 180 * 2) * 55 / (2 * 360);
|
||||
if(tilt < 45.0) tilt = 45.0;
|
||||
if(tilt > 180.0) tilt = 180.0;
|
||||
sprintf(waitMotionResBuf, "detect %d %d %d %d %d %d\n",
|
||||
rectInfo->left, rectInfo->right, rectInfo->top, rectInfo->bottom, lroundf(pan), lroundf(tilt));
|
||||
} else {
|
||||
sprintf(waitMotionResBuf, "detect %d %d %d %d - -\n",
|
||||
rectInfo->left, rectInfo->right, rectInfo->top, rectInfo->bottom);
|
||||
}
|
||||
CommandResponse(WaitMotionFd, waitMotionResBuf);
|
||||
} else {
|
||||
CommandResponse(WaitMotionFd, "clear\n");
|
||||
}
|
||||
pthread_cond_signal(&WaitMotionCond);
|
||||
}
|
||||
}
|
||||
return original_local_sdk_video_osd_update_rect(ch, display, rectInfo);
|
||||
}
|
||||
|
||||
static void *WaitMotionThread() {
|
||||
|
||||
while(1) {
|
||||
pthread_mutex_lock(&WaitMotionMutex);
|
||||
if(WaitMotionFd >= 0) {
|
||||
struct timeval now;
|
||||
struct timespec timeout;
|
||||
gettimeofday(&now, NULL);
|
||||
timeout.tv_sec = now.tv_sec + Timeout;
|
||||
timeout.tv_nsec = now.tv_usec * 1000;
|
||||
int ret = pthread_cond_timedwait(&WaitMotionCond, &WaitMotionMutex, &timeout);
|
||||
if(ret == ETIMEDOUT) CommandResponse(WaitMotionFd, "timeout\n");
|
||||
}
|
||||
WaitMotionFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute ((constructor)) osd_rect_hook_init(void) {
|
||||
|
||||
original_local_sdk_video_osd_update_rect = dlsym(dlopen ("/system/lib/liblocalsdk.so", RTLD_LAZY), "local_sdk_video_osd_update_rect");
|
||||
|
||||
pthread_mutex_lock(&WaitMotionMutex);
|
||||
pthread_t thread;
|
||||
if(pthread_create(&thread, NULL, WaitMotionThread, NULL)) {
|
||||
fprintf(stderr, "pthread_create error\n");
|
||||
pthread_mutex_unlock(&WaitMotionMutex);
|
||||
return;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user