Creating C# application using Hikvision SDK for DS-7116HVI-SL

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hello again,

As I promised in previous post here is a small mapper which I have made for my purposes.

HIK SDK C++ - C#
WORD - ushort
DWORD - uint
LONG - int
char* - string
BYTE - byte
BOOL - bool
void* - IntPtr (if u want to assign null then use IntPtr.Zero)
LPVOID - IntPtr (if u want to assign null then use IntPtr.Zero)
HWND - IntPtr
wchar_t[] - StringBuilder (wchar_t[256] new StringBuilder(256))

Generally i have notices that any variable in Hik SDK with prefix LP is a pointer (to structures mostly) in that case we need to use ref keyword.
For example:
LONG NET_DVR_Login_V40( LPNET_DVR_USER_LOGIN_INFO pLoginInfo, LPNET_DVR_DEVICEINFO_V40 lpDeviceInfo);

struct
{ NET_DVR_DEVICEINFO_V30 struDeviceV30;
BYTE bySupportLock;
BYTE byRetryLoginTime;
BYTE byPasswordLevel; BYTE byRes1;
DWORD dwSurplusLockTime;
BYTE byCharEncodeType;
BYTE byRes2[255];
} NET_DVR_DEVICEINFO_V30,*LPNET_DVR_DEVICEINFO_V30;

As you can see LPNET_DVR_DEVICEINFO_V30 is a pointer type while NET_DVR_DEVICEINFO_V30 is non pointer type.
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hi curiousDev,

i tried and that didn't worked. I will test this on c++ console app to see if this function works.
Is it working for you in c++?
I was trying to do this and having soem problems as well. I found a method NET_DVR_GetDeviceAbility which should be able to check if some functionalities are available on certain device but i am having problems with this as well.
 

Vilius

n3wb
Joined
Aug 2, 2018
Messages
16
Reaction score
0
Location
Vilnius, Lithuania
I noticed interesting thing. Camera with one frame returns 34 calbacks. This is what i received:

Date/time/buffer size/ actual buffer size
2018-08-09 16:26:47, 116, 1
2018-08-09 16:26:47, 72, 1
2018-08-09 16:26:47, 20, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 5120, 1
2018-08-09 16:26:47, 3808, 1
2018-08-09 16:26:47, 112, 1

i'm not sure why, but callback always returns actual buffer with only 1 element...
 

Vilius

n3wb
Joined
Aug 2, 2018
Messages
16
Reaction score
0
Location
Vilnius, Lithuania
i think i have solution.
i have this callback structure:
public delegate void REALDATACALLBACK(int lPlayHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser);
pBuffer is pointer, which shows where my bytes are. Maximum number of bytes is 5120. So with every callback i receive 5120 bytes or less. Using Marshal i can copy bytes from memory to my Byte[] array. Last thing i have to do, is to make very long byte array and put everything together. Tomorrow i will try to make picture from that information
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
I got it working. It's kinda tricky to make it work properly.

Dont know why you didnt use normal version of NET_DVR_CapturePicture instead of NET_DVR_CapturePicture_V50 but i believe you had some reasons.

The NET_DVR_CapturePicture is much more easier and could be done within 5 mins.

Anyway I am going to share with both of solutions. It was quiet good chellenge for me and i couldnt take care of that earlier. Now after 2-3h struggling in total I got the solution.

Dll import:

[DllImport(@"\Hikvision\CppDlls\HCNetSDK.dll", EntryPoint = "NET_DVR_CapturePicture")]
public static extern bool NET_DVR_CapturePicture(int lRealHandle, string sPicFileName);

[DllImport(@"\Hikvision\CppDlls\HCNetSDK.dll", EntryPoint = "NET_DVR_CapturePicture_V50")]
public static extern bool NET_DVR_CapturePicture_V50(int lUserID, int lChannel, ref NET_DVR_PICPARAM_V50 lpPicParam, IntPtr sPicBuffer, uint dwPicSize, ref uint lpSizeReturned);

structure definitions:

public struct NET_DVR_PICPARAM_V50
{
public NET_DVR_JPEGPARA struParam;
public byte byPicFormat;
public byte byCapturePicType;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 254, ArraySubType = UnmanagedType.I1)]
public byte[] byRes;
}


