Jump to content

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


Recommended Posts

2 hours ago, alvise said:

Yes,but  it was causing trouble every time. It was crashing Labview so I didn't add it later because I thought it wasn't necessary.

It absolutely is needed. How should the decoder otherwise get the compressed data to actually get image data????

You have no idea what you are doing here and will never get anywhere in this way. You do not understand what data comes from where, where it should go and how that all relates to each other.

1) The NET_DVR functions are the functions that communicate with the camera. 

2) You can let them draw directly into a window handle. Fairly easy and works as proven already.

3) You can instead (or in addition) install a callback function which is called whenever there is a data package from the camera and that data is passed to that callback.

3a) This data is compressed in the camera in some way, in your case it seems to be MPEG4 data but it could be also another compression.

3b) When you have determined that it is the HKMI (apparently their HikVision Media data  Identifier) datastream in the SYSHEAD message, you need to pass this data to their decoder, this are your PlayM4 functions. If you do not pass those data packages to the MPEG4 decoder stream it has NOTHING to decode and therefore can NOT return any image data ever!!!!!

3c) This passing of the compressed data packages happens with the PlayM4_InputData() method. This function hands the received data do the decoder which then buffers it until it has a complete frame and then decodes that frame and probably, maybe, possibly, hopefully or something stores it in a different buffer in its port (handle) as a decoded frame buffer. 

3d) Only once a complete frame has been received and decoded, can you hope to get something back from the PlayM4_GetJPEG() or one of the other PlayM4_Get****() functions.

If you would not keep putting only images in your post, I might be tempted to give every now and then a fixed VI but I'm not feeling inclined to try to debug images and fix them.

image.png.36a05dee070c0ab2ad0e019618b35d1e.png.2607ec531919b06f999cba5904d952f2.png.03e160dd4015ba81fab284d6e99fa5fb.png

Something like this MIGHT work. But there is no guarantee and I can not find any documentation for those functions, not even in bad English. The idea is that the function is called with an empty array buffer and a 0 nBufSize, then on return it MIGHT return a TRUE status if there is a full frame available or it might NOT. If it returns true then the last parameter is hopefully valid and can be used to determine what size of buffer needs to be allocated and then the function is called again with that buffer. If it does not return true you should not even try to interpret the returned last parameter.

Another possibility MIGHT be to use the PlayM4_GetPictureSize() function. It returns a height and width value. Multiply those and multiply the result with 4 which hopefully should be enough for an entire picture buffer. The code in the Client Demo application does a bit more elaborate calculation for this, naemly:

size = 3 * (4 * lWidth * lHeight + 100)

It then calls PlayM4_GetJPEG() with a buffer allocated to that size, and the size value. And if PlayM4_GetJPEG() does not return true it did not return an image, no matter what. Maybe because there is not yet a full data frame to decode, maybe because one of the maybes up to now in above text didn't hold true, or some other bad luck or whatever.

However even if this eventually works you have another problem. You have data in JPEG format, yet another compressed format that you still can't do much with. Sure you can decompress it with one of the earlier mentioned JPEG Stream to LabVIEW pixmap functions but it is getting now pretty complicated and multi-decoding and multi layer and therefore slooooooooooooooooow.

There seems to be another method which uses yet another callback!! Yupee!!

Looking at the Client Example JPEGPicDownload.cpp file you may have to actually use PlayM4_SetDecCallBack() to install a new callback function that is called when a full frame has been decoded. Fuuuuuuuuuun! This full frame seems to be fully decoded, so this COULD be converted into an IMAQ Vision image for instance. How? How many more weeks do you have for this available?

PS: The StandardCallback I tried to use in my original code only works if the camera supports RTP according to the SDK documentation, so yours may not support that.

Edited by Rolf Kalbermatter
Link to comment

That's how some guy did that in Delphi.

function GetBMP(playHandle: Longint): TBitmap;
var rbs: PDWORD;
     ps: PChar;
     i1,i: longint;
     bSize: DWORD;
     ms: TMemoryStream;
begin
   try
     result := TBitmap.Create();
     if playHandle < 0 then exit;
     bSize := 3000000;
     ms := TMemoryStream.Create;
     new(ps);
     GetMem(ps,bSize);
     new(rbs);
     if PlayM4_GetBMP(playHandle,ps,bSize,rbs) then begin
       i1 := rbs^;
       if i1>100000 then begin
         ms.WriteBuffer(ps[0],i1);
         MS.Position:= 0;
         result.LoadFromStream(ms);
       end;
     end;
   finally
     FreeMemory(ps);
     FreeMemory(rbs);
     ms.Free;
     ps :=nil;
     rbs := nil;
     ms := nil;
   end;
