Closed DavidMCampbell closed 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...
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.
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);
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:
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:
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