Wiris Ethernet Stream SDK Programming Guide

SUPPORT

WIRIS Ethernet Stream SDK Programming Guide​

Introduction

WIRIS Ethernet Stream SDK Guide is designed to stream video from the WIRIS and to control it via an Ethernet connection. The WIRIS camera runs the TCP/IP server, which can be controlled using simple text commands. Please refer to the SDK manual for a detailed description of the communication protocol.

In this guide, we will create a sample application that can communicate with the camera via text commands. We will use Boost ASIO library (https://www.boost.org/) for that purpose. However, you can also use another library that supports network programming.

1.

Create a new C++ project in your IDE and link the boost ASIO library. If you are using Visual Studio, add boost and include files to Additional Include Directories and binaries to Additional Dependencies in Project Properties.

2.

Create a new class Network Client, which will implement sending commands. 

1 manual
Figure 1 NetworkClient Class

Copy the code for the NetworkClient from the pastebin: https://pastebin.com/fbrmu37b

3.

Now we are ready to use the NetworkClient to communicate with the WIRIS device. In the main source file, create a function for sending commands through NetworkClient, which will also print a response.

2 manual
Figure 2. Function to send messages using NetworkClient

4.

Now we can test communication with commands. Verify that you have the correct license code for Ethernet mode activation. You can activate Ethernet mode using native camera firmware and by using commands (Figure 2).

 
3 manual
Figure 3 Sending commands to enable Ethernet mode and obtain information about the camera
4 manual
Figure 4. Sending commands for zoom control, setting palettes, thermal parameters and stream capture

5.

After running this sample code, you can check all WIRIS responses and make sure everything works correctly by reading the program standard output (the console output).

 

Example

For example, in the Ethernet Stream SDK GUI, the application workflow is as following: 

1.

The first step is to call the connect method, with the WIRIS IP address as passed argument

 


bool ControllerCore::connect(const QString& ip)
{
    //network client class takes care of TCP layer of application
    //it takes wiris ip and communication port(2240) as constructor parameters
    //from now on it is fairly easy to call method send on network client instance with any command as parameter
    //network client should automatically disconnect from WIRIS in its destructor
    if(this->_networkClient == nullptr || !*this->_networkClient || !_connected)
        _networkClient = std::shared_ptr(new NetworkClient(ip.toStdString(), this->_endpointPort.toStdString()));

    if (*_networkClient)
    {
        std::istringstream iss;
        //Sending test message
        if(!send("HIWS\n", iss) || !isPositive(iss.str()))
            return false;

        //Setting delimiter to null character
        send("SDLM NULL\n");

        //checking camera type
        fetchBasicInfo();
        if(_cameraType != _vals.wirisProType && _cameraType != _vals.wirisSecurityType)
            return false;

        //we are now connected, so we can save passed IP as valid application state
        _endpointIp = ip;

        //we can even save it to local storage so app could remember last used ip on startup
        setLastIp(_endpointIp);
    }

    _connected = *_networkClient;
    emit connectedChanged(_connected, 10);

    return _connected;

}

2.

activate method – if the activated method returns false, this indicates that the SDK has never been activated. To activate it, call the activate method with your activation code as the passed argument. 

 


bool ControllerCore::activate(const QString & actStr)
{
    if (!isActivated())
    {
        std::istringstream iss;
        if(send("ACTV " + actStr, iss) && isPositive(iss.str()))
            return true;
    }
    else return true;

    return false;
}

3.

activate method – if the activated method returns false, this indicates that the SDK has never been activated. To activate it, call the activate method with your activation code as the passed argument. 

 


bool ControllerCore::setup()
{
    //checking whether connect function was called
    if (*_networkClient) {
        if (!this->isActivated())
            return false;

        //Starting Ethernet Mode
        send("SETH TRUE");
        send("GETH");

4.

activate method – if the activated method returns false, this indicates that the SDK has never been activated. To activate it, call the activate method with your activation code as the passed argument. 

 


bool ControllerCore::changeStorage(const QString & storage){
    if (storage == _currentStorage)
        return true;

    std::istringstream iss;
    std::string cache;

    if (storage == "SSD" || storage == "SD_CARD" || storage == "FLASH_DRIVE")
    {
        if (send("SILC " + storage, iss) && isPositive(iss.str()))
        {
            _currentStorage = storage;
            return true;
        }
    }

    return false;
}

 

4.

Full project: https://github.com/SoftwareWorkswell/EthernetStreamSDKGUI

When it comes to video streaming, any library that is capable of receiving an RTSP stream can be used, however, we highly recommend using GStreamer, which should be the fastest solution. 

For this kind of solution, we used OpenCV 4.1.1 with GStreamer support (first install GStreamer runtime + GStreamer devel and then build OpenCV using CMake).

 


void ThermalThread::run()
{
#ifdef _WIN32
    const std::string addr(("rtspsrc location=rtsp://" + this->_ssrc.toStdString() + ":8554/thermal latency=250 ! rtph264depay ! avdec_h264 ! videoconvert ! appsink"));
#else
    const std::string addr("rtspsrc location=rtsp://" + this->_ssrc.toStdString() + ":8554/thermal latency=300 caps = \"application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96\" ! rtph264depay ! decodebin ! videoconvert ! appsink");
#endif
    cv::VideoCapture cap(addr, cv::CAP_GSTREAMER);
    if(!cap.isOpened())
    {
        qDebug() << "visible: Input error"; *_stream = false; return; } cv::Mat frame; while(*_stream) { cap >> frame;
        if (frame.empty())
        {
            qDebug() << "thermal: empty frame occurance, stopping stream!";
            break;
        }

        cv::cvtColor(frame, frame,cv::ColorConversionCodes::COLOR_BGR2RGB);
        zoomImage(frame);
        streamFrame = new QImage(reinterpret_cast<uchar*>(frame.data), frame.cols, frame.rows, static_cast(frame.step), QImage::Format_RGB888);
        drawExtremes();
        emit imageSourceChanged();
    }
    cap.release();
    *_stream = false;
}

</uchar*>