Tereius / libONVIF

Yet another ONVIF library
GNU General Public License v3.0
164 stars 47 forks source link

Questions related to example usage #4

Closed DavidMCampbell closed 4 years ago

DavidMCampbell commented 4 years ago

Thanks for writing this library. I have a few questions related to examples that would help me, and likely others, out a lot.

At a high level, I ultimately want to perform these steps as fast as possible, in a tight loop:

  1. Grab a current image at some specified resolution (based on available resolutions retrieved on initialization).
  2. Do some processing on that image
  3. Direct PTZ camera movement based on the results of the previous step

I have your example compiling and running on a raspberry pi and it detects my camera. As a baby step, if I specify the --host flag, I get:

./onvifinfo --host http://192.168.1.10 --port 8899 -u admin -p admin
WARNING: This binary was compiled without OpenSSL: SSL/TLS and http digest auth are disabled. Your password will be send as plaintext.
Using device endpoint:  "http://192.168.1.10:8899/onvif/device_service"
This build doesn't support http digest auth. Switching back to ws token
ONVIF device service namespace: http://www.onvif.org/ver10/device/wsdl Url: http://192.168.1.10:8899/onvif/device_service
This build doesn't support http digest auth. Switching back to ws token
ONVIF media service namespace: http://www.onvif.org/ver10/media/wsdl Url: http://192.168.1.10:8899/onvif/Media
This build doesn't support http digest auth. Switching back to ws token
ONVIF event service namespace: http://www.onvif.org/ver10/events/wsdl Url: http://192.168.1.10:8899/onvif/Events
This build doesn't support http digest auth. Switching back to ws token
ONVIF imaging service namespace: http://www.onvif.org/ver20/imaging/wsdl Url: http://192.168.1.10:8899/onvif/Imaging
This build doesn't support http digest auth. Switching back to ws token
ONVIF ptz service namespace: http://www.onvif.org/ver20/ptz/wsdl Url: http://192.168.1.10:8899/onvif/PTZ
This build doesn't support http digest auth. Switching back to ws token

Topic name "Motion"
Topic path "tns1:RuleEngine/CellMotionDetector"
    Item "VideoSourceConfigurationToken" type "tt:ReferenceToken" primitive "string"
    Item "VideoAnalyticsConfigurationToken" type "tt:ReferenceToken" primitive "string"
    Unknown Item "Rule" type "xsd:string"
    Item "IsMotion" type "xsd:boolean" primitive "boolean"

Topic name "SignalLoss"
Topic path "tns1:VideoSource"
    Item "Source" type "tt:ReferenceToken" primitive "string"
    Item "State" type "xsd:boolean" primitive "boolean"

Topic name "MotionAlarm"
Topic path "tns1:VideoSource"
    Item "Source" type "tt:ReferenceToken" primitive "string"
    Item "State" type "xsd:boolean" primitive "boolean"

Topic name "tnsn:SignalStandardMismatch"
Topic path "tns1:VideoSource"
    Item "VideoSourceToken" type "tt:ReferenceToken" primitive "string"
    Item "State" type "xsd:boolean" primitive "boolean"

How would you recommend accomplishing rapid, single-image retrieval (limited by the camera and network of course) and PTZ movement? In other words, any help with examples that would help accomplish the image capture and ptz continuous move steps outlined above would be really helpful.

Thanks, David

DavidMCampbell commented 4 years ago

Update: I found an ONVIF application guide and have PTZ code written up and mostly working from that, but only zoom responds to the ContinuousMove command. I'm getting 200 OK responses. Using other ONVIF clients and wireshark, I see that they use a different format e.g:

<ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">
  <ProfileToken>000</ProfileToken>
  <Velocity>
    <PanTilt x="0.5" y="0" xmlns="http://www.onvif.org/ver10/schema"/>
  </Velocity>
</ContinuousMove>

Request using this library:

xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"
xmlns:tt="http://www.onvif.org/ver10/schema"

<tptz:ContinuousMove>
  <tptz:ProfileToken>000</tptz:ProfileToken>
  <tptz:Velocity>
    <tt:PanTilt x="0.5" y="-0.5"></tt:PanTilt>
  </tptz:Velocity>
