{******************************************************************************}
{ @UnitName    : HDCameraControl                                                 }
{ @Project     : DJL                                                      }
{ @Copyright   :                                                               }
{ @Author      : SKZHEN                                                       }
{ @CreateDate  : 2012-08-08 20:58:38                                            }
{ @LastUpdate  : 2012-08-08 18:49:49 by SKZHEN                                 }
{ @Description :                                                               }
{ @Comment     :                                                               }
{ @History     :                                                               }
{******************************************************************************}

unit HDCameraControl;

interface

uses
  SysUtils, Classes, ExtCtrls, DateUtils, Types, Messages, ShellApi, Windows,
  HDFileOperate, Math,Dialogs;

const
  WM_HDREALDATA = WM_USER + $1000;
  MinFreeSpace = 4294967296;
  //MinFreeSpace = 454529115136;

  MaxDeleteFileNum = 3;    //删除的最大文件数目(删除历史录像，以天为单位)
  MaxRenameTempFileNum = 2; //要修改的最近TEMP文件的天数
type
  PLpframe_ExtData = ^TLpframe_ExtData;
  TLpframe_ExtData = record
  	bIsKey: Integer;//是否为关键帧
	  timestamp: Double;//时间截
	  pUserData: Pointer;//用户数据指针，本为函数中pUser所设指针
  end;

  PLpuser_VideoInfo = ^TLpuser_VideoInfo;
  TLpuser_VideoInfo = record
		nVideoPort: Integer;//连接的视频端口
		bIsTcp: Integer;//是否使用TCP连接
		nVideoChannle: Integer;//视频通道，为32位整数，高16表示类型，可以是0，1，0表示IPC，1表示DVS，低16位表示
						               //视频通道号,当类型为0时，可以是0，1，0表示主码流，1表示子码流
						               //当类型为1时，可以是0，1，2，3，4，分别表示通道1，2，3，4，和CIF输出。
		pUserData: Pointer;//用户指针，用于回调时作为最后一参数
  end;

  PDVRDeviceInfo = ^TDVRDeviceInfo;
  TDVRDeviceInfo = record
    sSerialNumber: array[0..47] of BYTE;
    byAlarmInPortNum: BYTE;
    byAlarmOutPortNum: BYTE;
    byDiskNum: BYTE;
    byDVRType: BYTE;
    byChanNum: BYTE;
    byStartChan: BYTE;
  end;

  PVideoParam = ^TVideoParam;
  TVideoParam = record
    Codec: array[0..255] of char;     //H264或是MPEG4，等，表示当前视频编码类型
    Width: LongInt;                   //视频宽
    Height: LongInt;                  //视频高
    Colorbits: LongInt;               //颜色位数，此处无效，仅用于内部
    Framerate: LongInt;               //参考帧率
    Bitrate: LongInt;                 //参考码率
    Vol_Data: array[0..255] of Byte;  //扩展参数,解码时必要的数据
    Vol_Length: LongInt;              //扩展参数长度
  end;

  PAudioParam = ^TAudioParam;
  TAudioParam = record
    Codec: array[0..255] of char;    //音频类型，AAC或G711
    Samplerate: LongInt;             //参考比特率
    BitSpersample: LongInt;          //参考比特率
    Channels: LongInt;               //声道数量
    Framerate: LongInt;
    BitRate: LongInt;
  end;

  PStreamAvParam = ^TStreamAvParam;
  TStreamAvParam = record
    protocolName: array[0..31] of Byte;      //==AV_FALG
    bHaveVideo: smallint;                    //0 表示没有视频参数
    bHaveAudio: smallint;                    //0 表示没有音频参数
    videoParam: TVideoParam;                 //视频参数
    AudioParam: TAudioParam;                //音频参数
  end;

  PFrame_Extdat = ^TFrame_Extdat;
  TFrame_Extdat = record
	  bIsKey: Integer;//是否为关键帧
	  timestamp: DWord;//时间截
	  pUserData: Pointer;//用户数据指针，本为函数中pUser所设指针
  end;


  //回调函数类型定义  TStatusEventCallBack: 状态改变回调函数 TRealDataCallBack: 媒体接收回调函数
  TStatusEventCallBack = function(iUser, nStateCode: Integer; pResponse: PChar; pUser: pointer): Integer; stdcall;
  TRealDataCallBack = function(lRealHandle: Integer; dwDataType: DWord; pBuffer: Pointer; dwBufSize: DWord;
     Lpframe_ExtData: TLpframe_ExtData): Integer; stdcall;

  //高清摄像头数据处理控制
  THDCameraControl = class
  private
    //处理视频数据消息
    procedure WndProc(var Msg: Tmessage); message WM_HDREALDATA;
  public
    LoginChannel: Integer;
    HsdVideoStream: Integer;
    HsdVideoParam: TVideoParam;

    constructor Create;
    //初始化高清摄像头通道-->请求视频流
    Procedure InitHDCameraChannels;
    //开始某一路高清摄像头录像
    function StartHDRecord: Boolean;
    //停止某一路高清摄像头录像
    function StopHDRecord: Boolean;
    //停止所有高清摄像头录像
    function StopAllHDRecord: Boolean;
  end;

  //录像时磁盘空间检测线程(如果磁盘空间小于2G，非循环录像模式则停止录像，
  //否则则删除旧文件以提供出空间)
  TDiskSpaceRecordThread = class(TThread)
  private
    function GetDiskSequence(Dir: string): Integer;
    function CheckOutFreeSpace: Boolean;  //为TRUE，则说明磁盘空间少于最少需求空间
    function DeleteOldRecordFile: Boolean;  //删除掉最早的MaxDeleteFileNum天的录像文件
    function GetOldRecordFileName(FilePath: string; var FileName: string): Boolean;
    function RenameTempFile: Boolean;
    function GetTempFiles(FilePath: string; var FileName: string): Boolean;
  protected
    procedure Execute; override;
  public
    constructor Create;
  end;

  //回调函数的实现  StatusEventCallBack: 状态改变回调函数 RealDataCallBack: 媒体接收回调函数
  function StatusEventCallBack(iUser, nStateCode: Integer; pResponse: PChar; pUser: pointer): Integer; stdcall;
  function RealDataCallBack(lRealHandle: Integer; dwDataType: DWord; pBuffer: PByte; dwBufSize: DWord;
    Lpframe_ExtData: PLpframe_ExtData): Integer; stdcall;

  //写日志
  procedure WriteLog(msg: string);
  function GetFilePath(IPStr: string): string;


  //参数化DLL库，在调用所有函数之前要调用一次此函数
  function IP_NET_DVR_Init: Integer; stdcall; external 'NetSDKDLL.dll';
  //设置设备状态变化、或者有接收到事件、告警时的回调函数
  function IP_NET_DVR_SetStatusEventCallBack(StatusEventCallBack: TStatusEventCallBack; pUser: pointer): Integer;
    stdcall; external 'NetSDKDll.dll';
  //设置接收媒体流的回调用函数，本函数所设置的回调会在请求流时传入的回调函数为NULL时起作用，
  //即当作所有通道的默认回调函数
  function IP_NET_DVR_SetRealDataCallBack(RealDataCallBack: TRealDataCallBack;  pUser: pointer): Integer;
    stdcall; external 'NetSDKDll.dll';

  function IP_NET_DVR_Login(szDVRIP: PChar; wDVRPort: Integer; sUserName, sPassword : PChar;
    DVRDeviceInfo: PDVRDeviceInfo): Integer; stdcall; external 'NetSDKDll.dll';

  //启动接收视频流，与IP_NET_DVR_RealPlay不同之处是，此函数，可以不连接辅助通道的情况下接收视频流
  function IP_NET_DVR_RealPlayEx(serverip, user, pass: PChar; RealDataCallBack: TRealDataCallBack;
    pUser: PLpuser_VideoInfo; bBlocked: Boolean): Integer; stdcall; external 'NetSDKDll.dll';
  //停止收流
  function IP_NET_DVR_StopRealPlay(lRealHandle: Integer): Integer; stdcall; external 'NetSDKDll.dll';
  //释放资源 当不再使用DLL库时，调用此函数，用于清理DLL中使用的资源，调用此函数后会自动退出所有登录，
  //会停止所有请求的流
  function IP_NET_DVR_Cleanup: Integer;  stdcall; external 'NetSDKDll.dll';
  //启动录像
  function IP_NET_DVR_StartRecord(lRealHandle: Integer; filePath: PChar; nFileMaxSeconds,
    nAllRecordMaxSeconds: Integer): Integer; stdcall; external 'NetSDKDll.dll';
  //停止录像
  function IP_NET_DVR_StopRecord(lRealHandle: Integer): Integer; stdcall; external 'NetSDKDll.dll';
  //基本云台控制
  function IP_NET_DVR_PTZControl(lUser, dwPTZCommand, nTspeed, nPpeed: Integer): Integer;  stdcall; external 'NetSDKDll.dll';
  //预置点控制
  function IP_NET_DVR_PTZPreset(lUser, dwPTZPresetCmd, dwPresetIndex: Integer): Integer;  stdcall; external 'NetSDKDll.dll';

  //此函数将打开一个流
  function IP_TPS_OpenStream(nPort: Integer; pParam: PByte; pSize, isAudioParam, nBufPoolSize: Integer): Integer;
    stdcall; external 'DllPlayer.dll';
  //传入视频数据进行解码播放
  function IP_TPS_InputVideoData(nPort: Integer; pBuf: PByte; nSize: DWord; isKey: Integer; timeStamp: DWord): Integer;
    stdcall; external 'DllPlayer.dll';
  //此函数表示在某窗口上开始播放某一路视频
  function IP_TPS_Play(nPort: Integer; Hwnd: THandle): Integer; stdcall; external 'DllPlayer.dll';
  //此函数表示在某区域上开始播放某一路视频
  function IP_TPS_PlayByArea(nPort: Integer; hWnd: THandle; rcArea: TRect): LongWord; stdcall; external 'DllPlayer.dll';
  //停止播放(或解码) 此函数等同于IP_TPS_DeleteStream,仅为保持接口
  function IP_TPS_Stop(nPort: Integer): Integer; stdcall; external 'DllPlayer.dll';
  //释放所有 停止所有线程并释放所有资源
  function IP_TPS_ReleaseAll: Integer;  stdcall; external 'DllPlayer.dll';
  //抓图保存到指定文件
  function IP_TPS_CatchPicByFileName(nPort: Integer; sFileName: PChar; isJpg: Integer): Integer;
    stdcall external 'DllPlayer.dll';
  //播放声音
  function IP_TPS_PlaySound(nPort: Integer): Integer;  stdcall; external 'DllPlayer.dll';
  //停止声音
  function IP_TPS_StopSound: Integer;  stdcall; external 'DllPlayer.dll';

