Delphi如何在另一个函数中使用回调函数作为参数?

时间:2016-06-06 07:55:58

标签: c++ delphi

我想将c ++代码转换为Delphi。 c ++代码从摄像头获取流(海康威视)。这是我想要转换为Delphi的c ++代码:

    void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void* dwUser)
    {

        HWND hWnd = GetConsoleWindow();
        switch (dwDataType)
        {
        case NET_DVR_SYSHEAD: //System head

            if (!PlayM4_GetPort(&lPort))  //Get unused port
            {
                break;
            }

            if (dwBufSize > 0)
            {
                if (!PlayM4_SetStreamOpenMode(lPort, STREAME_REALTIME))  
                {
                    break;
                }

                if (!PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024 * 1024))
                {
                    break;
                }

                if (!PlayM4_Play(lPort, hWnd)) //Start play
                {
                    break;
                }
            }
        case NET_DVR_STREAMDATA:   //Stream data
            if (dwBufSize > 0 && lPort != -1)
            {
                if (!PlayM4_InputData(lPort, pBuffer, dwBufSize))
                {
                    break;
                }
            }
        }
    }

int _tmain(int argc, _TCHAR* argv[])
{

   NET_DVR_Init();
  NET_DVR_DEVICEINFO_V30 struDeviceInfo;
  lUserID = NET_DVR_Login_V30("193.160.101.1", 8000, "admin", "12345", &struDeviceInfo);
  if (lUserID < 0)
  {
      printf("Login error, %d\n", NET_DVR_GetLastError());
      NET_DVR_Cleanup();
      return 0;
  }

     LONG lRealPlayHandle;
     NET_DVR_PREVIEWINFO struPlayInfo = { 0 };
     struPlayInfo.hPlayWnd = NULL;         //If need to decode, please set it valid. If want to get stream data only, it can be set to NULL
     struPlayInfo.lChannel = 1;       //Preview channel NO.
     //struPlayInfo.dwStreamType = 0;       //0-main stream, 1-sub stream, 2-stream3, 3-stream4.
     struPlayInfo.dwLinkMode = 0;         //0-TCP mode, 1-UDP mode, 2-Multi-play mode, 3-RTP mode, 4-RTP/RTSP, 5-RTSP/HTTP


     lRealPlayHandle = NET_DVR_RealPlay_V40(lUserID, &struPlayInfo, fRealDataCallBack, NULL)

    return 0;

}

这是我的Delphi代码

 procedure TForm1.MyRealDataCallBack_V30(lRealHandle:Longint;dwDataType:DWORD;pBuffer:PByte;dwBufSize,dwUser:DWORD); stdcall;
    begin

      hPlayWnd:=Panel1.Handle;
      if dwDataType = NET_DVR_SYSHEAD then
       begin
         if (not(PlayM4_GetPort(lPort))) then
         begin
           Exit;
         end;
         if dwBufSize > 0  then
         begin
           if not(PlayM4_SetStreamOpenMode(lPort, STREAME_REALTIME)) then    
           begin
             Exit;
           end;
            if not(PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024*1024)) then 
           begin
             Exit;
           end;
             if not(PlayM4_Play(lPort,hPlayWnd)) then
           begin
             Exit;
           end;
           if dwDataType = NET_DVR_STREAMDATA then
            begin
         if (dwBufSize > 0) and (lPort <> -1) then
         begin
           if not(PlayM4_InputData(lPort, pBuffer, dwBufSize)) then
           begin
             Exit
           end;
         end;
       end;
    end;
    end;
    end;
    procedure TForm1.btnPlayClickClick(Sender: TObject);
    var
    lRealPlayHandle :Longint;
    begin
    lRealPlayHandle:=NET_DVR_RealPlay_V40(iLoginID,struPlayInfo,MyRealDataCallBack_V30,null);
    end; 
 function  NET_DVR_RealPlay_V40(lUserID: LongInt;var lpPreviewInfo: TNET_DVR_PREVIEWINFO; RealDataCallBack_V30:fRealDataCallBack_V30;pUser:Pointer): LongInt;stdcall; external 'HCNetSDK.dll' name'NET_DVR_RealPlay_V40';  

我为播放视频格式的海康威视相机定义了回调函数(MyRealDataCallBack),并将此函数用作另一个函数的输入参数(NET_DVR_RealPlay_V40)

2 个答案:

答案 0 :(得分:4)

你不能在这里使用表格的方法,你需要定期的程序:

 void CALLBACK fRealDataCallBack(LONG lRealHandle, DWORD dwDataType, 
               BYTE *pBuffer, DWORD dwBufSize, void* dwUser)

应该是

procedure fRealDataCallBack(lRealHandle : LongInt; dwDataType: DWORD; 
            pBuffer: PByte; dwBufSize: DWORD; dwUser: Pointer); stdcall;