public struct NET_DVR_JPEGPARA
{
/*Note: If encoding resolution is VGA, it supports grabbing 0=CIF, 1=QCIF, 2=D1 image.
But if encoding resolution is 3=UXGA (1600x1200) , 4=SVGA (800x600) , 5=HD720p (1280x720) , 6=VGA, 7=XVGA, and 8=HD900p it only support grabbing image with current resolution*/
/*
0-CIF, 1-QCIF, 2-D1, 3-UXGA(1600x1200), 4-SVGA(800x600),5-HD720p(1280x720),
6-VGA, 7-XVGA, 8-HD900p, 9-HD1080, 10-2560*1920,
11-1600*304, 12-2048*1536, 13-2448*2048, 14-2448*1200, 15-2448*800,
16-XGA(1024*768), 17-SXGA(1280*1024),18-WD1(960*576/960*480), 19-1080i, 20-576*576,
21-1536*1536, 22-1920*1920, 23-320*240, 24-720*720, 25-1024*768,
26-1280*1280, 27-1600*600, 28-2048*768, 29-160*120, 75-336*256,
78-384*256, 79-384*216, 80-320*256, 82-320*192, 83-512*384,
127-480*272, 128-512*272, 161-288*320, 162-144*176, 163-480*640,
164-240*320, 165-120*160, 166-576*720, 167-720*1280, 168-576*960,
500-384*288,
0xff-Auto(Use resolution of current stream)
*/
public ushort wPicSize;
public ushort wPicQuality; /* 0 - the best, 1 - better, 2 - average; */
}


calling 'normal' version (keep in mind it requires RealPlay) (not 100% sure but I guess it saves as bmp only):

string picPath = @"D:\Temp\pic.bmp";
bool picCaptured = SDKMethods.NET_DVR_CapturePicture(realPlayId, picPath);
if (!picCaptured)
{
string message = string.Format("RealPlay failed, error code: {0}\n", SDKMethods.NET_DVR_GetLastError());
Console.WriteLine(message);
result.AddError(message);
result.IsSuccessful = false;
SDKMethods.NET_DVR_StopRealPlay(realPlayId);
SDKMethods.NET_DVR_Logout(lUserID);
SDKMethods.NET_DVR_Cleanup();
return result;
}

calling V50 version (saves as jpg file):

NET_DVR_JPEGPARA jpegParam = new NET_DVR_JPEGPARA();
jpegParam.wPicQuality = 0;
jpegParam.wPicSize = 0xff;
NET_DVR_PICPARAM_V50 picParam_V50 = new NET_DVR_PICPARAM_V50();
picParam_V50.struParam = jpegParam;
picParam_V50.byCapturePicType = 0;
picParam_V50.byPicFormat = 0;
uint picSize = 2500 * 2048;
StringBuilder picBufferStr = new StringBuilder((int)picSize);
byte[] picBuffer = new byte[picSize];
IntPtr picBufferPtr = new IntPtr();
uint lpSizeReturned = 0;
int channel = 36;
picBufferPtr = Marshal.AllocHGlobal(picBuffer.Length);
Marshal.Copy(picBuffer, 0, picBufferPtr, picBuffer.Length);

bool picCaptured = SDKMethods.NET_DVR_CapturePicture_V50(lUserID, channel, ref picParam_V50, picBufferPtr, picSize, ref lpSizeReturned);
if (!picCaptured)
{
string message = string.Format("CapturePicture_V50 failed, error code: {0}\n", SDKMethods.NET_DVR_GetLastError());
Console.WriteLine(message);
result.AddError(message);
result.IsSuccessful = false;
SDKMethods.NET_DVR_Logout(lUserID);
SDKMethods.NET_DVR_Cleanup();
return result;
}
byte[] imageRawData = new byte[(int)lpSizeReturned];
Marshal.Copy(picBufferPtr, imageRawData, 0, (int)lpSizeReturned);
System.IO.MemoryStream buf = new System.IO.MemoryStream(imageRawData);
Image image = Image.FromStream(buf, true);
image.Save(@"D:\Temp\test.jpg");
 

Vilius

n3wb
Joined
Aug 2, 2018
Messages
16
Reaction score
0
Location
Vilnius, Lithuania
hi curiousDev,