var
  _HDCameraControl: THDCameraControl;
  _DiskSpaceRecordThread: TDiskSpaceRecordThread;

implementation

uses MainForm;

//回调函数的实现  StatusEventCallBack: 状态改变回调函数
function StatusEventCallBack(iUser, nStateCode: Integer; pResponse: PChar; pUser: pointer): Integer; stdcall;
var
  I, FactIndex: Integer;
  HDCameraIP, ErrNote: string;
  UserVideoInfo: PLpuser_VideoInfo;
begin
  //写日志以便调试 >>>此地方不能打开，不然超过1个摄像头时程序会报错
  //WriteLog('[D]StatusEventCallBack[iUser：' + IntToStr(iUser) + '  nStateCode：' +
  //  IntToStr(nStateCode) + ']');
  case nStateCode of
    4: begin    //EVENT_LOGINOK,//登录成功
      with HDCamerasData do
      begin
        if _HDCameraControl.LoginChannel = iUser then
        begin
          if _HDCameraControl.HsdVideoStream > 0 then
            IP_NET_DVR_StopRealPlay(_HDCameraControl.HsdVideoStream);

          if not HDCamerasData.IfShowMainCode then
          begin
            //请求标清视频流  标清视频用来界面显示
            New(UserVideoInfo);
            UserVideoInfo^.nVideoPort := HDCameraData.CameraPort;
            UserVideoInfo^.bIsTcp := bIsTcp;
            UserVideoInfo^.nVideoChannle := 1;     //==0主码流 360P ==1子码流，1080P占用资源
            UserVideoInfo^.pUserData := nil;
            HDCameraIP := HDCameraData.IP;
            _HDCameraControl.HsdVideoStream := IP_NET_DVR_RealPlayEx(PChar(HDCameraIP), PChar(HDUserName),
              PChar(HDPassword), @RealDataCallBack, UserVideoInfo, False);
          end
          else begin
            //请求高清视频流  高清视频用来录像
            New(UserVideoInfo);
            UserVideoInfo^.nVideoPort := HDCameraData.CameraPort;
            UserVideoInfo^.bIsTcp := bIsTcp;
            UserVideoInfo^.nVideoChannle := 0;     //==0主码流 360P ==1子码流，1080P占用资源
            UserVideoInfo^.pUserData := nil;
            HDCameraIP := HDCameraData.IP;
            _HDCameraControl.HsdVideoStream := IP_NET_DVR_RealPlayEx(PChar(HDCameraIP), PChar(HDUserName),
              PChar(HDPassword), @RealDataCallBack, UserVideoInfo, False);
          end;
        end;
      end;    // for
    end;
    30: begin    //EVENT_RECVVIDEOAUDIOPARAM,//收到音视频参数   如果需要录像此时可以开始
      if _HDCameraControl.HsdVideoStream = iUser then
      begin
        //如果还未开始录像 这个地方不屏蔽可以在此自动启动录像
       // _HDCameraControl.StartHDRecord;
      end;
    end;
    2,3,5: begin   //连接失败，Sock失败，登陆失败
      if _HDCameraControl.LoginChannel = iUser then
      begin
        HDCameraIP := HDCamerasData.HDCameraData.IP;
        case nStateCode of    //
          2: ErrNote := '连接IP：' + HDCameraIP + ' 失败';
          3: ErrNote := '连接IP：' + HDCameraIP + ' sock失败';
          5: ErrNote := '登陆IP：' + HDCameraIP + ' 失败';
        end;    // case
      end;
    end;
  end;