end;

But that bSize := 3000000; looks not an elegant enough, so I'd suggest using PlayM4_GetPictureSize and calculating the final buffer size as

sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + w * h * 4

But you may test with that for now to make sure everything is working. Another option would be to use the DisplayCallback, that is set by PlayM4_SetDisplayCallBack. There the frames should already be decoded and in YV12 format, therefore you'd have to convert them to a standard RGBA or any other format of your liking.

Link to comment
33 minutes ago, dadreamer said:

That's how some guy did that in Delphi.

function GetBMP(playHandle: Longint): TBitmap;
var rbs: PDWORD;
     ps: PChar;
     i1,i: longint;
     bSize: DWORD;
     ms: TMemoryStream;
begin
   try
     result := TBitmap.Create();
     if playHandle < 0 then exit;
     bSize := 3000000;
     ms := TMemoryStream.Create;
     new(ps);
     GetMem(ps,bSize);
     new(rbs);
     if PlayM4_GetBMP(playHandle,ps,bSize,rbs) then begin
       i1 := rbs^;
       if i1>100000 then begin
         ms.WriteBuffer(ps[0],i1);
         MS.Position:= 0;
         result.LoadFromStream(ms);
       end;
     end;
   finally
     FreeMemory(ps);
     FreeMemory(rbs);
     ms.Free;
     ps :=nil;
     rbs := nil;
     ms := nil;
   end;
end;

But that bSize := 3000000; looks not an elegant enough, so I'd suggest using PlayM4_GetPictureSize and calculating the final buffer size as

sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + w * h * 4

But you may test with that for now to make sure everything is working. Another option would be to use the DisplayCallback, that is set by PlayM4_SetDisplayCallBack. There the frames should already be decoded and in YV12 format, therefore you'd have to convert them to a standard RGBA or any other format of your liking.

I don't understand Delphi very well.

I've added the VI's I've been working on. There's really nothing I'm doing wrong, right?

Quote

sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + w * h * 4

-Where did "BITMAPFILEHEADER" and "BITMAPINFOHEADER" come from here?

 

It makes more sense to use "PlayM4 Set Display CallBack" but I guess that requires a new effort. Right?

 

Link to comment

I slightly modified your VI, try it.

Preview CAM.vi

1 hour ago, alvise said:

Where did "BITMAPFILEHEADER" and "BITMAPINFOHEADER" come from here?

These are Windows API bitmap definitions. In 32-bit IDE they are 14 bytes and 40 bytes long respectively. So the final formula should be 54 + w * h * 4. But it is valid only if you will use PlayM4_GetBMP! For JPEG format there's a different header length to be defined.

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

Doesn't this work also? Do you ever see PlayM4_GetJPEG returning 1 sometimes?

I'm afraid that doesn't work. It was an idea based on the fact that this function does return a size in its last parameter. If it was a Microsoft API it would work like that, and there was a reasonable chance that they would have followed the model of Microsoft APIs but alas, it seems not the case. It would have been to simple. 😃

I think you have to use the PlayM4_GetPictureSize() to calculate a reasonably large buffer and allocate that and pass it directly to the PlayM4_GetJPEG() function to MAYBE make it work.

Link to comment
3 minutes ago, Rolf Kalbermatter said:

I think you have to use the PlayM4_GetPictureSize() to calculate a reasonably large buffer and allocate that and pass it directly to the PlayM4_GetJPEG() function to MAYBE make it work.

He already tried to allocate a huge buffer of 3000000 bytes. This buffer is definitely large enough to hold not only a single JPEG content, but even a several BMP ones. But this doesn't work as well.

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

You could try to switch to PlayM4_GetBMP, but I assume it gives nothing new. This is odd that even the last error number is zero.

No it may not be. Last error values are notoriously tricky to handle in multithreading code and LabVIEW is highly multithreading. Even if they are stored in thread local storage as do the Microsoft APIs, they are difficult to handle in LabVIEW as your call to GetLastError() is potentially executed in a different thread than the previous call that caused an error and voila you are reading the last error from some completely different function call. And if you force all calls into the UI thread you are in fact calling the functions all in the same thread but between the call to the error causing function and the retrieval of the last error there could be zillion other calls that might have overwritten that last error value already. Same problem exists independent of how the functions are called when the library only maintains a global last error value. If this library has a thread safe last error value or not is not documented as far as I remember.

