Jump to content

Using the DLL files of an application compiled with C# with labview


Recommended Posts

Something caught my attention here.

-If I set 'dwDatatype' to 1 it returns output like this.image.png.d89aa95cb65fe8a69746684395f5d2d7.png

-If I set 'dwDatatype' to 2 it returns output like this.image.png.2b4db90ce6535247cb79ca54399d8f07.png

As you change the 'dwDataType' from 1 to 2 and run it again, the 'SetCbState return' number value increases. But if I run it again without changing the 'dwDataType', the value of ''SetCbState return'' remains constant. Is there any relation between the number returned by ''SetCbState'' and ''DwDataType''? Why does it have such an effect?

Link to comment

SetCbState returns nothing! Its return value is defined as void. That means that the function does not have a return value at all (in Pascal and Delphi such a function is called procedure). So after you set some return value for it in the CLFN settings, you keep getting some totally unrelated numbers, e.g. return values of some internal functions in LV core or whatever. It's useless to search for some correlations between that fictional return value and dwDataType. And even if there would be some connection (as after you change some constant and LabVIEW recompiles all and it affects the memory layout in some 'unusual' way), it's of no use absolutely.

6 hours ago, alvise said:

-I try as follows, but the size of the array does not remain constant, it constantly changes between 0 and 4350

It seems to be more complicated then. Honestly I even don't have an idea how and where to start from. Maybe you could collect several (or more) files with different sizes and upload them?

Edited by dadreamer
Link to comment

 

-I'm reviewing the example here. I guess the 'NET_DVR_SYSHEAD' package is required.

Quote

11 hours ago dadreamer said:
Maybe you can collect and upload a few different (or more) files?


-I couldn't quite understand what you said here, do you want me to record in my record before?

I took a few records as below and created a record with the normal button.

 

 

NET_DVR_STREAMDATA.rar

Edited by alvise
Link to comment
10 hours ago, alvise said:

-I'm looking at the example here. I think it is necessary to read the 'NET_DVR_SYSHEAD' package.

Maybe. I've been browsing their samples too. Looks like they use a custom MPEG-4 decoder. In NET_DVR_SYSHEAD case they just initialize the decoder as this is the very first frame. But seems that the actual pBuffer contents of the system header aren't used in any way. Or I'm wrong? Later in NET_DVR_STREAMDATA case they obtain the packets and render them into a separate window using that MP4 decoder. Maybe it would be easier to use it instead of reinventing not only a wheel, but an entire car. Could you try to #include "plaympeg4.h" header to your code and recompile? Do you receive any errors?

10 hours ago, alvise said:

I took a few records as below and created the records with a normal button.

Normal button is not suitable here due to the reasons I explained earlier. You could try to generate a random file name on each packet arrival (say, packet number or current date + time or something else), so the data gets recorded into a new file instead of being written to the same file.

Edited by dadreamer
Link to comment

 

12 minutes ago, dadreamer said:

Maybe. I've been browsing their samples too. Looks like they use a custom MPEG-4 decoder. In NET_DVR_SYSHEAD case they just initialize the decoder as this is the very first frame. But seems that the actual pBuffer contents of the system header aren't used in any way. Or I'm wrong? Later in NET_DVR_STREAMDATA case they obtain the packets and render them into a separate window using that MP4 decoder. Maybe it would be easier to use it instead of reinventing not only a wheel, but an entire car. Could you try to #include "plaympeg4.h" header to your code and recompile? Do you receive any errors?

Yes, I'm getting errors like the following. I'm looking at all the examples, similar examples have been created.

image.png.01174d35a8c1fe65a7267827f52d5755.png

plaympeg4.h

 

17 minutes ago, dadreamer said:

Normal button is not suitable here due to the reasons I explained earlier. You could try to generate a random file name on each packet arrival (say, packet number or current date + time or something else), so the data gets recorded into a new file instead of being written to the same file.

With the method you suggested, it is necessary to stop and restart the VI for each new package. It should be like this, right?

 

NET_DVR_STREAMDATA NEW.rar