end;

//回调函数的实现 RealDataCallBack: 媒体接收回调函数
function RealDataCallBack(lRealHandle: Integer; dwDataType: DWord; pBuffer: PByte; dwBufSize: DWord;
  Lpframe_ExtData: PLpframe_ExtData): Integer; stdcall;
var
  lrect: TRect;
  I, FactIndex: Integer;
  Frame_Extdat: PFrame_Extdat;
  StreamAvParam: PStreamAvParam;
  videoParam: tvideoParam;
begin
  try
    case dwDataType of    //
      0: begin   //表示视频媒体
        Frame_Extdat := PFrame_Extdat(lpframe_ExtData);
        IP_TPS_InputVideoData(lRealHandle, PBuffer, dwBufSize, Frame_Extdat^.bIsKey, Frame_Extdat^.timestamp);
      end;
      1: begin   //表示音频媒体 暂不处理
      end;
      2: begin   //表示解码参数媒体
        StreamAvParam := PStreamAvParam(PBuffer);
        videoParam := tvideoParam(StreamAvParam^.videoParam);
        if StreamAvParam^.bHaveVideo > 0 then
          IP_TPS_OpenStream(lRealHandle, @videoParam, SizeOf(TVideoParam), 0, 40);
        if StreamAvParam^.bHaveAudio > 0 then
          IP_TPS_OpenStream(lRealHandle, @StreamAvParam^.AudioParam, SizeOf(TVideoParam), 1, 40);

          if _HDCameraControl.HsdVideoStream = lRealHandle then
          begin
            _HDCameraControl.HsdVideoParam := videoParam;
            lrect := Rect(FormMain.CameraPanel.Left + 1, FormMain.CameraPanel.Top + 1,
              FormMain.CameraPanel.left + FormMain.CameraPanel.Width,
              FormMain.CameraPanel.Top + FormMain.CameraPanel.Height);

            lrect := FormMain.CameraPanel.BoundsRect;

            IP_TPS_PlayByArea(lRealHandle, FormMain.CameraPanel.Handle, lrect);
          end;
      end;
    end;    // case

  except
    on e: Exception do
      WriteLog('[E]RealDataCallBack[lRealHandle：' + IntToStr(lRealHandle) + e.Message);
  end;