none of those methods are good enough for me.
NET_DVR_CapturePicture saves picture in computer.
NET_DVR_CapturePicture_V50 saves in byte array, but it gives me only 1fps.. I need pictures in byte arrays but framerate should be as high as possible.
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hey Vilius,

Cannot you just call method NET_DVR_CapturePicture_V50 n times to get more frames? I wasnt trying trough but i think it might be a solution at least partial.
Similar to V50 is also NET_DVR_CapturePictureBlock_New so it might come with help.
 

Vilius

n3wb
Joined
Aug 2, 2018
Messages
16
Reaction score
0
Location
Vilnius, Lithuania
i tried, but it returns only one picture per second.
i guess i have to capture whole package and then try to decode from h.254 format. I am going to do c++ wrapper for that
 

Mechalec

n3wb
Joined
Jul 25, 2018
Messages
2
Reaction score
0
Location
Australia
Again, thanks to all that are contributing on this thread. It is extremely helpful. I have had some time away but only now revisiting my code.

I have managed to login successfully to my camera and start the live data stream. Reverted to C++ but will revert back to C# with the help from CuriousDev.

I am now confused as to what to do with that live video stream. (data only)

My main goal is to start a live stream to a camera and then save this to a file in what ever video format necessary (e.g MP4).

I open a stream to the camera and it responds by supplying a system header, it then starts streaming data, but I am unsure of how that data is packaged.
 
Last edited:

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hi Mechalec,

Try use NET_DVR_SaveRealData or NET_DVR_SaveRealData_V30 it requires to open realplay though but I am sure that is what u are looking for.
 

DannyDS

n3wb
Joined
Sep 25, 2017
Messages
7
Reaction score
0
I know its to do with video playback but its the only thread i've seen active involving the Hikvision SDK, has anyone had any experience with Net_DVR_StartListenV30?

When starting the listen i get error 109 - Alarm component is failed to upload

Ive got an old set of the SDK libraries from 2015 which when used instead allow me to start listening but has some errors with the alarm data recieved.

Any help appreciated, thanks
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hello DannyDS,

Like for me it looks like an error referencing to missing dll. Check previous posts I've made a screenshot of directory structure.
 

Vilius

n3wb
Joined
Aug 2, 2018
Messages
16
Reaction score
0
Location
Vilnius, Lithuania
Quick update.

i used PlayCtrl.dll