Link to comment
7 minutes ago, alvise said:

Yes, I'm getting errors like the following.

It's difficult for me to find the errors source from your screenshot.

7 minutes ago, alvise said:

With the method you suggested, it is necessary to stop and restart the VI for each new package.

No. Just replace the filename string constant with your randomised filename and the frame will be recorded to a new file on each event.

Edited by dadreamer
Link to comment

 

When I make a change like below, it only saves one file, shouldn't it save a new file for each event iteration? Why does it only save one file? Is the method I'm using correct?

image.png.aa985b14488907a7631b43f49e05bf2f.png

1 hour ago, dadreamer said:

It's difficult for me to find the errors source from your screenshot.

These errors appear in the "plaympeg 4.h" file.

Quote

PLAYM4_API DWORD __stdcall PlayM4_GetSourceBufferRemain(LONG nPort);

Error    C4430    missing type specifier - int assumed. Note: C++ does not support default-int    hikLabview-0.0.01 

Quote

PLAYM4_API BOOL __stdcall PlayM4_Stop(LONG nPort);

Severity    Code    Description    Project    File    Line    Suppression State
Error    C2146    syntax error: missing ';' before identifier 'BOOL'    hikLabview-0.0.01      line 299    

-I think here is the reason for the error;
Because "BOOL" is written in capitals, if I write it small, the problem disappears, but I don't know if it creates a different problem.

Edited by alvise
Link to comment
16 hours ago, alvise said:

Something caught my attention here.

-If I set 'dwDatatype' to 1 it returns output like this.image.png.d89aa95cb65fe8a69746684395f5d2d7.png

-If I set 'dwDatatype' to 2 it returns output like this.image.png.2b4db90ce6535247cb79ca54399d8f07.png

As you change the 'dwDataType' from 1 to 2 and run it again, the 'SetCbState return' number value increases. But if I run it again without changing the 'dwDataType', the value of ''SetCbState return'' remains constant. Is there any relation between the number returned by ''SetCbState'' and ''DwDataType''? Why does it have such an effect?

That makes doubly no sense. Or you need to specify which dwDatatype you mean. First as dadreamer already explained and I tried to explain at least twice before.

Quote

If you want the function to return something you can't just configure the Call Library Node to return a value! You need to change the C code accordingly to actually return something. The last version you showed is declared to return void (or in other words nada, njet, nothing). What LabVIEW will return is simply the random value left behind in the EAX register by that function. That could be anything including your birthday!

Second,which dwDataType are you talking about? The dwDataType in the callback routine is not something you should change at all. It is what the SDK driver returns to you and that's it. That is the definition of a callback, it is called by the other software component with values that you should use, not manipulate unless the callback function documentation states explicitly that you are expected to return some data in one or more of the passed in buffers.

Link to comment
16 minutes ago, alvise said:

Problem solved. "play mpeg 4.h" no longer crashes, it can be compiled.
The cause of the error was the line here.It was only necessary to leave a space.

 #define PLAYM4_API  extern "C" __declspec(dllexport) 

Of course, and where did you get that header from? It can never compile in any C compiler that I know of. But it would help if you use generally accepted terms in your communication. A CRASH is something that occurs AFTER you have COMPILED and LINKED your application and start it. I usually means that your process dies with or without an according error message. What you encountered was a COMPILE ERROR since the compiler could not understand the code statement.

Edited by Rolf Kalbermatter
Link to comment
22 minutes ago, Rolf Kalbermatter said:

Second,which dwDataType are you talking about? The dwDataType in the callback routine is not something you should change at all. It is what the SDK driver returns to you and that's it. That is the definition of a callback, it is called by the other software component with values that you should use, not manipulate unless the callback function documentation states explicitly that you are expected to return some data in one or more of the passed in buffers.

image.png.9204883e29e0c05121d6f2a18b983149.png Are you saying it's unnecessary to send any value to "dwDataType" like in the photo?

 

23 minutes ago, Rolf Kalbermatter said:

Of course, and where did you get that header from?

