MsgWaitForMultipleObjectsEx, indeed core function

Formerly I wrote message loop code like

1
2
3
4
5
	if (GetMessage (&msg, NULL, 0, 0, PM_REMOVE))
	{
		TranslateMessage (&msg);
		DispatchMessage (&msg);
	}

If no message occured, I couldn't do anything else. It's the reason why I couldn't wrote a cross-platform UI framework which needed to realize IOC abstraction.

In the GStreamer and GLib source code, I learnt from its G_WIN32_MSG_HANDLE processing logic, there is a critical api, MsgWaitForMultipleObjectsEx, which can bundle message and all other types of events together for polling, we needn't repetitively call PeekMessage to query if a message happens, it's ridiculous.

I guess the Qt framework really knows this trick while the Awtk doesn't.

Render video from OpenCV Mat by using Direct3d

mainwindow.h

1
2
3
4
5
6
7
8
#include "vren_thread.h"
 
class MainWindow : public QMainWindow
{
	Q_OBJECT
	...
	vren_thread vren_;
};

mainwindow.c

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
#include "mainwindow.h"
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>
 
void CALLBACK DecCBFun(long nPort, char* pBuf, long nSize, FRAME_INFO* pFrameInfo, long nReserved1, long nReserved2)
{
	long lFrameType = pFrameInfo->nType;
 
	if (lFrameType == T_YV12)
	{
		MainWindow* win = port2MainWindow[nPort];
		if (nullptr == win)
		{
			qDebug() << "lookup main window from " << nPort << " failed.";
			return;
		}
 
		win->realYuvCallback(pBuf, nSize, pFrameInfo->nStamp, pFrameInfo->nWidth, pFrameInfo->nHeight);
	}
}
 
void MainWindow::realYuvCallback(const char* pBuf, int len, int64_t nStamp, int width, int height)
{
	cv::Mat dst(height, width, CV_8UC3);
	cv::Mat src(height + height / 2, width, CV_8UC1, (uchar*)pBuf);
	cv::cvtColor(src, dst, CV_YUV2RGBA_YV12); // CV_YUV2BGR_YV12);
	cv::line(dst, cv::Point(0, 0), cv::Point(100, 100), cv::Scalar(255, 0, 0), 10);
 
	vren_.Render_d3d(dst);
}
 
void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize, void* pUser)
{
	MainWindow* pThis = (MainWindow*)pUser;
	pThis->realDataCallback(lRealHandle, dwDataType, pBuffer, dwBufSize);
}
 
void MainWindow::realDataCallback(LONG lRealHandle, DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize)
{
	DWORD dRet = 0;
	BOOL inData = FALSE;
 
	switch (dwDataType)
	{
	case NET_DVR_SYSHEAD:
		if (!PlayM4_GetPort(&port_))
		{
			break;
		}
 
		port2MainWindow[port_] = this;
		playWnd_ = (HWND)ui->widgetVideo->winId();
		vren_.SetParam(playWnd_);
 
		if (!PlayM4_OpenStream(port_, pBuffer, dwBufSize, 1024 * 1024))
		{
			dRet = PlayM4_GetLastError(port_);
			break;
		}
 
		if (!PlayM4_SetDecCallBackEx(port_, DecCBFun, NULL, NULL))
		{
			dRet = PlayM4_GetLastError(port_);
			break;
		}
 
		if (!PlayM4_Play(port_, NULL)) // playWnd_))
		{
			dRet = PlayM4_GetLastError(port_);
			break;
		}
	}
}

vren_thread.h

Read more

Compile gstreamer's test-launch in Windows

Include paths

1
2
D:\work\gstreamer\gstreamer\installed\include\gstreamer-1.0
D:\work\gstreamer\gstreamer\installed\include\glib-2.0

Lib paths

1
2
D:\work\gstreamer\gstreamer\installed\lib\gstreamer-1.0
D:\work\gstreamer\gstreamer\installed\lib

Libs:

1
2
3
4
5
6
7
8
9
10
11
gstrtspserver-1.0.lib
gstgio.lib
gstges.lib
gstmediafoundation.lib
gstwic.lib
gstadaptivedemux2.lib
gstd3d11.lib
gstnetsim.lib
gstreamer-1.0.lib
glib-2.0.lib
gobject-2.0.lib

invalid cast from 'GstVideoTestSrc' to 'GstBin'

videotestsrc is just an element, not a bin container, so we must use round brackets to embrace the elements all, which means rtsp://127.0.0.1:8554/test is the default mount point.

1
2
test-launch.exe "( videotestsrc ! qsvh264enc ! rtph264pay name=pay0 pt=96 )"
gst-launch-1.0.exe playbin uri=rtsp://127.0.0.1:8554/test --gst-debug=d3d11window:5

GStreamer memo

https://gstreamer.freedesktop.org/documentation/tools/gst-launch.html