end;

constructor THDCameraControl.Create;
begin
  inherited Create;
end;

function GetFilePath(IPStr: string): string;
var
  I: Integer;
  IPStrEx: string;
begin
  IPStrEx := IPStr;
  for I := 1 to Length(IPStrEx) do    // Iterate
  begin
    if IPStrEx[I] = '.' then
      IPStrEx[I] := '-';
  end;    // for
  Result := IPStrEx;
end;

procedure THDCameraControl.InitHDCameraChannels;
var
  I: Integer;
  HDCameraIP: string;
begin
  //如果高清摄像头信息对象未初始化则退出
  if not Assigned(HDCamerasData) then Exit;
  try
    if IP_NET_DVR_Init <> 0 then Exit;
    if IP_NET_DVR_SetStatusEventCallBack(@StatusEventCallBack, self) <> 0 then Exit;
    if IP_NET_DVR_SetRealDataCallBack(nil, nil) <> 0 then Exit;
    with HDCamerasData do
    begin
      HDCameraIP := HDCameraData.IP;
      LoginChannel := IP_NET_DVR_Login(PChar(HDCameraIP), HDCameraData.THeadPort,
        PChar(HDUserName), PChar(HDPassword), nil);
    end;    // with
  except
    on e: Exception do
      WriteLog('[E]InitHDCameraChannels：' + e.Message);
  end;
