Grabbing frames from a Hikvision IP-camera
Asked Answered
H

2

6

I'm having problems with grabbing frames from a remote IP-camera. My employer wants it done in C# .NET (for Windows) and if possible to use a light-weight solution, i.e. not using any huge frameworks.

The device model is DS-2CD2632F-I, it us currently connected to my LAN and the camera's Web-interface works perfectly fine.

I already tried out several popular frameworks, e.g. AForge, EmguCV, OzekiSDK and Directshow.NET, but none of them seem to be working. Particularly the OzekiSDK (apparently, recommended by Hikvision?) isn't able to get a video stream from the camera, even if I simply use of the sample projects provided, which simply shows a black screen and throws an "Empty camera object" exception if I try to grab a frame.

The camera's Web-interface works correctly and even the VLC Player manages to successfully play the stream from the camera via a rtsp:// link (rtsp://my_ip:554//Streaming/Channels/1), without asking for the login and the password.

I thought about using libvlcnet, but I'm not sure it's a viable solution.

Do you have any recommendations?

Herschel answered 14/7, 2015 at 6:13 Comment(0)
H
11

Ok, so I think I figured it out. I'll post the solution here, in case someone needs it in future. I found out, that for this particular type of camera there is a url, that simply returns the current frame from the camera as a JPEG picture, which looks like this: http://IP_ADDRESS:PORT/Streaming/channels/1/picture?snapShotImageType=JPEG

Since my employer only needs to be able to grab one frame from the camera whenever he wants to and doesn't need to stream the video itself, I just wrote an application that copies this JPEG from that url by using an Async Web-Request:

private Bitmap loadedBitmap;
...
private void requestFrame()
{    
 string cameraUrl = @"http://192.168.0.1XX:80/Streaming/channels/1/picture?snapShotImageType=JPEG";
 var request = System.Net.HttpWebRequest.Create(cameraUrl);   
 request.Credentials = new NetworkCredential(cameraLogin, cameraPassword);
 request.Proxy = null;
 request.BeginGetResponse(new AsyncCallback(finishRequestFrame), request);
}

void finishRequestFrame(IAsyncResult result)
{
 HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
 Stream responseStream = response.GetResponseStream();

 using (Bitmap frame = new Bitmap(responseStream)) {
  if (frame != null) {
   loadedBitmap = (Bitmap) frame.Clone();                        
  }
 }
}
...
requestFrame(); // call the function
Herschel answered 14/7, 2015 at 18:57 Comment(1)
THANK YOU FOR POSTING THE SOLUTION IN 2015!!!!! <3. Only thing I see a little bit problematic with it, is that it's using (now) deprecated class, however rewriting to use HttpClient and HttpClientHandler is easy.Julejulee
J
1

After somebody wrote me an email, about the HttpClient implementation, I'm going to post it here :D. I was originally writing this to integrate with my asp.net core project, so this is created as a CameraService and used with Dependency injection as Scoped dependecy.

Just for the sake of this answear, I've picked the code, that's usefull universally, however I'll post my DI solution as well.

The only import required is this one:

using System.Net;

Solution:

public class CameraService
{
    private readonly string _cameraUrl;
    private readonly HttpClient _client;

    private readonly static string imgPath = @"C:\Path\To\Final\Image.jpg";

    public CameraService(string cameraUrl, string username, string password)
    {
        // Camera url is going to be something like this: @"http://192.168.0.1XX:80/Streaming/channels/1/picture?snapShotImageType=JPEG"
        if (cameraUrl == null) {
            throw new Exception("Camera connection url cannot be empty.");
        }

        if (username == null) {
            throw new Exception("Camera username credentials cannot be empty.");
        }

        if (password == null) {
            throw new Exception("Camera password credentials cannot be empty.");
        }

        _cameraUrl = cameraUrl;
        _client = new HttpClient(new HttpClientHandler() {
            Credentials = new NetworkCredential(username, password),
            Proxy = null
        });
    }

    public async Task GetImage()
    {
        // Get image from the camera
        Stream? responseStream = await _client.GetStreamAsync(_cameraUrl);
        if (responseStream == null) {
            throw new Exception("Unable to get image from camera.");
        }
        // Save it into a file
        using (FileStream fileStream = new FileStream(imgPath, FileMode.Create, FileAccess.Write, FileShare.Read)) {
            responseStream.CopyTo(fileStream);
        }
    }
}

Asp net core solution:

ICameraService.cs

public interface ICameraService
{
    public Task GetImage();
}

CameraService.cs

public class CameraService : ICameraService
{
    private readonly string _cameraUrl;
    private readonly HttpClient _client;

    // Basically just dynamically find where to place the image, could be hardcoded
    private readonly static string inputDirForAlpr = Path.Combine(Constants.baseAlprDirPath, "alpr_in");
    private readonly static string inputPathForAlprImg = Path.Combine(inputDirForAlpr, "camera_image.jpg");

    // Get all login info from asp net core config, can be hardcoded (however I don't recommend it, cuz of security and all that jazz)
    public CameraService(ILogger<CameraService> logger, IConfiguration configuration)
    {
        string? cameraUrl = configuration.GetSection("CameraSettings").GetValue<string>("Url");
        string? username = configuration.GetSection("CameraSettings").GetValue<string>("Username");
        string? password = configuration.GetSection("CameraSettings").GetValue<string>("Password");

        if (cameraUrl == null) {
            throw new Exception("Camera connection url cannot be empty.");
        }

        if (username == null) {
            throw new Exception("Camera username credentials cannot be empty.");
        }

        if (password == null) {
            throw new Exception("Camera password credentials cannot be empty.");
        }

        _cameraUrl = cameraUrl;
        _client = new HttpClient(new HttpClientHandler() {
            Credentials = new NetworkCredential(username, password),
            Proxy = null
        });
    }

    public async Task GetImage()
    {
        // Cleanup after previous rans
        if (Directory.Exists(inputDirForAlpr)) {
            Directory.Delete(inputDirForAlpr, true);
        }
        Directory.CreateDirectory(inputDirForAlpr);

        Stream? responseStream = await _client.GetStreamAsync(_cameraUrl);
        if (responseStream == null) {
            throw new Exception("Unable to get image from camera.");
        }
        using (FileStream fileStream = new FileStream(inputPathForAlprImg, FileMode.Create, FileAccess.Write, FileShare.Read)) {
            responseStream.CopyTo(fileStream);
        }
    }
}
Julejulee answered 30/7, 2022 at 11:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.