编译Android版本的OpenSSL

将android-ndk-r20b和openssl-master解压在同一层目录,在此目录创建脚本bld.sh,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/sh
 
BASE_DIR=/home/sdb/android/ndk-r20b
 
export ANDROID_NDK_HOME=${BASE_DIR}/android-ndk-r20b
 
PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH
 
cd openssl-master/
 
#./Configure --prefix=${BASE_DIR}/openssl-arm32 android-arm -D__ANDROID_API__=29
./Configure --prefix=${BASE_DIR}/openssl-arm32 android-arm -D__ANDROID_API__=16
#./Configure --prefix=${BASE_DIR}/openssl-x86 android-x86 -D__ANDROID_API__=16
 
make
make install

运行bld.sh脚本就会生成OpenSSL库文件。

How to build rtsp stream from a mp4 file to test EuhatRtsp

First, convert mp4 file to h264 file, save script below as convert.bat

1
2
3
ffmpeg.exe -i %1 -s 1920x1080 -b:v 1536K -an output.mp4
ffmpeg -i output.mp4 -codec copy -bsf: h264_mp4toannexb -f h264 output.264
#ffmpeg -i test.264 -vcodec copy -f mp4 test.mp4

drag a mp4 file over convert.bat, after a while, output.264 will be generated. download h264LiveMediaServer.zip, unzip as h264LiveMediaServer.exe, move it to the same directory with output.264, just double click and run h264LiveMediaServer.exe, it will notify you the rtsp url, then input the url in the url edit box on the EuhatRtsp Demo app ui, click begin button, wait several seconds, you will see the video rendering in EuhatRtsp.

Before running h264LiveMediaServer.exe, vc2019 x86 Redistributable must be installed.

Visit H264LiveMediaServer on Github to get the source code.

编译时打印宏变量内容

1
2
3
4
5
6
7
8
9
#define PRINT_MACRO_HELPER(_x) #_x
#define PRINT_MACRO(_x) #_x " = " PRINT_MACRO_HELPER(_x)
 
#define DEFINED_PI 3.14
#define DEFINED_NULL
#pragma message(PRINT_MACRO(DEFINED_PI))
#pragma message(PRINT_MACRO(DEFINED_NULL))
#pragma message(PRINT_MACRO(UNDEFINED))
//#error print stop here.

refer to: https://blog.csdn.net/xshbx/article/details/7981564

晋朝帝王年表

西晋

庙号 帝号 姓名 在位时期 上位 在位 年号
高祖 宣帝 司马懿 249-251 70岁 3年
世宗 景帝 司马师 252-254 44岁 3年
太祖 文帝 司马昭 255-265 44岁 11年
世祖 武帝 司马炎 266-290 30岁 25年 泰始/咸宁/太康/太熙
孝惠帝 司马衷 291-306 35岁 16年 永平/元康/永康/永宁/太安/永安/建武/永兴/光熙
孝怀帝 司马炽 307-313 23岁 7年 永嘉
孝愍帝 司马邺 313-316 13岁 4年 建兴

东晋

庙号 帝号 姓名 在位时期 上位 在位 年号
中宗 元帝 司马睿 317-323 41岁 7年 建武/太兴/永昌/太宁
肃宗 明帝 司马绍 323-326 24岁 4年 太宁
显宗 成帝 司马衍 326-342 5岁 15年 咸和/咸康
康帝 司马岳 343-344 21岁 2年 建元
孝宗 穆帝 司马聃 345-361 2岁 17年 永和/升平
哀帝 司马丕 362-365 21岁 4年 隆和/兴宁
司马奕 366-371 24岁 6年 太和
太宗 简文帝 司马昱 371-372 51岁 2年 咸安
烈宗 孝武帝 司马曜 373-396 11岁 28年 宁康/太元
安帝 司马德宗 397-402 15岁 6年 隆安/元兴/大亨
恒楚 桓玄 403-404 34岁 2年 永始
恒楚 恒谦 404-410 7年 天康
安帝 司马德宗 405-418 23岁 14年 义熙
恭帝 司马德文 419-420 33岁 2年 元熙

refer to: https://baike.baidu.com/item/%E6%99%8B%E6%9C%9D/195770?fr=aladdin

从cmdline解析出参数token

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
#include <string>
#include <vector>
#include <sstream>
 
using namespace std;
 
wstring copySpanStr(const wchar_t* start, const wchar_t* end)
{
	wchar_t* buf = (wchar_t*)malloc((end - start + 1) * sizeof(wchar_t));
	wchar_t* pTo = buf;
	for (const wchar_t* p = start; p != end; p++)
	{
		if (*p == L'\\' && p + 1 != end)
		{
			p++;
			*pTo++ = *p;
		}
		else
			*pTo++ = *p;
	}
	*pTo = 0;
	wstring out = buf;
	free(buf);
	return out;
}
 
int getParams(const wchar_t* str, vector<wstring>& out)
{
	int isInQMark = 0;
	int isInSpace = 1;
	const wchar_t* tokenStart = str;
	for (const wchar_t* p = str; ; p++)
	{
		if (*p == L'"')
		{
			if (!isInQMark)
			{
				isInQMark = 1;
				tokenStart = p + 1;
			}
			else
			{
				isInQMark = 0;
				out.push_back(copySpanStr(tokenStart, p));
			}
		}
		else if (*p == L'\\')
		{
			if (*(p + 1) != 0)
				p++;
		}
		else if (*p == L' ' || *p == 0)
		{
			if (!isInQMark)
			{
				if (!isInSpace)
				{
					isInSpace = 1;
					if (tokenStart != p)
					{
						out.push_back(copySpanStr(tokenStart, p));
						tokenStart = p;
					}
				}
				else
				{
 
				}
			}
		}
		else
		{
			if (!isInQMark)
			{
				if (!isInSpace)
				{
 
				}
				else
				{
					isInSpace = 0;
					tokenStart = p;
				}
			}
		}
		if (*p == 0)
			break;
	}
	return out.size();
}
 
wstring strReplaceCh2Str(const wchar_t* in, wchar_t fromCh, const wchar_t* toStr)
{
	const wchar_t* p = in;
	wstringstream ss;
	const wchar_t* pToStr;
	for (; *p != 0; p++)
	{
		if (*p == fromCh)
		{
			for (pToStr = toStr; *pToStr != 0; pToStr++)
			{
				ss << *pToStr;
			}
		}
		else
			ss << *p;
	}
	return ss.str();
}
 
int main()
{
	wstring path = strReplaceCh2Str(L"c:\\aa.txt", L'\\', L"\\\\");
	wstring msg = strReplaceCh2Str(L"\"优孩\"是EuhatExpert的中文名。", L'\"', L"\\\"");
 
	wstring cmd = L"EuhatExample.exe subCmd \"" + path + L"\" \"" + msg + L"\" 1234 5678";
 
	vector<wstring> params;
	getParams(cmd.c_str(), params);
	return 0;
}