end;

function THDCameraControl.StartHDRecord: Boolean;
var
  FilePath: string;
begin
  try
    if HsdVideoStream <= 0 then
      Result := False
    else begin
      FilePath := 'D:\DvrRecordFile\';
      FilePath := FilePath + GetFilePath(HDCamerasData.HDCameraData.IP);
      if not DirectoryExists(FilePath) then
        ForceDirectories(FilePath);

      IP_NET_DVR_StartRecord(HsdVideoStream, PChar(FilePath), HDCamerasData.HDCameraData.CameraLength, 315360000);
      Result := True;
    end;
  except
    Result := False;
  end;
end;

function THDCameraControl.StopAllHDRecord: Boolean;
var
  Index: Integer;
begin
  try
    {for Index := 1 to HDCamerasData.HDCameraCount do    // Iterate
    begin
      if HsdVideoStream[Index] > 0 then
        IP_NET_DVR_StopRecord(HsdVideoStream[Index]);
    end;
    Result := True;    }
  except
    Result := False;
  end;
end;

function THDCameraControl.StopHDRecord: Boolean;
begin
  try
    if HsdVideoStream > 0 then
      IP_NET_DVR_StopRecord(HsdVideoStream);
    Result := True;
  except
    Result := False;
  end;
end;

procedure THDCameraControl.WndProc(var Msg: Tmessage);
begin

end;

procedure WriteLog(msg: string);
var
  llst: TStringList;