And are you sure that the PlayM4 APIs make use of the NET_DVR_GetLastError()? If so they are almost certainly thread local storage and you need to make sure that all the functions execute in the same thread. But with call backs going on in the background there could be all kinds of things going on in the time between calling the PlayM4_GetJPEG() function and the NET_DVR_GetLastError() one.

No it has its own PlayM4_GetLastError(long nPort) function! And since it takes the port (handle) as a parameter it is most likely thread context safe as the error is apparently stored in the port somehow.

Edited by Rolf Kalbermatter
Link to comment
Posted (edited)
22 minutes ago, dadreamer said:

You could try to switch to PlayM4_GetBMP, but I assume it gives nothing new. This is odd that even the last error number is zero.

Yes, interesting things one after the other :)However, there is such a function here.
But I see that there are many dll files in SDKs. I think there must be an easy way somewhere.

Edited by alvise
Link to comment
Posted (edited)
1 hour ago, dadreamer said:

@alvise Based on what Rolf said try to run this VI and report the PlayM4_GetJPEG Error Number.

image.png.e103d7d9586d698b0095ea3784303954.png

Returns 2 values.

image.png.a4e725630541a37f9d5613be4bd443da.png

image.png.a55e5a81f334aefc981f6664f6bbfb93.png

But if I take a little long to get the stream it returns 34.

image.png.48a43b996f1638411829c26727533d07.png

Edited by alvise
Link to comment
Posted (edited)
20 minutes ago, Rolf Kalbermatter said:

Well 2 means there is no data yet to work with, 34 means PLAYM4_NEED_LARGER_BUFFER. Seems obvious what's the problem here.

How can we solve this?

 

image.png.7c56538d351d0b813381ac7000503895.png

image.png.1538ecb29d8e7b5a39f7ac984af0dc1d.png

if i add the number ''20130528'' here
I get an output like below but it's just outputting an image and labVIEW is getting heavy.

image.png.0d831774213a384febc7580bdd5b4d0a.png

Edited by alvise
Link to comment
1 hour ago, alvise said:

if i add the number ''20130528'' here

:o

It's date when pzj coder added that define to the header. :D

1 hour ago, alvise said:

I get an output like below but it's just outputting an image

What do you mean?..

Edited by dadreamer
Link to comment
Posted (edited)
12 minutes ago, dadreamer said:

:o

It's date when pzj coder added that define to the header. :D

What do you mean?..

Yes it's a big number  :D

The array fills the specified size. I can't close the VI unless the array is already finished with the specified size. labVIEW freezes. But I mean, the numbers don't change and that's why I only treated it as 1 image :)

What do you think is the real solution here?

Edited by alvise
Link to comment

Well, I see from your data that you're finally getting a valid JPEG stream. Can you save that pJpeg array into a binary file and open it in a viewer? Just to make sure it's the cam image. And now you need to figure out the proper array size so the GetJPEG function wouldn't error on you anymore. And in your "Stop" frame you should accomplish the cleanup procedures such as stopping the playback, freeing the port etc. Just find the opposite functions according to your UserEvent frame calls.

Edited by dadreamer
Link to comment
Posted (edited)

Ok, I will follow what you said step by step.

1 hour ago, dadreamer said:

And now you need to figure out the proper array size so the GetJPEG function wouldn't error on you anymore.

I guess I need to find the correct array size first because if I press the 'Stream' button, the VI ''pJpegSize'' does not allow pressing the 'stop' button until the specified array size is reached. Because the labVIEW becomes heavy.
Therefore, I will try to find the right ''pJpegSize''first.
I created a test with different values to find the array size, either I get error 34 or the problem I mentioned above occurs.
Do you have any suggestions for finding the array size?

Edited by alvise
Link to comment
1 hour ago, alvise said:

Do you have any suggestions for finding the array size?

Only those stated in the documentation.

Quote

pJpeg [in] Address assigned by users for storing JPEG data, no less then jpeg file size: suggested w * h * 3/2, in which w and h stand for the width and height of the image.

This is the minimum size required. But it may occur that this size is not enough - this needs some testing on your side. If you would use BMP, then there's a more or less precise formula, but BMPs are quite larger in size, as you know.

Also I, as Rolf did few posts ago, suggest using PlayM4_GetPictureSize function to know the actual image size. Insert it between InputData and GetJPEG nodes.

2 hours ago, alvise said:

I can't close the VI unless the array is already finished with the specified size. labVIEW freezes.

Are you saying that those GetJPEG/GetBMP functions are synchronous and don't return until the buffer is filled? What if you switch all the HikVision and PlayM4 CLFNs from UI thread to any thread (yellow coloring)? Then it would run in another thread and not freeze the GUI.

Edited by dadreamer
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.