This header is available in the provided SDK files.

33 minutes ago, Rolf Kalbermatter said:

It can never compile in any C compiler that I know of. But it would help if you use generally accepted terms in your communication. A CRASH is something that occurs AFTER you have COMPILED and LINKED your application and start it. I usually means that your process dies with or without an according error message. What you encountered was a COMPILE ERROR since the compiler could not understand the code statement.

.After importing the ''play mpeg 4.h'' header in the C++ code, an error occurred, I wanted to say that this compilation error has disappeared.

Yes it was a compilation error.Sorry,I have problems with some terms :)

I'm looking at this sample code as I don't have a solution at the moment. How can we use this sample code to achieve the desired result?

Link to comment
4 hours ago, dadreamer said:

No. Just replace the filename string constant with your randomised filename and the frame will be recorded to a new file on each event.

image.png.b3aa2cf1ae6f80355a8cab96c8a434f2.png

I made a change as below and noticed the results are somewhat interesting. Records 1 to 3 and values 3 to 6 look alike.It looks like a loop.

 

NET_DVR_STREAMDATA-125.rar

Edited by alvise
Link to comment
3 hours ago, alvise said:

When I make a change like below, it only saves one file, shouldn't it save a new file for each event iteration? Why does it only save one file? Is the method I'm using correct?

- The "1" case is for NET_DVR_SYSHEAD capture, but you assign NET_DVR_STREAMDATA name inside it; the "2" case is for NET_DVR_STREAMDATA capture.

- You have unwired tunnel for blue wire in some frames of the Event Structure. Don't you see that small rect is not painted completely?..

49 minutes ago, alvise said:

Are you saying it's unnecessary to send any value to "dwDataType" like in the photo?

It's senseless! You can input any values in that cluster constant and this changes literally nothing. This constant is only to define the User Event data type and that's all.

51 minutes ago, alvise said:

I'm looking at this sample code as I don't have a solution at the moment. How can we use this sample code to achieve the desired result?

So can you call the functions from the PlayM4 SDK now? You need to find a suitable function to decode the stream and receive a ready-to-use bitmap or pixels array. I don't know exactly which one is okay as I can't find the documentation (but I barely searched, to be honest, because was busy today).

Ok, I found these:

//get bmp or jpeg
PLAYM4_API BOOL __stdcall PlayM4_GetBMP(LONG nPort,PBYTE pBitmap,DWORD nBufSize,DWORD* pBmpSize);
PLAYM4_API BOOL __stdcall PlayM4_GetJPEG(LONG nPort,PBYTE pJpeg,DWORD nBufSize,DWORD* pJpegSize);

Do you have them in your headers?

Link to comment
10 minutes ago, dadreamer said:

- The "1" case is for NET_DVR_SYSHEAD capture, but you assign NET_DVR_STREAMDATA name inside it; the "2" case is for NET_DVR_STREAMDATA capture.

- You have unwired tunnel for blue wire in some frames of the Event Structure. Don't you see that small rect is not painted completely?..

It's senseless! You can input any values in that cluster constant and this changes literally nothing. This constant is only to define the User Event data type and that's all.

-I set it that way because ''dwDataType'' never returns a value of 1.

image.png.ba5e864db89cff2518ae927faa46c867.png-After the explanations above, I stopped assigning a value to the cluster elements. I fixed it.

15 minutes ago, dadreamer said:

 

So can you call the functions from the PlayM4 SDK now? You need to find a suitable function to decode the stream and receive a ready-to-use bitmap or pixels array. I don't know exactly which one is okay as I can't find the documentation (but I barely searched, to be honest, because was busy today).

Ok, I found these:

//get bmp or jpeg
PLAYM4_API BOOL __stdcall PlayM4_GetBMP(LONG nPort,PBYTE pBitmap,DWORD nBufSize,DWORD* pBmpSize);
PLAYM4_API BOOL __stdcall PlayM4_GetJPEG(LONG nPort,PBYTE pJpeg,DWORD nBufSize,DWORD* pJpegSize);

