0

我想开始使用 Delphi 通过 Onvif SOAP 协议访问和控制 IP 摄像机。

但是,我不明白如何实际执行来自 Delphi 的调用。我已经导入了以下 WDSL:

http://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl

并且在 Delphi 中生成了一个单元。但是我如何执行对相机的调用呢?我应该以某种方式将它与 THTTPRIO 一起使用吗?如何指定我拥有的摄像机(当前为 Axis Q1755 摄像机)的 IP 地址。

如果有人可以通过指出我正确的方向来让我开始,我将非常感激。

4

2 回答 2

1

如果您使用 Delphi 的WSDL导入器,它将生成必要的类来表示任何request来自SOAPweb 服务及其对应的response.

它还将生成一个wrapper,您将使用它来实际进行调用。通常它会有如下几种方法:

function mySoapMethod(myRequest: TmyRequestType): TMyResponse;

要拨打电话,您基本上执行以下操作:

  1. 获取wrapper实例引用。单元中应该有一个方法,称为类似于GetWrapper.
  2. 如有必要,您可以创建一个实例request type并设置其所有属性。SOAP请注意,如果方法只需要一些基本类型作为参数,则可能没有请求类。还要考虑到任何足够复杂的情况request type都可能意味着您需要创建对象实例并将它们作为属性分配给请求。
  3. 使用对应wrapper method发送请求(如果是简单调用,也可以设置参数)。
  4. 接收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实例注入到。例如,这可以帮助您设置另一个或检查生成的。wrappergetXYZWrapperSOAP URLXML
  • 有时 Delphi会以与预期XML略有不同的方式生成要发送的内容。SOAP如果您认为它应该有效但无效,请检查XML生成的内容并将其与应有的内容进行比较。您可以在发送之前使用HTTPRIO对象的onBeforeExecute事件来修改XML它。
  • 我需要它,您也可以使用对象的onAfterExecute方法HTTPRIO来检查XML响应。
于 2014-09-28T20:16:15.777 回答
0

你可以使用我通过 Delphi XE7 导入的 WSDL

媒体:媒体 .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 请求示例请求获取一些一般信息 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>

按钮代码:

ip:http: //192.168.1.1

网址:onvif/媒体

  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-ONVIF
于 2019-07-24T07:52:33.777 回答