Retrieve all widgets after times of calling addWidget at same position

Don't call QGridLayout::itemAtPosition.

Like this,

1
2
3
4
5
6
7
8
9
10
11
12
for (int i = 0; i < grid_layout->count(); i++)
{
	QLayoutItem* item = grid_layout->itemAt(i);
 
	if (item->widget() == widget_wanted)
	{
		int row, column, row_span, column_span;
		grid_layout->getItemPosition(i, &row, &column, &row_span, &column_span);
 
		// grid_layout->addWidget(frame, row, column);
	}
}

C++ memo

Term

1
2
RTTI: Runtime Type Identification		// typeid
RAII: Resource Acquisition Is Initialization	// std::mutex

Blender source memo

1
2
3
4
5
6
7
8
9
10
#blender\source\blender\editors
ED_region_do_draw editors\screen\area.c
	outliner_main_region_draw editors\space_outliner\space_outliner.cc
		draw_outliner editors\space_outliner\outliner_draw.cc
			outliner_buttons
				UI_but_active_only editors\interface\interface.cc
					UI_but_active_only_ex
						ui_but_activate_event editors\interface\interface_handlers.c
							ui_do_button
								ui_do_but_TEX

Python Operator Precedence

The upper operators have higher precedence than the lower.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Grouping			()
Function call			f()
Slicing				[index:index]
Array subscription		[]
Bitwise NOT			~x
Unary plus/minus		+, -
Mul/Div/Mod			*, /, %
Add/Sub				+, -
Bitwise shift			<<, >>
Bitwise AND			&
Bitwise XOR			^
Bitwise OR			|
Relation			==, !=, >, >=, <, <=, is, is not, in, not in
				not
				and
				or
				lambda

refer to:
https://discuss.codechef.com/t/operator-precedence-table/14545

Stunning forbidden keyword about QSettings

1
2
3
4
5
    QSettings cfg(CONFIG_INI_PATH, QSettings::IniFormat);
    cfg.beginGroup("general"); // <-- other keywords are all ok.
    std::string val = cfg.value("itemCount").toString().toStdString();
    int video_count = cfg.value("itemCount").toInt();
    cfg.endGroup();

'general' keyword will lead 'val' to output empty in Qt5.15.2.

Notify us socket is ready after WSAEWOULDBLOCK

Two ways to achieve this goal:

  • Use select api.
  • Use WSAEventSelect and WSAWaitForMultipleEvents. This method is recommended, for we can add a cancellable event along with the socket for polling like GCancellable structure in glib. Cancellable architecture responds smarter than tangible waiting for the ending of sub-modules.

refer to:
gstreamer/subprojects/glib/gio/gsocket.c:g_socket_condition_timed_wait
https://blog.csdn.net/qq_30145355/article/details/78379969

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
3
D:\work\gstreamer\gstreamer\installed\include\gstreamer-1.0
D:\work\gstreamer\gstreamer\installed\include\glib-2.0
D:\work\gstreamer\gstreamer\installed\lib\glib-2.0\include

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