Do you have them in your headers?

Yes the header file contains these calls but I don't know how to use them in C++ code. I will try to do that.

Link to comment
11 minutes ago, alvise said:

Yes the header file contains these calls but I don't know how to use them in C++ code. I will try to do that.

In order to use them you need to adapt the callback function as shown in their examples:

void CALLBACK g_RealDataCallBack_V30(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer,DWORD dwBufSize,DWORD dwUser)
{
    HWND hWnd = GetConsoleWindow();

	switch (dwDataType)
	{
	case NET_DVR_SYSHEAD: //系统头

		if (!PlayM4_GetPort(&lPort))  //获取播放库未使用的通道号
		{
			break;
		}
		//m_iPort = lPort; //第一次回调的是系统头,将获取的播放库port号赋值给全局port,下次回调数据时即使用此port号播放
		if (dwBufSize > 0)
		{
			if (!PlayM4_SetStreamOpenMode(lPort, STREAME_REALTIME))  //设置实时流播放模式
			{
				break;
			}

			if (!PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024*1024)) //打开流接口
			{
				break;
			}

			if (!PlayM4_Play(lPort, hWnd)) //播放开始
			{
				break;
			}
		}
	case NET_DVR_STREAMDATA:   //码流数据
		if (dwBufSize > 0 && lPort != -1)
		{
			if (!PlayM4_InputData(lPort, pBuffer, dwBufSize))
			{
				break;
			} 
		}
	}
}

But there are a lot of things to be reworked as well.

- You will need to prepare a proper bitmap buffer to have your pixels loaded into.

- You will likely need to replace or complement PlayM4_InputData call with PlayM4_GetBMP / PlayM4_GetJPEG call.

- You will need to remake PostLVUserEvent call and some other functions around it.

Edited by dadreamer
Link to comment

In any case, it is necessary to read the data "NET_DVR_SYSHEAD", right?Currently it still can't read the NET_DVR_SYSHEAD information. Isn't that a problem?image.png.ff228596d1f1592817c68002e145b545.png

 


-What is your suggestion? Shall I switch to using the ''plaympeg4.h'' header?
If we use this header, I think we will also solve the problem of decoding H.264-MPEG4.

Edited by alvise
Link to comment
4 hours ago, alvise said:

Isn't that a problem?

If you're planning to implement PlayM4 API in your code, then yes. You won't be able to get NET_DVR_SYSHEAD called. But I don't know why it suddenly stopped working on your side. Maybe when you have switched from NET_DVR_SetRealDataCallBack to NET_DVR_SetStandardDataCallBack... You may try switch back just for a test. Or insert something like this into the beginning of your DataCallBack:

if (dwDataType==1) DbgPrintf("NET_DVR_SYSHEAD received");

 

Link to comment

1-) 

By the way, ''dwDataType'' only returned 1 once, otherwise it always returned 2.

I am getting output as below. But still value 1 is not returned and therefore I could not create NET_DVR_SYSHEAD packet save.

image.png.8a2a78514948bec795bd06160615e0f0.png

image.png.074e584d91c41707282846d6af101f45.png

 

2-)

