unit UMainRTSP; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, MPVBasePlayer, Vcl.ExtCtrls, System.IniFiles, Vcl.StdCtrls, System.IOUtils; const CLR_BG = TColor($002A170F); // #0F172A CLR_PANEL = TColor($0045342D); // #1E293B (alpha overlay over #0F172A) CLR_PANEL2 = TColor($0045342D); // consistent panel color CLR_GREEN = TColor($0050AF4C); // #4CAF50 CLR_RED = TColor($005252FF); // #FF5252 CLR_WHITE = TColor($00FFFFFF); CLR_GRAY = TColor($00B8A394); // #94A3B8 WIDGET_W = 380; WIDGET_H = 220; WIDGET_GAP = 16; SIDEBAR_W = 350; type TfrmMainRTSP = class(TForm) pnlCCTVButtons: TPanel; pnlCCTVVideo: TPanel; lstCameras: TListBox; lblDateTime: TLabel; btnFullscreen: TPanel; lblFullscreenText: TLabel; Panel1: TPanel; lblCloseText: TLabel; TimerTime: TTimer; procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); procedure OnPlayCameraClick(Sender: TObject); procedure TimerTimeTimer(Sender: TObject); procedure lblFullscreenTextClick(Sender: TObject); procedure lblCloseTextClick(Sender: TObject); private { Private declarations } FMpv: TMPVBasePlayer; FActiveCameraIdx: Integer; procedure BuildCCTVGrid; procedure LoadSettings; function MakeDynButton(AParent: TWinControl; const AText: string; ATag: Integer; AEvent: TNotifyEvent): TPanel; public { Public declarations } end; var frmMainRTSP: TfrmMainRTSP; implementation {$R *.dfm} procedure TfrmMainRTSP.FormCreate(Sender: TObject); begin lblCloseText.Align := alClient; lblFullscreenText.Align := alClient; lblDateTime.Caption := FormatDateTime('yyyy-mm-dd hh:nn:ss', Now); LoadSettings; BuildCCTVGrid; WindowState := wsMaximized; end; function TfrmMainRTSP.MakeDynButton(AParent: TWinControl; const AText: string; ATag: Integer; AEvent: TNotifyEvent): TPanel; var P: TPanel; L: TLabel; begin P := TPanel.Create(Self); P.Parent := AParent; P.Left := 0; P.Top := 0; P.Width := 160; P.Height := 80; P.Color := CLR_PANEL2; P.BevelOuter := bvNone; P.ParentBackground := False; P.ParentColor := False; P.Caption := ''; P.Cursor := crHandPoint; P.Tag := ATag; P.OnClick := AEvent; L := TLabel.Create(Self); L.Parent := P; L.Align := alClient; L.Layout := tlCenter; L.Caption := AText; L.Font.Size := 20; L.Font.Color := CLR_WHITE; L.Font.Style := [fsBold]; L.Transparent := True; L.AutoSize := False; L.SetBounds(6, 6, 148, 65); L.Alignment := taCenter; L.Tag := ATag; L.OnClick := AEvent; Result := P; end; procedure TfrmMainRTSP.LoadSettings; var Ini: TIniFile; i, Count: Integer; S, SP: string; begin SP := TPath.Combine(TPath.GetHomePath, 'SmartFarmHMI_settings.ini'); Ini := TIniFile.Create(SP); try lstCameras.Clear; Count := Ini.ReadInteger('CCTV', 'Count', 0); for i := 0 to Count-1 do begin S := Ini.ReadString('CCTV', 'Cam'+IntToStr(i), ''); if S <> '' then lstCameras.Items.Add(S); end; finally Ini.Free; end; end; procedure TfrmMainRTSP.OnPlayCameraClick(Sender: TObject); var URL: string; VTag, k: Integer; ClickedBtn: TPanel; begin if Sender is TPanel then VTag := (Sender as TPanel).Tag else if Sender is TLabel then VTag := (Sender as TLabel).Tag else Exit; // ¸ðµç Ä«¸Þ¶ó ¹öư »ö ÃʱâÈ­ ÈÄ Å¬¸¯µÈ ¹öư °­Á¶ ClickedBtn := nil; for k := 0 to pnlCCTVButtons.ControlCount-1 do if pnlCCTVButtons.Controls[k] is TPanel then begin TPanel(pnlCCTVButtons.Controls[k]).Color := CLR_PANEL2; if TPanel(pnlCCTVButtons.Controls[k]).Tag = VTag then ClickedBtn := TPanel(pnlCCTVButtons.Controls[k]); end; if ClickedBtn <> nil then ClickedBtn.Color := TColor($00226622); FActiveCameraIdx := VTag; if (VTag >= 0) and (VTag < lstCameras.Count) then begin URL := lstCameras.Items[VTag]; // ±âÁ¸ Ç÷¹À̾î Á¤¸® if FMpv <> nil then begin FMpv.Stop; FreeAndNil(FMpv); end; if URL.StartsWith('rtsp://', True) or URL.StartsWith('http://', True) or URL.StartsWith('https://', True) then begin FMpv := TMPVBasePlayer.Create; FMpv.InitPlayer(IntToStr(pnlCCTVVideo.Handle), '', '', ''); FMpv.SetMute(True); FMpv.OpenFile(PChar(URL)); end else begin try except on E: Exception do ShowMessage('¹Ìµð¾î ÆÄÀÏÀ» Àç»ýÇÒ ¼ö ¾ø½À´Ï´Ù: ' + E.Message); end; end; end; end; procedure TfrmMainRTSP.TimerTimeTimer(Sender: TObject); begin lblDateTime.Caption := FormatDateTime('yyyy-mm-dd hh:nn:ss', Now); end; procedure TfrmMainRTSP.BuildCCTVGrid; var i: Integer; Btn: TPanel; LText: string; begin for i := 0 to lstCameras.Count-1 do begin LText := 'Camera '+IntToStr(i+1); Btn := MakeDynButton(pnlCCTVButtons, LText, i, OnPlayCameraClick); Btn.Top := 8; Btn.Left := 10 + i*170; if i = FActiveCameraIdx then Btn.Color := TColor($00226622); // Ȱ¼º Ä«¸Þ¶ó ¹öư °­Á¶ end; // µî·ÏµÈ Ä«¸Þ¶ó°¡ ÀÖÀ¸¸é ù ¹øÂ° Ä«¸Þ¶ó ÀÚµ¿ Àç»ý if lstCameras.Count > 0 then OnPlayCameraClick(pnlCCTVButtons.Controls[0]); end; procedure TfrmMainRTSP.FormDestroy(Sender: TObject); begin if FMpv <> nil then begin FMpv.Stop; FreeAndNil(FMpv); end; end; procedure TfrmMainRTSP.lblCloseTextClick(Sender: TObject); begin Close; end; procedure TfrmMainRTSP.lblFullscreenTextClick(Sender: TObject); begin if WindowState = wsMaximized then begin WindowState := wsNormal; BorderStyle := bsSizeable; end else begin BorderStyle := bsNone; WindowState := wsMaximized; end; end; end.