https://cloud.tencent.com/developer/article/1820526
https://blog.csdn.net/csdnhuaong/article/details/80026433
https://blog.csdn.net/qq_42711516/article/details/123921984
https://blog.csdn.net/han2529386161/article/details/102724856

https://blog.csdn.net/m0_51004308/article/details/121357638
https://blog.csdn.net/Aidam_Bo/article/details/109772430
https://blog.51cto.com/u_13161667/3310768
gstreamer之RTSP Server一个进程提供多路不同视频

https://blog.51cto.com/u_13161667/3310521
全网首发:gstreamer如何接入RTSP流(IP摄像头)的代码范例

http://t.zoukankan.com/missmzt-p-10918216.html

#播放并存储为h264
gst-launch-1.0 -e -v  udpsrc port=10001 !  "application/x-rtp, media=video, clock-rate=90000, encoding-name=H264"  ! rtph264depay ! tee name=t  t. ! queue ! h264parse ! "video/x-h264, stream-format=byte-stream" ! filesink location=./aa.h264 t. !  queue ! avdec_h264 ! glimagesink

#混流+缩放
./gst-launch-1.0  intervideosrc !  video/x-raw,framerate=(fraction)10/1,width=3200,height=2400 ! videomixer name=mix sink_1::xpos=0 sink_2::xpos=1000 sink_2::width=100 sink_2::height=100 ! videoconvert ! glimagesink filesrc location=./ttt.mov ! decodebin ! video/x-raw,width=1280,height=720 ! videoscale ! video/x-raw,width=100  ! mix.  videotestsrc ! video/x-raw ! mix.

gst-launch-1.0.exe videotestsrc ! queue ! d3d11videosink

https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html
set GST_DEBUG_DUMP_DOT_DIR=D:\work\gstreamer\gstdot
http://www.graphviz.org/doc/info/command.html

1
2
3
4
push
	upstream element calls downstream sink pads' gst_pad_push
pull
	downstream element calls upstream source pads' gst_pad_pull_range

pragma pack vs. cplusplus align

TAlignedBytes definition is picked from ue4,

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
typedef unsigned char uint8;
typedef int int32;
typedef unsigned int uint32;
 
template<int32 Size, uint32 Alignment>
struct TAlignedBytes; // this intentionally won't compile, we don't support the requested alignment
 
/** Unaligned storage. */
template<int32 Size>
struct TAlignedBytes<Size, 1>
{
	uint8 Pad[Size];
};
 
#define GCC_ALIGN(_align)
#define MS_ALIGN(n) __declspec(align(n))
 
// C++/CLI doesn't support alignment of native types in managed code, so we enforce that the element
// size is a multiple of the desired alignment
#ifdef __cplusplus_cli
#define IMPLEMENT_ALIGNED_STORAGE(Align) \
		template<int32 Size>        \
		struct TAlignedBytes<Size,Align> \
		{ \
			uint8 Pad[Size]; \
			static_assert(Size % Align == 0, "CLR interop types must not be aligned."); \
		};
#else
/** A macro that implements TAlignedBytes for a specific alignment. */
#define IMPLEMENT_ALIGNED_STORAGE(Align) \
	template<int32 Size>        \
	struct TAlignedBytes<Size,Align> \
	{ \
		struct MS_ALIGN(Align) TPadding \
		{ \
			uint8 Pad[Size]; \
		} GCC_ALIGN(Align); \
		TPadding Padding; \
	};
#endif
 
// Implement TAlignedBytes for these alignments.
IMPLEMENT_ALIGNED_STORAGE(16);
IMPLEMENT_ALIGNED_STORAGE(8);
IMPLEMENT_ALIGNED_STORAGE(4);
IMPLEMENT_ALIGNED_STORAGE(2);
 
#undef IMPLEMENT_ALIGNED_STORAGE

My test code is in vc2019 x64,

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
struct TTask
{
	char ch2;
	char ch3;
	double d4;
	__int64 i64;
};
 
#pragma pack(push, 1)
struct TTaskB
{
	char ch2;
	alignas(16) char ch3;
	double d4;
	__int64 i64;
};
struct AAa
{
	char ch1;
	TAlignedBytes<sizeof(TTask), alignof(TTask)> TaskStorage;
};
struct AAb
{
	char ch1;
	TTask TaskStorage;
};
#pragma pack(pop)
 
void CMFCApplication1Dlg::OnBnClickedButton1()
{
	__int64 sizeTTask = alignof(TTask);			// sizeTTask is 8
	__int64 sizeTTaskB = alignof(TTaskB);			// sizeTTaskB is 16
 
	AAa aa;
	TTask& Task = *(TTask*)&aa.TaskStorage;
	__int64 gapAAa = (char*)&Task - (char*)&aa;		// gapAAa is 8
 
	AAb bb;
	TTask& TaskB = *(TTask*)&bb.TaskStorage;
	__int64 gapAAb = (char*)&TaskB - (char*)&bb;		// gapAAb is 1
}

Let cpu fans be quiet when UE4 Editor is in front