[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_GetPort(ref int Port);

[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_SetStreamOpenMode(int port, int mode);

[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_OpenStream(int nPort, IntPtr pFileHeadBuf, uint nSize, int nBufPoolSize);

[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_Play(int nPort, IntPtr hWnd);

[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_InputData(int nPort, IntPtr pBuf, uint nSize);

[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_GetJPEG(int nPort, IntPtr pJpeg, uint nBufSize, ref int pJpegSize);

[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_GetBMP(int nPort, IntPtr pBitmap, uint nBufSize, ref int pBmpSize);


this is my realDataCallback:

public void VideoCallback(int lPlayHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser)
{
if(dwDataType == 1)
{

if (!SDKMethods.PlayM4_GetPort(ref lPort))
{
return;
}
m_iPort = lPort;
if (dwBufSize > 0)
{
if (!SDKMethods.PlayM4_SetStreamOpenMode(lPort, Defines.STREAME_FILE)) //or just 1
{
return;
}

if (!SDKMethods.PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024 * 1024))
//Open stream
{
return;
}

if (!SDKMethods.PlayM4_Play(lPort, IntPtr.Zero)) //Start play
{
return;
}
}
}

else
{
if (dwBufSize > 0 && lPort != -1)
{
if (!SDKMethods.PlayM4_InputData(lPort, pBuffer, dwBufSize))
{

return;
}
if(dwBufSize == 20)
{
new Task(() => { GetImage(); }).Start();
}

}
}
}


public void GetImage()
{
int buffSize = 0;
bool rez = SDKMethods.PlayM4_GetBMP(lPort, AllocatedMem, 1280 * 720 * 5, ref buffSize);
//bool rez = SDKMethods.PlayM4_GetJPEG(lPort, AllocatedMem, 1280 * 720 * 5,ref buffSize);
byte[] Data = new byte[buffSize];
Marshal.Copy(AllocatedMem, Data, 0, buffSize);
try
{
using (image = Image.FromStream(new MemoryStream(Data)))
{
OnNewImageReceived();
//image.Save("output.jpg", ImageFormat.Png); // Or Png
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

also, dont forget to allocate memory IntPtr AllocatedMem = Marshal.AllocHGlobal(1280 * 720 * 5);

with these steps i am now receiving picture with around 300ms delay.

I have uploaded .rar archive with required dll
 

Attachments

Joined
Aug 17, 2018
Messages
6
Reaction score
1
Location
Belgium
does someone have experience with the functions NET_DVR_GetSTDAbility.

while i'm pretty sure the camera has unattendedBaggage capabilities i still get false and lpAbilityParam stays empty.

so far i have the following:

public struct NET_DVR_STD_ABILITY
{
IntPtr lpCondBuffer;
int dwCondSize;
IntPtr lpOutBuffer;
int dwOutSize;
IntPtr lpStatusBuffer;
int dwStatusSize;
int dwRetSize;
byte byRes;
}

[DllImport("HCNetSDK")]
public static extern bool NET_DVR_GetSTDAbility(int lUserID, int dwAbilityType, ref NET_DVR_STD_ABILITY lpAbilityParam);

int userId = CHCNetSDK.NET_DVR_Login_V30(...);
CHCNetSDK.NET_DVR_STD_ABILITY ability = new CHCNetSDK.NET_DVR_STD_ABILITY();
bool result = CHCNetSDK.NET_DVR_GetSTDAbility(userId, 3556, ref ability);
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hello wolfblaster,

Try this code.

dll import:
[DllImport(@"\Hikvision\CppDlls\HCNetSDK.dll", EntryPoint = "NET_DVR_GetSTDAbility")]
public static extern bool NET_DVR_GetSTDAbility(int lUserID, uint dwAbilityType, ref NET_DVR_STD_ABILITY lpAbilityParam);

structure definition:

public struct NET_DVR_STD_ABILITY
{
public IntPtr lpCondBuffer;
public uint dwCondSize;
public IntPtr lpOutBuffer;
public uint dwOutSize;
public IntPtr lpStatusBuffer;
public uint dwStatusSize;
public uint dwRetSize;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
public byte[] byRes;
}

call:

int bufferSize = 65535;
int channelNo = 36;
byte[] condBuffer = Encoding.Default.GetBytes(channelNo.ToString());
IntPtr condBufferPtr = new IntPtr();
condBufferPtr = Marshal.AllocHGlobal(4);
Marshal.Copy(condBuffer, 0, condBufferPtr, condBuffer.Length);
byte[] statusBuffer = new byte[bufferSize];
IntPtr statusBufferPtr = new IntPtr();
statusBufferPtr = Marshal.AllocHGlobal(statusBuffer.Length);
Marshal.Copy(statusBuffer, 0, statusBufferPtr, statusBuffer.Length);
byte[] outBuffer = new byte[bufferSize];
IntPtr outBufferPtr = new IntPtr();
outBufferPtr = Marshal.AllocHGlobal(outBuffer.Length);
Marshal.Copy(outBuffer, 0, outBufferPtr, outBuffer.Length);

NET_DVR_STD_ABILITY ability = new NET_DVR_STD_ABILITY();
ability.lpCondBuffer = condBufferPtr;
ability.dwCondSize = sizeof(uint);
ability.lpOutBuffer = outBufferPtr;
ability.dwOutSize = (uint)bufferSize;
ability.lpStatusBuffer = IntPtr.Zero;
ability.dwStatusSize = 0;
ability.dwRetSize = 0;
bool success = SDKMethods.NET_DVR_GetSTDAbility(lUserID, 3556, ref ability);
if (!success)
{
result.AddError(string.Format("Login failed, error code: {0}\n", SDKMethods.NET_DVR_GetLastError()));
result.IsSuccessful = false;
SDKMethods.NET_DVR_Logout(lUserID);
SDKMethods.NET_DVR_Cleanup();
return result;
}
byte[] rawData = new byte[bufferSize];
Marshal.Copy(outBufferPtr, rawData, 0, (int)ability.dwRetSize);
string abilityResult = Encoding.Default.GetString(rawData); //result in xml


I noticed that if device doesnt support certain functionality then it will return false and important is to check in this case what errors is giving SDKMethods.NET_DVR_GetLastError().
Those two values together will determine wheter it supports functionality or not.
Having value 17 (Parameter error) from SDKMethods.NET_DVR_GetLastError() will indicate errors with calling method NET_DVR_GetSTDAbility() and you should look for mistake in call.
For example if I choose to check functionality '3556' I am getting value 29 (Device operation failed).

In case when I switch one of input parameter let's assume ability.dwCondSize = sizeof(uint) * 2 it will result with false and SDKMethods.NET_DVR_GetLastError() will return 17 (Parameter error).

I Hope you know what I have on mind since this looks kinda confusing what I tried to explain.
 

Jivakula

n3wb
Joined
Sep 21, 2018
Messages
6
Reaction score
0
Location
Sofia, Bulgaria
Hi there, I am trying to get video from Hikvision DVR and camera but still get a error 64. I can login and read device info but with "NET_DVR_RealPlay_V40" I stopped. Here is my code:

private IntPtr real_play;
private void RealPlay_Hikvision(int channel)
{
//handle = videoPanel.Handle; // videoPanel is a pictureBox
real_play = handle;
callback = new VideoHelper.REALDATACALLBACK(RealDataCallBack_V30);
Hik_PrevInfo = new VideoHelper.NET_DVR_PREVIEWINFO();
Hik_ClientInfo = new VideoHelper.NET_DVR_CLIENTINFO();

if (play_video == true)
{
VideoHelper.NET_DVR_StopRealPlay(realPlayId);

videoPanel.Refresh();
play_video = false;
}

try
{
Hik_PrevInfo.hPlayWnd = real_play;
Hik_PrevInfo.lChannel = channel; //Preview channel NO.
Hik_PrevInfo.dwStreamType = 0; //0-main stream, 1-sub stream, 2-stream3, 3-stream4.
Hik_PrevInfo.dwLinkMode = 0; //0-TCP mode, 1-UDP mode, 2-Multi-play mode, 3-RTP mode, 4-RTP/RTSP, 5-RTSP over HTTP
Hik_PrevInfo.bBlocked = false;

IntPtr pUser = new IntPtr(Hik_PrevInfo.lChannel);

realPlayId = VideoHelper.NET_DVR_RealPlay_V40(Hik_LoginID, ref Hik_PrevInfo, null, pUser);

if (realPlayId < 0)
{
string message = string.Format("RealPlay_v40 failed, error code: {0}", VideoHelper.NET_DVR_GetLastError());
frmObject.frmMain.to_log(message);

var bmp = new Bitmap(videoPanel.ClientSize.Width, videoPanel.ClientSize.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawString(message, new Font("Verdana", (float)12, FontStyle.Bold, GraphicsUnit.Pixel), new SolidBrush(Color.Red), (float)20, (float)20);
g.Dispose();
}
videoPanel.Image = bmp;

VideoHelper.NET_DVR_StopRealPlay(realPlayId);

play_video = false;
}
else
{
play_video = true;
}
}
catch (Exception ex)
{
play_video = false;

frmObject.frmMain.to_log("Video player, Hikvision connect: " + camera_name + " - " + camera_ip + ":" + camera_port + " - " + ex.Message);

var bmp = new Bitmap(videoPanel.ClientSize.Width, videoPanel.ClientSize.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawString("Video player, Hikvision connect: " + camera_name + " - " + camera_ip + ":" + camera_port + " - " + ex.Message, new Font("Verdana", (float)12, FontStyle.Bold, GraphicsUnit.Pixel), new SolidBrush(Color.Red), (float)20, (float)20);
g.Dispose();
}
videoPanel.Image = bmp;

VideoHelper.NET_DVR_StopRealPlay(realPlayId);
VideoHelper.NET_DVR_Logout(Hik_LoginID);
VideoHelper.NET_DVR_Cleanup();
}
}

I appreciate any helps!
Thank you!
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hi Jivakula,

I already wrote a post about RealPlay_V40 check 1st page of this thread and you should find answer there.

EDIT:
Error 64 can be referring to missing HIK dll file. Make sure your file structure of HIK dlls is ok. Somewhere in previous posts I attached screenshots of this. Also keep in mind that SDK dlls in version x64 can cause a trouble which Vilius has encountered

Best regards
Curious
 
Last edited:
Top