begin
//  exit;
  llst := TStringList.Create;
  if FileExists('c:\' + inttostr(yearof(now)) + '-' + inttostr(monthof(now)) + '-' + inttostr(dayofthemonth(now)) + '.log') then
    llst.LoadFromFile('c:\' + inttostr(yearof(now)) + '-' + inttostr(monthof(now)) + '-' + inttostr(dayofthemonth(now)) + '.log');
  lLst.Add(DateTimeToStr(now) + '  ' + msg);
  lLst.SaveToFile('c:\' + inttostr(yearof(now)) + '-' + inttostr(monthof(now)) + '-' + inttostr(dayofthemonth(now)) + '.log');
  llst.Free;
end;

{ TDiskSpaceRecordThread }

function TDiskSpaceRecordThread.CheckOutFreeSpace: Boolean;
var
  iDiskSequence: Integer;
begin
  Result := False;  //默认未小于设定空间
//  iDiskSequence := GetDiskSequence(_DJLVideoControl.SaveFilePath[1]);
  if iDiskSequence = 0 then
    Result := False
  else begin
    if DiskFree(iDiskSequence) < MinFreeSpace then
      Result := True;
  end;
end;

constructor TDiskSpaceRecordThread.Create;
begin
  FreeOnTerminate := True;
  inherited Create(False);
end;

function TDiskSpaceRecordThread.DeleteOldRecordFile: Boolean;
  //删除指定目录及其包含的所有文件
  procedure DeleteFile(iFilePath: string);
  var
    lpFileOp: TSHFileOpStruct;
  begin
    with lpFileOp do
    begin
      wnd := self.handle;
      wFunc := FO_Delete;
      pFrom := PChar(iFilePath);
      pTo := nil;
      fFlags := FOF_SILENT + FOF_NOCONFIRMATION + FOF_NOERRORUI;//标志表明允许恢复，无须确认并不显示出错信息
      hNameMappings := nil;
      lpszProgressTitle := nil;
      fAnyOperationsAborted := true;
    end;
    SHFileOperation(lpFileOp);
  end;
var
  I, Index, FileCount: Integer;
  FileList: TStringList;
  FilePath, FilePathEx, FileName: string;
begin
  try
    Result := True;
//    FilePath := _DJLVideoControl.SaveFilePath;
    Delete(FilePath, Length(FilePath), 1);
    while FilePath[Length(FilePath)] <> '\' do
      Delete(FilePath, Length(FilePath), 1);
{    for I := 1 to HDCamerasData.HDCameraCount do    // Iterate
    begin
      FilePathEx := FilePath + GetFilePath(HDCamerasData.HDCameraData[I].IP);
      if not GetOldRecordFileName(FilePathEx + '\*.*', FileName) then
        continue;
      FileList := TStringList.Create;
      try
        FileList.CommaText := FileName;
        FileCount := Min(MaxDeleteFileNum, FileList.Count);
        for Index := 0 to FileCount - 1 do    // Iterate
          DeleteFile(FilePathEx + '\' + FileList.Strings[Index] + #0#0);
      finally
        FileList.Free;
      end;
    end;    // for       }
  except
    Result := False;
  end;
end;

procedure TDiskSpaceRecordThread.Execute;
begin
  Sleep(15000);
  RenameTempFile;
  Sleep(5000);
  while not Terminated do
  begin
    try
      if CheckOutFreeSpace then
      begin
{        case _DJLVideoControl.VideoRecordType of
          //非循环录像，直接停止所有录像   
          0: _HDCameraControl.StopAllHDRecord;
          //循环录像，删除最早的录像文件
          1: DeleteOldRecordFile;
        end;    // case                 }
      end;
    finally
      Sleep(300000);
    end;        
  end;    // while
end;

function TDiskSpaceRecordThread.GetDiskSequence(Dir: string): Integer;
begin
  Result:=0;
  if (Dir='A') or (Dir='a') then
    Result:=1
  else if (Dir='B') or (Dir='b') then
    Result:=2
  else if (Dir='C') or (Dir='c') then
    Result:=3
  else if (Dir='D') or (Dir='d') then
    Result:=4
  else if (Dir='E') or (Dir='e') then
    Result:=5
  else if (Dir='F') or (Dir='f') then
    Result:=6
  else if (Dir='G') or (Dir='g') then
    Result:=7
  else if (Dir='H') or (Dir='h') then
    Result:=8
  else if (Dir='I') or (Dir='i') then
    Result:=9
  else if (Dir='J') or (Dir='j') then
    Result:=10
  else if (Dir='K') or (Dir='k') then
    Result:=11
  else if (Dir='L') or (Dir='l') then
    Result:=12
  else if (Dir='M') or (Dir='m') then
    Result:=13
  else if (Dir='N') or (Dir='n') then
    Result:=14
  else if (Dir='O') or (Dir='o') then
    Result:=15
  else if (Dir='P') or (Dir='p') then
    Result:=16
  else if (Dir='Q') or (Dir='q') then
    Result:=17
  else if (Dir='R') or (Dir='r') then
    Result:=18
  else if (Dir='S') or (Dir='s') then
    Result:=19
  else if (Dir='T') or (Dir='t') then
    Result:=20
  else if (Dir='U') or (Dir='u') then
    Result:=21
  else if (Dir='V') or (Dir='v') then
    Result:=22
  else if (Dir='W') or (Dir='w') then
    Result:=23
  else if (Dir='X') or (Dir='x') then
    Result:=24
  else if (Dir='Y') or (Dir='y') then
    Result:=25
  else if (Dir='Z') or (Dir='z') then
    Result:=26;
end;

function TDiskSpaceRecordThread.GetOldRecordFileName(FilePath: string;
  var FileName: string): Boolean;
var
  Dir: TSearchRec;
begin
  try
    FileName := '';
    if FindFirst(FilePath, faAnyFile, Dir) = NO_ERROR then
    begin
      repeat
        if ((Dir.Attr and faAnyFile) = Dir.Attr) and (Dir.Name[1] <> '.') then
          FileName := FileName + ',' + Dir.Name;
        until FindNext(Dir) <> NO_ERROR;
        SysUtils.FindClose(Dir);
    end;
    if FileName <> '' then
    begin
      Delete(FileName, 1, 1);
      Result := True;
    end
    else Result := False;
  except
    Result := False;
  end;
end;

function TDiskSpaceRecordThread.GetTempFiles(FilePath: string;
  var FileName: string): Boolean;
var
  Dir: TSearchRec;
begin
  try
    FileName := '';
    if FindFirst(FilePath, faAnyFile, Dir) = NO_ERROR then
    begin
      repeat
        if ((Dir.Attr and faAnyFile) = Dir.Attr) then
          FileName := FileName + ',' + Dir.Name;
        until FindNext(Dir) <> NO_ERROR;
        SysUtils.FindClose(Dir);
    end;
    if FileName <> '' then
    begin
      Delete(FileName, 1, 1);
      Result := True;
    end
    else Result := False;
  except
    Result := False;
  end;
end;

function TDiskSpaceRecordThread.RenameTempFile: Boolean;
var
  I, Index, TempIndex, FileCount: Integer;
  FileList, TempFileList: TStringList;
  FilePath, FilePathEx, FileName, TempFile, TempFilePath, TempFileName: string;
begin
  try
{    Result := True;
    FilePath := _DJLVideoControl.SaveFilePath;
    Delete(FilePath, Length(FilePath), 1);
    while FilePath[Length(FilePath)] <> '\' do
      Delete(FilePath, Length(FilePath), 1);
    for I := 1 to HDCamerasData.HDCameraCount do    // Iterate
    begin
      FilePathEx := FilePath + GetFilePath(HDCamerasData.HDCameraData[I].IP);
      if not GetOldRecordFileName(FilePathEx + '\*.*', FileName) then
        continue;
      FileList := TStringList.Create;
      try
        FileList.CommaText := FileName;
        FileCount := Min(MaxRenameTempFileNum, FileList.Count);
        for Index := FileList.Count - FileCount to FileList.Count - 1 do
        begin
          TempFilePath := FilePathEx + '\' + FileList.Strings[Index];
          if not GetTempFiles(TempFilePath + '\*.temp', TempFileName) then
            continue;
          TempFileList := TStringList.Create;
          try
            TempFileList.CommaText := TempFileName;
            for TempIndex := 0 to TempFileList.Count - 1 do   // Iterate
            begin
              TempFile := ChangeFileExt(TempFilePath + '\' + TempFileList.Strings[TempIndex], '.avi');
              RenameFile(TempFilePath + '\' + TempFileList.Strings[TempIndex], TempFile);
            end;    // for
          finally
            TempFileList.Free;
          end;
        end;
      finally
        FileList.Free;
      end;
    end;    // for   }
  except
    Result := False;
  end;
end;

end.
