我想开始使用Delphi来访问和控制带有Onvif SOAP协议的IP摄像机。
但是,我不明白如何实际执行来自Delphi的调用。我导入了以下WDSL:
http://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl
在Delphi中生成了一个单元。但是我该如何处理对着摄像机的呼叫呢?我应该以某种方式使用与THTTPRIO一起生成的这个吗?如何指定我拥有的相机的IP地址(目前是Axis Q1755摄像机)。
如果有人能让我从正确的方向开始,我将非常感激。
发布于 2014-09-28 20:16:15
如果您使用Delphi的WSDL导入程序,它将生成必要的类来表示来自SOAP its服务及其相应的response的任何response。
它还将生成一个wrapper,您将使用它来实际执行调用。通常,它将有以下几种方法:
function mySoapMethod(myRequest: TmyRequestType): TMyResponse;要打电话,你基本上可以做以下几件事:
wrapper实例引用。单元中应该有一个类似于GetWrapper的方法。request type创建一个实例,并设置其所有属性。请注意,如果SOAP方法只需要几个基本类型作为参数,就可能没有这样的请求类。还要考虑到,任何足够复杂的request type都可能意味着您需要创建对象的实例,并将它们作为属性分配给请求。wrapper method发送请求(如果是简单调用,则设置参数)。response对象并根据需要对其进行操作。在伪码中如下所示:
myWrapper := GetMyWrapper();
myRequest := TMyRequest.Create;
//set myRequest properties
myResponse := myWrapper.mySoapMethod(myRequest);
//do whatever you need with the response关于包装器
wrapper将是带有一些新增方法的IInvokable接口的实现。实际上,对于您可以调用的每个SOAP method,它都应该有一个方法。
通常,它的接口声明如下所示:
TmyWrapper = interface(IInvokable)
['...'] //GUID here
function oneMethod(...): oneMethodResponse;
function anotherMethod(...): anotherMethodResponse;
end;
function getMyWrapper(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): TmyWrapper ;该函数的实现将如下所示:
function GetMyWrapper(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): TmyWrapper;
const
defWSDL = 'http://<soap service IP and port>/<soap service name>?wsdl';
defURL = 'http://<soap service IP and port>/<soap service name>';
defSvc = '<default service name>';
defPrt = '<default service port>';
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = '') then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
Result := (RIO as TmyWrapper );
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;一些附带说明:
HTTPRIO方法获得wrapper实例时,您可以将它注入到getXYZWrapper实例。例如,这可以帮助您设置另一个SOAP URL或检查生成的XML。XML将按照SOAP的预期以一种稍微不同的方式发送。如果您认为它应该工作,但不工作,那么检查生成的XML并将它与它应该是什么相比较。在发送HTTPRIO对象的onBeforeExecute事件之前,可以使用它来修改XML。HTTPRIO对象的HTTPRIO方法来检查XML响应。发布于 2019-07-24 07:52:33
您可以通过Delphi XE7使用我导入的WSDL
媒体:Media.WSDL
成像:Imaging.wsdl
设备管理:devicemgmt.wsdl
通常导入的WSDL有一个函数,如
function GetMySoap(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): MySoap;但是它不存在于onvif导入的wsdl中。
将此函数添加到项目实例中,Media2是IInvokable类的名称。
function GetWSSoap(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): Media2;
const
defWSDL = 'http://192.168.1.1/onvif/Media?WSDL';
defURL = 'http://192.168.1.1/onvif/Media';
defSvc = 'Media';
defPrt = '80';
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = '') then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
Result := (RIO as Media2);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;另一种解决方案,使用发送http requst示例请求获取一些通用信息,GetProfiles是方法名称。
<?xml version="1.0"?> <soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsdl="http://www.onvif.org/ver10/media/wsdl">
<soap:Header>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<UsernameToken>
<Username>%s</Username>
<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%s</Password>
<Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%s</Nonce>
<Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%s</Created>
</UsernameToken>
</Security>
</soap:Header>
<soap:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<GetProfiles xmlns="http://www.onvif.org/ver10/media/wsdl" />
</soap:Body>
</soap:Envelope>按钮代码:
网址: onvif/media
GetONVIFPasswordDigest(ed_user.text, ED_pass.text, PasswordDigest, Nonce, Created);
User_Pass := Format(M_Request, [UserName, PasswordDigest, Nonce, Created]);
ONVIFRequest(ED_IP.Text + ED_URL.Text,User_Pass,Result);密码制作程序:
procedure GetONVIFPasswordDigest(const UserName, Password: String; Var PasswordDigest, Nonce, Created: String);
Var
i: Integer;
raw_nonce, bnonce, digest , S_In: TBytes;
raw_digest: TBytes;
DT : TDateTime;
begin
SetLength(raw_nonce, 20);
for i := 0 to High(raw_nonce) do
raw_nonce[i] := Random(256);
bnonce := TNetEncoding.Base64.Encode(raw_nonce);
Nonce := BytesToString(bnonce);
DT := Now();
Created := GetONVIFDateTime(DT);
S_In := raw_nonce + StringToBytes(Created) + StringToBytes(Password);
raw_digest := SHA1(S_In);
digest := TNetEncoding.Base64.Encode(raw_digest);
PasswordDigest := BytesToString(digest);
end;获取数据过程:
procedure ONVIFRequest(const Addr: String; const InStream, OutStream: TStringStream);overload;
Var
idhtp1: TIdHTTP;
Uri: TIdURI;
begin
idhtp1 := TIdHTTP.Create;
Uri := TIdURI.Create(Addr);
try
With idhtp1 do
begin
AllowCookies := True;
HandleRedirects := True;
Request.Accept := 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
Request.Host := '';
Request.Connection := '';
Request.Accept := '';
Request.UserAgent := '';
Request.CustomHeaders.Clear;
Request.ContentType := 'text/xml;charset=utf-8';
Request.CustomHeaders.Add('Host: ' + Uri.Host);
//-------------------
request.username := ed_user.text;
request.password := ed_pass.text;
HTTPOptions := [hoInProcessAuth,hoForceEncodeParams,hoNoProtocolErrorException, hoWantProtocolErrorContent];
//-------------------
ProtocolVersion := pv1_1;
Post(Addr, InStream, OutStream);
end;
finally
Uri.Free;
idhtp1.Free;
end;
end;
procedure ONVIFRequest(const Addr, Request: String; Var Answer: String);overload;
Var
InStream, OutStream: TStringStream;
begin
InStream := TStringStream.Create(Request);
OutStream := TStringStream.Create;
try
ONVIFRequest(Addr, InStream, OutStream);
Answer := OutStream.DataString;
finally
InStream.Free;
OutStream.Free;
end;
end;你也可以在这里找到一个更好的样本。
https://github.com/Laex/Delphi-ONVIFhttps://stackoverflow.com/questions/26088527
复制相似问题