或使用静态类程序

type
  TMyClass = class 
....
  class procedure fRealDataCallBack(lRealHandle : LongInt; dwDataType: DWORD; 
            pBuffer: PByte; dwBufSize: DWORD; dwUser: Pointer); stdcall; static;

您的NET_DVR_RealPlay_V40是使用类型化的回调参数声明的,因此在NET_DVR_RealPlay_V40之前需要回调函数的类型声明:

fRealDataCallBack_V30 = procedure (lRealHandle : LongInt; dwDataType: DWORD; 
            pBuffer: PByte; dwBufSize: DWORD; dwUser: Pointer); stdcall;

答案 1 :(得分:4)

您正在尝试使用Form类的非静态方法作为回调。非静态方法具有隐藏的Self参数,相机API将无法填充该参数(除非您创建代理存根,这是此问题范围之外的高级技术)。您需要从回调中删除该参数,方法是将回调声明为独立过程,或者将其声明为class static方法。无论哪种方式,如果您需要访问Form对象的成员(例如TPanel),您可以使用回调的dwUser参数将表单的对象指针传递给回调。

尝试这样的事情:

interface

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    btnPlay: TButton;
    ...
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnPlayClick(Sender: TObject);
    ...
  private
    lRealPlayHandle: LONG;
    lPort: LONG;
    iLoginID: LONG;
    struDeviceInfo: TNET_DVR_DEVICEINFO_V30;
    struPlayInfo: TNET_DVR_PREVIEWINFO;
    ...
    procedure MyRealDataCallBack_V30(lRealHandle: LONG; dwDataType: DWORD; pBuffer: PByte; dwBufSize: DWORD);
    ...
  end;

implementation

function NET_DVR_Init: BOOL; stdcall; external 'HCNetSDK.dll' name 'NET_DVR_Init';  
function NET_DVR_Cleanup: BOOL; external 'HCNetSDK.dll' name 'NET_DVR_Cleanup';  
function NET_DVR_RealPlay_V40(lUserID: LONG; var lpPreviewInfo: TNET_DVR_PREVIEWINFO; RealDataCallBack_V30: fRealDataCallBack_V30; pUser: Pointer): LONG; stdcall; external 'HCNetSDK.dll' name 'NET_DVR_RealPlay_V40';  
// other DVR function declaration as needed...

procedure ActualRealDataCallBack_V30(lRealHandle: LONG; dwDataType: DWORD; pBuffer: PByte; dwBufSize: DWORD; dwUser: Pointer); stdcall;
begin
  TForm1(dwUser).MyRealDataCallBack_V30(lRealHandle, dwDataType, pBuffer, dwBufSize);
end;

procedure TForm1.MyRealDataCallBack_V30(lRealHandle: LONG; dwDataType: DWORD; pBuffer: PByte; dwBufSize: DWORD);
begin
  case dwDataType of
    NET_DVR_SYSHEAD:
    begin
      if not PlayM4_GetPort(lPort) then
        Exit;
      if (dwBufSize > 0) then
      begin
        if not PlayM4_SetStreamOpenMode(lPort, STREAME_REALTIME) then    
          Exit;
        if not PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024*1024) then 
          Exit;
        if not PlayM4_Play(lPort, Panel1.Handle) then
          Exit;
      end;
    end;

    NET_DVR_STREAMDATA:
    begin
      if (dwBufSize > 0) and (lPort <> -1) then
      begin
        if not PlayM4_InputData(lPort, pBuffer, dwBufSize) then
          Exit;
      end;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  err: Integer;
begin
  NET_DVR_Init;

  iLoginID := NET_DVR_Login_V30('193.160.101.1', 8000, 'admin', '12345', struDeviceInfo);
  if (iLoginID < 0) then
  begin
    err := NET_DVR_GetLastError;
    NET_DVR_Cleanup;
    raise Exception.CreateFmt('Login error, %d', [err]);
  end;

  struPlayInfo.hPlayWnd := 0;         //If need to decode, please set it valid. If want to get stream data only, it can be set to NULL
  struPlayInfo.lChannel := 1;       //Preview channel NO.
  //struPlayInfo.dwStreamType := 0;       //0-main stream, 1-sub stream, 2-stream3, 3-stream4.
  struPlayInfo.dwLinkMode := 0;         //0-TCP mode, 1-UDP mode, 2-Multi-play mode, 3-RTP mode, 4-RTP/RTSP, 5-RTSP/HTTP

  lPort := ...;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  NET_DVR_Cleanup;
end;

procedure TForm1.btnPlayClick(Sender: TObject);
begin
  lRealPlayHandle := NET_DVR_RealPlay_V40(iLoginID, struPlayInfo, ActualRealDataCallBack_V30, Self);
end; 

end.