While trying to understand (which I still don't understand) how to modify the C++ code, one more thing caught my attention.
There is a dll file like below, isn't there a shorter way to get video stream information using it?
The function names in this dll file match the function names shown in the sample code here, and there is also a user guide of this dll file as below.
Of course, a callback is required under all circumstances.

 

PlayCtrl.dll Windows Player SDK Programmer Manual (Version 6.2.XX).pdf

Edited by alvise
Link to comment
22 minutes ago, alvise said:

There is a dll file like below, isn't there a shorter way to get video stream information using it?

Yes, PlayM4 headers appear to be a C wrapper around that DLL. So it could be called even from the Event Structure, thus no C code modifications needed. But you need to receive NET_DVR_SYSHEAD in LabVIEW somehow, because it sends a MPEG-4 header, based on which the stream gets decoded later. So you need to figure out what happens in NET_DVR_SYSHEAD case in your DLL and why the event is not posted.

So, try to move that DbgPrintf condition to the if (cbState == LVBooleanTrue) {...} and check this. Then if it's called OK, after NumericArrayResize add something like this:

if (dwDataType==1) DbgPrintf("NumericArrayResize returned %d", err);

Check this then. And so on. Keep debugging until you find something.

Edited by dadreamer
Link to comment

 

image.png.4e2843cd92ab6f47a83e80440bcdbdce.png

I ran a test as you said and nothing is returned. 

I think I found the cause of the problem. Setting the status "cbState" to true false with the stream button in the stream fram was causing problems.

image.png.d1608c92f9eb238345ec0e98adae4093.png

It's an interesting situation... If I press the '''STOP'' button directly without disabling the 'STREAM' button (receiving data), then when 'START' button is pressed again (beacuse I set  "cbState" the constant True  function of the ''STREAM'' ), the data is directly initialized to NET_DVR_SYSHEAD However, if I send true-false to the "cbState" function in the "Stream" frame with the button, the "NET_DVR_SYSHEAD" value will not be read, but the stream can be stopping and restarting.

Edited by alvise
Link to comment

It was obvious. Strange that we couldn't get to it so long. I think the easiest way would be to alter the callback condition like this.

if (cbState == LVBooleanTrue || dwDataType == 1)
{
}

In this case the NET_DVR_SYSHEAD packet will be posted regardless of the state of cbState button. You should receive it right after starting the playback.

Edited by dadreamer
Link to comment
30 minutes ago, dadreamer said:

It was obvious. Strange that we couldn't get to it so long. I think the easiest way would be to alter the callback condition like this.

In this case the NET_DVR_SYSHEAD packet will be posted regardless of the state of cbState button. You should receive it right after starting the playback.

You're talking about the time here, right?image.png.d9bf7655334681d1b31864d4c730aa73.png

I changed it as you said. The feedback comes directly when I press the Start button and it can save the header file.

image.png.37a27e56c9adcd3484d59ed0c29a4c99.png

I guess there is no need to save ''NET_DVR_STREAMDATA''.

NET_DVR_SYSHEAD1.txt

Edited by alvise
Link to comment
11 hours ago, alvise said:

image.png.9204883e29e0c05121d6f2a18b983149.png 

Are you saying it's unnecessary to send any value to "dwDataType" like in the photo?

I'm saying you send NOTHING there.  This is the definition of the user event datatype and what you "send" there into that cluster makes absolutely no difference. You could just as well leave the entire Bundle by Name away. What is important is the data type that the LVEventData element defines, nothing else. And this data type must at ALL times match the data type setup on the C side for the user event data structure or VERY BAD things will happen.

Edited by Rolf Kalbermatter
Link to comment

"IMKH" FourCC says it's MPEG-PS format. Most decoders should recognize it. Now you can build some logic around PlayCtrl.dll or any other decoder such as ffmpeg.

2022-06-07_10-03-21.jpg.add3305e34cbe1687fd4024102f61d53.jpg

Use that HikVision example and Windows Player SDK Programmer Manual to implement the decoder calls.

Link to comment
9 hours ago, Rolf Kalbermatter said:

I'm saying you send NOTHING there.  This is the definition of the user event datatype and what you "send" there into that cluster makes absolutely no difference. You could just as well leave the entire Bundle by Name away. What is important is the data type that the LVEventData element defines, nothing else. And this data type must at ALL times match the data type setup on the C side for the user event data structure or VERY BAD things will happen.

Thanks for the reply. I changed it like this.

image.png.4765e330a89592bd13d2d4701b5c57cc.png

4 hours ago, dadreamer said:

Use that HikVision example and Windows Player SDK Programmer Manual to implement the decoder calls.

I created it as you suggested. But there are 2 things I can't understand.
-For "BYTE *pBuffer", is it necessary to convert the "Handle" array to string and then convert it back to U32 number?
- For ''if (!PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024*1024))'', is it necessary to transmit the result of multiplying the number here with ''1024*1024''?

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.