Two methods to solve this,

  • Modify source code,
    D:\ue\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsPlatformApplicationMisc.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    #include <io.h>
    int doesFileExist(const char* filePath)
    {
    	int result = _access(filePath, 0);
    	if (result < 0)
    		return 0;
    	return 1;
    }
     
    bool FWindowsPlatformApplicationMisc::IsThisApplicationForeground()
    {
    	if (doesFileExist("d:/ue/not_focus.txt"))
    	{
    		return false;
    	}
     
    	uint32 ForegroundProcess;
    	::GetWindowThreadProcessId(GetForegroundWindow(), (::DWORD *)&ForegroundProcess);
    	return (ForegroundProcess == GetCurrentProcessId());
    }

    If d:\ue\not_focus.txt exists, whether UE4 Editor is active, UE4 will not occupy a cpu kernel thoroughly.

  • In D:\ue\Engine\Config\ConsoleVariables.ini, or in console, type

    1
    
    t.MaxFPS 5

refer to:
なんとなく日誌

Navigate to source location by writing code

UE4 has a functionality of "Goto Definition",

1
FSourceCodeNavigationImpl::NavigateToFunctionSource

which uses two apis from dbghelp.dll,

1
2
SymGetSymFromName64
SymGetLineFromAddr64

UE4 blueprint memo

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
Level Viewport
	bp_test
		Details
			Actor
				Tags
	Box Trigger
		Actor Hidden in Game
 
 
Level Blueprint
	1
		DestroyActor
	Event Tick
		Get All Actors with Tag
			Get Actor Location
			Set Actor Location
	Add Event for Trigger Box 1
		OnActorBeginOverlap
			cast to ThirdPersonCharacter
				begin_event
		OnActorEndOverlap
 
bp_test: Event Graph
	Event BeginPlay
		Exec
			Sequence
				Delay
					Print String
				Set Timer by Event
					Event
						test_event
					Return Value
						Promote to variable
							New Var 1
			If
				New Var 0
					true
						Print String
					false
						Print String
	Event Destroyed
	4
		New Var 1
			Clear and Invalidate Timer by Handle
	5
		Array Var 2
			For Each Loop
			Reverse for Each Loop
	6
		Struct Var 3 : Struct Type 3
			Break Struct Type 3
	7
		Enum Var 4 : Enum Type 4
			Switch on Enum Type 4
	Add Timeline
		Lerp Vector
			Set World Location
 
	test_event: Custom Event
		Exec
			Draw Debug Point
ThirdPersonCharacter : Event Graph
	begin_event: Custom Event
	Event Dispatchers
		hitDemon
	1
		hitDemon
Demon1 : Event Graph
	Get Player Character
		cast to ThirdPersonCharacter
			bind event to hitDemon
				add custom event
Demon1
	Details
		Collision
			Collision Presets
				Custom...
ThirdPersonCharacter : Blueprint
	Components
		ThirdPersonCharacter
			Use Controller Rotation Yaw
		CameraBoom
			Use Pawn Control Rotation
		CharacterMovement
			Orient Rotation to Movement
	1
		Capsule Component
			Get Word Location as Start
			Get Forward Vector
				x 10000
					+ Get World Location
						as End
							Line Trace By Channel
Get Player Controller
	Show Mouse Cursor
	ConvertMouseLocationToWorldSpace
 
Level Blueprint
	Q
		CubeMesh
			Static Mesh Component
				Create Dynamic Material Instance
					Set Vector Parameter Value
						Parameter Name : cube_color4
 
Mat_cube asigned to CubeMesh
	cube_color4 : Constant3Vector
		Base Color

In Actor Blueprint, enable input event,

1
2
3
4
bp_test: Event Graph
	Event BeginPlay
		Get Player Controller
			Enable Input

Questions,

  • Why can't 'Delay' function be used in 'While Loop'?
  • In Game mode, can't control previous character while incarnating into a new character?

    1
    2
    3
    4
    5
    
    ThirdPersonCharactor1
    	Details
    		Pawn
    			Auto Possess Player
    				Player 0

refer to:
我是一只好蛋YEAH
https://blog.csdn.net/sunday7279/article/details/88665577

strdupa in Windows

my_alloca.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef _MY_ALLOCA_H_
#define _MY_ALLOCA_H_
 
#include <malloc.h>
 
__declspec(thread) extern size_t strdupa_len;
__declspec(thread) extern char* strdupa_p;
#define strdupa(_str) \
( \
	strdupa_len = strlen(_str), \
	strdupa_p = (char*)_alloca(strdupa_len + 1), \
	memcpy(strdupa_p, _str, strdupa_len + 1), \
	strdupa_p \
)
 
#endif

my_alloca.c

1
2
3
#include "my_alloca.h"
__declspec(thread) size_t strdupa_len;
__declspec(thread) char* strdupa_p;

example.c

1
2
3
4
5
6
#include "my_alloca.h"
 
int main()
{
	char* p = strdupa("hi");
}