</tptz:ContinuousMove>

They requests seem equivalent so I'm not sure what the problem is...

edit: x and y movement work if you only intend to move using one axis at a time, e.g. x="0.5" y="0". For some reason you can't move in both axis at once...

Tereius commented 4 years ago

To list all supported media profiles you would do sth. like:

auto mpMediaClient = new OnvifMediaClient(QUrl("http://192.168.1.10:8899/onvif/Media"));
Request<_trt__GetProfiles> profilesRequest;
auto profilesResponse = mpMediaClient->GetProfiles(profilesRequest);
if(profilesResponse) {
    for(auto profile : profilesResponse.GetResultObject()->Profiles) {
        qInfo() << "Profile:" << profile->Name << profile->token;
    }
}

After that you get the streaming url for the selected media profile as follows:

QUrl streamingUrl;
Request<_trt__GetStreamUri> streamUriRequest;
streamUriRequest.ProfileToken = token; // The token of the media profile
streamUriRequest.StreamSetup = new tt__StreamSetup();
streamUriRequest.StreamSetup->Stream = tt__StreamType::RTP_Unicast;
streamUriRequest.StreamSetup->Transport = new tt__Transport();
streamUriRequest.StreamSetup->Transport->Protocol = tt__TransportProtocol::UDP;
auto streamUriResponse = mpMediaClient->GetStreamUri(streamUriRequest);
if(streamUriResponse) {
    if(auto streamUri = streamUriResponse.GetResultObject()->MediaUri) {
        streamingUrl = QUrl(streamUri->Uri);
    }
    else {
        qWarning() << shortId << "Couldn't extract streaming Uri";
    }
}
else {
    qWarning() << shortId << "Couldn't get media profiles:" << streamUriResponse.GetCompleteFault();
}
// Decoding the video stream is out of scope of this library

From there on you have to use another library like ffmpeg to receive/decode the video stream.

I can't help you with PTZ because I don't have a device for testing.

DavidMCampbell commented 4 years ago

Thanks. Yea, I got a similar GetStreamUri() example request from one of the other closed issues.

The trick with the with PTZ control is that you have to send a pan continuous move, then tilt continuous move, then sleep(), then Stop(). You can send zoom with the pan and tilt commands, but for some reason, you can't pan and tilt in the same continuous move command.

        QString profileToken = "000";

        qDebug() << "Building continuous move request...";
        Request<_tptz__ContinuousMove> continuousMoveRequest;

        continuousMoveRequest.ProfileToken = profileToken;
        continuousMoveRequest.Velocity = new tt__PTZSpeed();
        continuousMoveRequest.Velocity->PanTilt = new tt__Vector2D();
        continuousMoveRequest.Velocity->Zoom = new tt__Vector1D();

        continuousMoveRequest.Velocity->PanTilt->x = -0.5; // + pan right, - pan left
        continuousMoveRequest.Velocity->PanTilt->y = 0; // - tilt down, 1 tilt up
        continuousMoveRequest.Velocity->Zoom->x = 0; // - zoom out, + zoom in
        qDebug() << "Sending continuous move request...";
        ptzClient->ContinuousMove(continuousMoveRequest);

        continuousMoveRequest.Velocity->PanTilt->x = 0; // + pan right, - pan left
        continuousMoveRequest.Velocity->PanTilt->y = 0.5; // - tilt down, 1 tilt up
        continuousMoveRequest.Velocity->Zoom->x = -1; // - zoom out, + zoom in
        ptzClient->ContinuousMove(continuousMoveRequest);

        qDebug() << "Waiting...";
        std::this_thread::sleep_for(std::chrono::milliseconds(500));

        qDebug() << "Sending PTZ stop request...";
        Request<_tptz__Stop> ptzStopRequest;
        ptzStopRequest.ProfileToken = profileToken;
        ptzStopRequest.PanTilt = new bool(true);
        ptzStopRequest.Zoom = new bool(true);
        ptzClient->Stop(ptzStopRequest);