-
Notifications
You must be signed in to change notification settings - Fork 0
/
ga-common.cpp
269 lines (252 loc) · 6.6 KB
/
ga-common.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*
* Copyright (c) 2013 Chun-Ying Huang
* Modification Copyright (c) 2021 me(github.com/am009)
*
* This file is part of GamingAnywhere (GA).
*
* GA is free software; you can redistribute it and/or modify it
* under the terms of the 3-clause BSD License as published by the
* Free Software Foundation: http://directory.fsf.org/wiki/License:BSD_3Clause
*
* GA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the 3-clause BSD License along with GA;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* @file
* implementation: common GA functions and macros
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#ifndef WIN32
#ifndef ANDROID
#include <execinfo.h>
#endif /* !ANDROID */
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/syscall.h>
#endif /* !WIN32 */
#ifdef ANDROID
#include <android/log.h>
#endif /* ANDROID */
#ifdef __APPLE__
#include <syslog.h>
#endif
#if !defined(WIN32) && !defined(__APPLE__) && !defined(ANDROID)
#include <X11/Xlib.h>
#endif
#include "ga-common.h"
#include "config.h"
// #include "ga-conf.h"
#ifndef ANDROID_NO_FFMPEG
// #include "ga-avcodec.h"
#endif
// #include "rtspconf.h"
#include <map>
#include <list>
#include <algorithm>
using namespace std;
#ifndef NIPQUAD
/** For printing IPv4 addresses: convert an unsigned int to 4 unsigned char. */
#define NIPQUAD(x) ((unsigned char*)&(x))[0], \
((unsigned char*)&(x))[1], \
((unsigned char*)&(x))[2], \
((unsigned char*)&(x))[3]
#endif
/** The gloabl log file name */
static char *ga_logfile = NULL;
// https://stackoverflow.com/questions/865668/parsing-command-line-arguments-in-c
char* getCmdOption(char** begin, char** end, const std::string& option)
{
char** itr = std::find(begin, end, option);
if (itr != end && ++itr != end)
{
return *itr;
}
return 0;
}
bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
return std::find(begin, end, option) != end;
}
/**
* Compute the time difference for two \a timeval data structure, i.e.,
* \a tv1 - \a tv2.
*
* @param tv1 [in] Pointer to the first \a timeval data structure.
* @param tv2 [in] Pointer to the second \a timeval data structure.
* @return The difference in micro seconds.
*/
EXPORT
long long
tvdiff_us(struct timeval *tv1, struct timeval *tv2) {
struct timeval delta;
delta.tv_sec = tv1->tv_sec - tv2->tv_sec;
delta.tv_usec = tv1->tv_usec - tv2->tv_usec;
if(delta.tv_usec < 0) {
delta.tv_sec--;
delta.tv_usec += 1000000;
}
return 1000000LL*delta.tv_sec + delta.tv_usec;
}
/**
* Sleep and wake up at \a ptv + \a interval (micro seconds).
*
* @param interval [in] The expected sleeping time (in micro seconds).
* @param ptv [in] Pointer to the baseline time.
* @return Currently always return 0.
*
* This function is useful for controlling precise sleeps.
* We usually have to process each video frame in a fixed interval.
* Each time interval includes the processing time and the sleeping time.
* However, the processing time could be different in each iteration, so
* the sleeping time has to be adapted as well.
* To achieve the goal, we have to obtain the baseline time \a ptv
* (using \a gettimeofday function)
* \em before the processing task and call this function \em after
* the processing task. In this case, the \a interval is set to the total
* length of the interval, e.g., 41667 for 24fps video.
*
* This function sleeps for \a interval micro seconds if the baseline
* time is not specified.
*/
EXPORT
long long
ga_usleep(long long interval, struct timeval *ptv) {
long long delta;
struct timeval tv;
if(ptv != NULL) {
gettimeofday(&tv, NULL);
delta = tvdiff_us(&tv, ptv);
if(delta >= interval) {
usleep(1);
return -1;
}
interval -= delta;
}
usleep(interval);
return 0LL;
}
/**
* Write message \a s into the log file.
* This in an internal function only called by \em ga_log function.
*
* @param tv [in] The timestamp of logging.
* @param s [in] The message to be written.
*
* This function is SLOW, but it attempts to make all writes successfull.
* It appends the message into the file each time when it is called.
*/
static void
ga_writelog(struct timeval tv, const char *s) {
FILE *fp;
if(ga_logfile == NULL)
return;
if((fp = fopen(ga_logfile, "at")) != NULL) {
fprintf(fp, "[%d] %ld.%06ld %s", getpid(), tv.tv_sec, tv.tv_usec, s);
fclose(fp);
}
return;
}
/**
* Write log messages and print on Android console.
*
* @param fmt [in] The format string for the message.
* @param ... [in] The arguments for replacing specifiers in the format string.
*
* This function has the same syntax as the \em printf function.
* It outputs a timestamp before the message, and optionally writing
* the message into a log file if log feature is turned on.
*/
EXPORT
int
ga_log(const char *fmt, ...) {
char msg[4096];
struct timeval tv;
va_list ap;
//
gettimeofday(&tv, NULL);
va_start(ap, fmt);
#ifdef ANDROID
__android_log_vprint(ANDROID_LOG_INFO, "ga_log.native", fmt, ap);
#endif
vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
#ifdef __APPLE__
syslog(LOG_NOTICE, "%s", msg);
#endif
//
ga_writelog(tv, msg);
//
return 0;
}
/**
* Print out log messages (on \em stderr or log console (on Android)).
*
* @param fmt [in] The format string for the message.
* @param ... [in] The arguments for replacing specifiers in the format string.
*
* This function has the same syntax as the \em printf function.
* It outputs a timestamp before the message.
*/
EXPORT
int
ga_error(const char *fmt, ...) {
char msg[4096];
struct timeval tv;
va_list ap;
gettimeofday(&tv, NULL);
va_start(ap, fmt);
#ifdef ANDROID
__android_log_vprint(ANDROID_LOG_INFO, "ga_log.native", fmt, ap);
#endif
vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
#ifdef __APPLE__
syslog(LOG_NOTICE, "%s", msg);
#endif
fprintf(stderr, "# [%d] %ld.%06ld %s", getpid(), tv.tv_sec, tv.tv_usec, msg);
//
ga_writelog(tv, msg);
//
return -1;
}
/**
* Get the thread ID in long format.
*/
EXPORT
long
ga_gettid() {
#ifdef WIN32
return GetCurrentThreadId();
#elif defined __APPLE__
return pthread_mach_thread_np(pthread_self());
#elif defined ANDROID
return gettid();
#else
return (pid_t) syscall(SYS_gettid);
#endif
}
/**
* Initialize windows socket sub-system.
*
* @return 0 on success and -1 on error.
*/
int
winsock_init() {
#ifdef WIN32
WSADATA wd;
if(WSAStartup(MAKEWORD(2,2), &wd) != 0)
return -1;
#endif
return 0;
}