1 feat: Implementación de logging y código de verificación dinámico

2 
   3 - Se añade un sistema de logging que guarda todos los eventos y errores en el archivo 'hikvision-player.log'.
   4 - Se implementa un visor de logs en la pestaña 'Configuración' que lee y muestra el contenido del archivo de 
     log.
   5 - Se añade un botón 'Limpiar Log' para borrar el archivo de log y refrescar el visor.
   6 - Se mejora el detalle de los mensajes de error en los logs para incluir IP, puerto y canal, haciéndolos más 
     informativos.
   7 - Se añade un checkbox en la UI para habilitar o deshabilitar el uso del código de verificación del stream.
   8 - La inicialización del SDK ahora utiliza condicionalmente el código de verificación basado en esta 
     configuración.
   9 - Se actualiza la carga y guardado de la configuración para incluir el estado del nuevo checkbox.
This commit is contained in:
Pablinux
2025-11-19 10:47:04 -05:00
parent 099f3c2b3a
commit 7135b9d211
2 changed files with 1187 additions and 0 deletions

View File

@@ -0,0 +1,446 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
<NonVisualComponents>
<Container class="javax.swing.JPopupMenu" name="jPopupMenu1">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
<Property name="useNullLayout" type="boolean" value="true"/>
</Layout>
<SubComponents>
<MenuItem class="javax.swing.JMenuItem" name="menu_copiar">
<Properties>
<Property name="text" type="java.lang.String" value="Copiar"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menu_copiarActionPerformed"/>
</Events>
</MenuItem>
</SubComponents>
</Container>
</NonVisualComponents>
<Properties>
<Property name="defaultCloseOperation" type="int" value="3"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="3"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="jTabbedPane1" min="-2" pref="728" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jTabbedPane1" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="jTabbedPane1StateChanged"/>
</Events>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Vision en directo">
<Property name="tabTitle" type="java.lang.String" value="Vision en directo"/>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="panel_video" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Component id="jPanel2" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="panel_video" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jPanel2" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="panel_video">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="0" type="rgb"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="jPanel2">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="bt_conectar" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="bt_reproducir" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="544" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="bt_conectar" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bt_reproducir" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="bt_conectar">
<Properties>
<Property name="text" type="java.lang.String" value="Conectar"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bt_conectarActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="bt_reproducir">
<Properties>
<Property name="text" type="java.lang.String" value="play"/>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bt_reproducirActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jPanel3">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Configuracion">
<Property name="tabTitle" type="java.lang.String" value="Configuracion"/>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jScrollPane1" max="32767" attributes="0"/>
<Component id="jPanel4" alignment="0" max="32767" attributes="0"/>
<Component id="jPanel5" alignment="0" max="32767" attributes="0"/>
<Component id="jPanel6" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="bt_cargarConfig" min="-2" pref="216" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="bt_guardarConfig" min="-2" pref="216" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="bt_limpiarLogs" min="-2" pref="164" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jPanel4" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jPanel5" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jPanel6" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="340" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="bt_cargarConfig" alignment="3" min="-2" pref="46" max="-2" attributes="0"/>
<Component id="bt_guardarConfig" alignment="3" min="-2" pref="46" max="-2" attributes="0"/>
<Component id="bt_limpiarLogs" alignment="3" min="-2" pref="46" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel4">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="99" green="99" red="99" type="rgb"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txt_ip" min="-2" pref="266" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel4" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="txt_puerto" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cb_channel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txt_ip" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txt_puerto" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cb_channel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="cb_channel">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="4">
<StringItem index="0" value="1"/>
<StringItem index="1" value="2"/>
<StringItem index="2" value="3"/>
<StringItem index="3" value="4"/>
</StringArray>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JTextField" name="txt_puerto">
</Component>
<Component class="javax.swing.JTextField" name="txt_ip">
</Component>
<Component class="javax.swing.JLabel" name="jLabel3">
<Properties>
<Property name="text" type="java.lang.String" value="IP"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel4">
<Properties>
<Property name="text" type="java.lang.String" value="PUERTO"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel5">
<Properties>
<Property name="text" type="java.lang.String" value="CANAL"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="bt_cargarConfig">
<Properties>
<Property name="text" type="java.lang.String" value="Cargar Configuracion"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bt_cargarConfigActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="jPanel5">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="cc" green="cc" red="cc" type="rgb"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="37" max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txt_usr" min="-2" pref="260" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="txt_pasword" min="-2" pref="241" max="-2" attributes="0"/>
<EmptySpace pref="34" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txt_pasword" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txt_usr" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="txt_pasword">
</Component>
<Component class="javax.swing.JTextField" name="txt_usr">
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" value="Usuario"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" value="Contrase&#xf1;a"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="bt_guardarConfig">
<Properties>
<Property name="text" type="java.lang.String" value="Guardar Configuracion"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bt_guardarConfigActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="jPanel6">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="cc" green="cc" red="cc" type="rgb"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="ck_habilitaVerificacionCode" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="jLabel6" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="txt_videoCrypt" min="-2" pref="177" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="43" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txt_videoCrypt" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ck_habilitaVerificacionCode" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel6">
<Properties>
<Property name="text" type="java.lang.String" value="Codigo de Verificacion"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="txt_videoCrypt">
</Component>
<Component class="javax.swing.JCheckBox" name="ck_habilitaVerificacionCode">
<Properties>
<Property name="text" type="java.lang.String" value="Contrase&#xf1;a de Ecriptacion de flujo de video"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextPane" name="txtPane_consola">
<Properties>
<Property name="componentPopupMenu" type="javax.swing.JPopupMenu" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="jPopupMenu1"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="bt_limpiarLogs">
<Properties>
<Property name="text" type="java.lang.String" value="Limpiar Log"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bt_limpiarLogsActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,741 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JFrame.java to edit this template
*/
package com.telcotronics.hikvision.player;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.util.concurrent.ExecutionException;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
/**
*
* @author pablinux
*/
public class panel extends javax.swing.JFrame {
// SDK de Hikvision
private HCNetSDK hcNetSDK;
private NativeLong userID;
private NativeLong realHandle;
private Canvas videoCanvas;
private ConfigManager config;
private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(panel.class.getName());
public panel() {
initComponents();
setupLogging(); // Configure logging to file
config = new ConfigManager();
loadConfigToUI();
// Add action listener for the checkbox
ck_habilitaVerificacionCode.addActionListener(e -> {
txt_videoCrypt.setEnabled(ck_habilitaVerificacionCode.isSelected());
});
// Set initial state of txt_videoCrypt based on checkbox
txt_videoCrypt.setEnabled(ck_habilitaVerificacionCode.isSelected());
initSDK();
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
setupVideo();
}
@Override
public void windowClosing(WindowEvent e) {
cleanup();
}
});
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPopupMenu1 = new javax.swing.JPopupMenu();
menu_copiar = new javax.swing.JMenuItem();
jTabbedPane1 = new javax.swing.JTabbedPane();
jPanel1 = new javax.swing.JPanel();
panel_video = new javax.swing.JPanel();
jPanel2 = new javax.swing.JPanel();
bt_conectar = new javax.swing.JButton();
bt_reproducir = new javax.swing.JButton();
jPanel3 = new javax.swing.JPanel();
jPanel4 = new javax.swing.JPanel();
cb_channel = new javax.swing.JComboBox<>();
txt_puerto = new javax.swing.JTextField();
txt_ip = new javax.swing.JTextField();
jLabel3 = new javax.swing.JLabel();
jLabel4 = new javax.swing.JLabel();
jLabel5 = new javax.swing.JLabel();
bt_cargarConfig = new javax.swing.JButton();
jPanel5 = new javax.swing.JPanel();
txt_pasword = new javax.swing.JTextField();
txt_usr = new javax.swing.JTextField();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
bt_guardarConfig = new javax.swing.JButton();
jPanel6 = new javax.swing.JPanel();
jLabel6 = new javax.swing.JLabel();
txt_videoCrypt = new javax.swing.JTextField();
ck_habilitaVerificacionCode = new javax.swing.JCheckBox();
jScrollPane1 = new javax.swing.JScrollPane();
txtPane_consola = new javax.swing.JTextPane();
bt_limpiarLogs = new javax.swing.JButton();
menu_copiar.setText("Copiar");
menu_copiar.addActionListener(this::menu_copiarActionPerformed);
jPopupMenu1.add(menu_copiar);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTabbedPane1.addChangeListener(this::jTabbedPane1StateChanged);
panel_video.setBackground(new java.awt.Color(0, 0, 0));
panel_video.setLayout(new java.awt.BorderLayout());
jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
bt_conectar.setText("Conectar");
bt_conectar.addActionListener(this::bt_conectarActionPerformed);
bt_reproducir.setText("play");
bt_reproducir.setEnabled(false);
bt_reproducir.addActionListener(this::bt_reproducirActionPerformed);
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addComponent(bt_conectar)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(bt_reproducir)
.addContainerGap(544, Short.MAX_VALUE))
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(bt_conectar)
.addComponent(bt_reproducir))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(panel_video, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(panel_video, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
jTabbedPane1.addTab("Vision en directo", jPanel1);
jPanel4.setBackground(new java.awt.Color(153, 153, 153));
cb_channel.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "1", "2", "3", "4" }));
jLabel3.setText("IP");
jLabel4.setText("PUERTO");
jLabel5.setText("CANAL");
javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
jPanel4.setLayout(jPanel4Layout);
jPanel4Layout.setHorizontalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addGap(14, 14, 14)
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txt_ip, javax.swing.GroupLayout.PREFERRED_SIZE, 266, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel4)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(txt_puerto, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jLabel5)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cb_channel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
jPanel4Layout.setVerticalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txt_ip, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txt_puerto, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(cb_channel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel3)
.addComponent(jLabel4)
.addComponent(jLabel5))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
bt_cargarConfig.setText("Cargar Configuracion");
bt_cargarConfig.addActionListener(this::bt_cargarConfigActionPerformed);
jPanel5.setBackground(new java.awt.Color(204, 204, 204));
jLabel1.setText("Usuario");
jLabel2.setText("Contraseña");
javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
jPanel5.setLayout(jPanel5Layout);
jPanel5Layout.setHorizontalGroup(
jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel5Layout.createSequentialGroup()
.addGap(37, 37, 37)
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txt_usr, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txt_pasword, javax.swing.GroupLayout.PREFERRED_SIZE, 241, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(34, Short.MAX_VALUE))
);
jPanel5Layout.setVerticalGroup(
jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel5Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txt_pasword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txt_usr, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1)
.addComponent(jLabel2))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
bt_guardarConfig.setText("Guardar Configuracion");
bt_guardarConfig.addActionListener(this::bt_guardarConfigActionPerformed);
jPanel6.setBackground(new java.awt.Color(204, 204, 204));
jLabel6.setText("Codigo de Verificacion");
ck_habilitaVerificacionCode.setText("Contraseña de Ecriptacion de flujo de video");
javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
jPanel6.setLayout(jPanel6Layout);
jPanel6Layout.setHorizontalGroup(
jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup()
.addContainerGap()
.addComponent(ck_habilitaVerificacionCode)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel6)
.addGap(18, 18, 18)
.addComponent(txt_videoCrypt, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(43, 43, 43))
);
jPanel6Layout.setVerticalGroup(
jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel6Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel6)
.addComponent(txt_videoCrypt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(ck_habilitaVerificacionCode))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
txtPane_consola.setComponentPopupMenu(jPopupMenu1);
jScrollPane1.setViewportView(txtPane_consola);
bt_limpiarLogs.setText("Limpiar Log");
bt_limpiarLogs.addActionListener(this::bt_limpiarLogsActionPerformed);
javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
jPanel3.setLayout(jPanel3Layout);
jPanel3Layout.setHorizontalGroup(
jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jScrollPane1)
.addComponent(jPanel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jPanel5, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jPanel6, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel3Layout.createSequentialGroup()
.addComponent(bt_cargarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 216, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(bt_guardarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 216, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(bt_limpiarLogs, javax.swing.GroupLayout.PREFERRED_SIZE, 164, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
jPanel3Layout.setVerticalGroup(
jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel3Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 340, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(bt_cargarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(bt_guardarConfig, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(bt_limpiarLogs, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
jTabbedPane1.addTab("Configuracion", jPanel3);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 728, javax.swing.GroupLayout.PREFERRED_SIZE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jTabbedPane1)
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void bt_conectarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_conectarActionPerformed
if (bt_conectar.getText().equals("Conectar")) {
connectToDVRAsync();
//bt_conectar.setText("Desconectar");
//bt_reproducir.setEnabled(true);
} else {
bt_reproducir.setEnabled(false);
bt_conectar.setText("Conectar");
stopPreview(); // ⚠️ AGREGA ESTO
disconnectFromDVR();
}
}//GEN-LAST:event_bt_conectarActionPerformed
private void bt_reproducirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_reproducirActionPerformed
if (bt_reproducir.getText().equals("play")) {
startPreviewAsync();
bt_reproducir.setText("Stop");
} else {
stopPreview();
bt_reproducir.setText("play");
}
}//GEN-LAST:event_bt_reproducirActionPerformed
private void bt_guardarConfigActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_guardarConfigActionPerformed
saveConfigFromUI();
}//GEN-LAST:event_bt_guardarConfigActionPerformed
private void bt_cargarConfigActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_cargarConfigActionPerformed
config = new ConfigManager(); // Recarga desde el archivo
loadConfigToUI();
JOptionPane.showMessageDialog(this,
"Configuración recargada desde config.properties",
"Éxito", JOptionPane.INFORMATION_MESSAGE);
}//GEN-LAST:event_bt_cargarConfigActionPerformed
private void jTabbedPane1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jTabbedPane1StateChanged
if(jTabbedPane1.getSelectedIndex()==1){
cargar_logs();
}
}//GEN-LAST:event_jTabbedPane1StateChanged
private void bt_limpiarLogsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bt_limpiarLogsActionPerformed
try {
// Close all handlers on the root logger to release the file lock
for (java.util.logging.Handler handler : java.util.logging.Logger.getLogger("").getHandlers()) {
handler.close();
}
// Delete the file
java.nio.file.Files.deleteIfExists(java.nio.file.Paths.get("hikvision-player.log"));
// Re-initialize logging to create a new file
setupLogging();
// Refresh the text pane
cargar_logs();
logger.info("Log file cleared.");
} catch (java.io.IOException e) {
logger.log(java.util.logging.Level.SEVERE, "Failed to clear log file", e);
JOptionPane.showMessageDialog(this, "Error al limpiar el log: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}//GEN-LAST:event_bt_limpiarLogsActionPerformed
private void menu_copiarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menu_copiarActionPerformed
String textoACopiar = txtPane_consola.getText();
// 1. Obtener el portapapeles del sistema.
Clipboard portapapeles = Toolkit.getDefaultToolkit().getSystemClipboard();
// 2. Crear un objeto StringSelection con el texto.
StringSelection seleccion = new StringSelection(textoACopiar);
// 3. Colocar el StringSelection en el portapapeles.
portapapeles.setContents(seleccion, null);
System.out.println("El texto se ha copiado al portapapeles.");
}//GEN-LAST:event_menu_copiarActionPerformed
private void initSDK() {
try {
System.setProperty("jna.library.path", "./lib");
hcNetSDK = HCNetSDK.INSTANCE;
// >>> INICIO: CONFIGURAR CLAVE DE ENCRIPTACIÓN ANTES DE INICIALIZAR
if (config.getEnableVerificationCode()) {
String verificationCode = config.getVerificationCode();
if (verificationCode != null && !verificationCode.isEmpty()) {
logger.info("Intentando configurar código de verificación...");
HCNetSDK.NET_DVR_LOCAL_PROTECT_KEY_CFG keyCfg = new HCNetSDK.NET_DVR_LOCAL_PROTECT_KEY_CFG();
System.arraycopy(verificationCode.getBytes(), 0, keyCfg.byProtectKey, 0, verificationCode.length());
boolean success = hcNetSDK.NET_DVR_SetSDKLocalCfg(HCNetSDK.NET_SDK_LOCAL_CFG_TYPE_PROTECT_KEY, keyCfg.getPointer());
if (success) {
logger.info("Código de verificación configurado exitosamente.");
} else {
logger.severe("FALLO al configurar código de verificación. Error SDK: " + hcNetSDK.NET_DVR_GetLastError());
}
}
}
// <<< FIN: CONFIGURAR CLAVE DE ENCRIPTACIÓN
boolean init = hcNetSDK.NET_DVR_Init();
if (init) {
logger.info("SDK inicializado correctamente");
} else {
logger.severe("Error al inicializar SDK. Error SDK: " + hcNetSDK.NET_DVR_GetLastError());
}
} catch (Exception e) {
logger.log(java.util.logging.Level.SEVERE, "Error al cargar SDK", e);
JOptionPane.showMessageDialog(this,
"Error al cargar el SDK: " + e.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
}
private void setupVideo() {
// Asegurarse de que panel_video use BorderLayout para que el Canvas ocupe todo el panel
panel_video.setLayout(new BorderLayout());
videoCanvas = new Canvas();
videoCanvas.setBackground(Color.BLACK);
// AGREGAR LISTENER PARA HABILITAR EL BOTÓN CUANDO EL CANVAS ESTÉ LISTO
videoCanvas.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
// Una vez que el canvas tiene tamaño, habilitamos el botón de reproducir
// si ya estamos conectados.
if (userID != null && userID.longValue() > -1) {
bt_reproducir.setEnabled(true);
}
// Opcional: remover el listener para que no se ejecute más
videoCanvas.removeComponentListener(this);
}
});
// Hacer que el canvas sea visible y agregalo al panel
panel_video.removeAll();
panel_video.add(videoCanvas, BorderLayout.CENTER);
videoCanvas.setVisible(true);
panel_video.revalidate();
panel_video.repaint();
}
private void connectToDVRAsync() {
// Deshabilitar botón mientras conecta
bt_conectar.setEnabled(false);
bt_conectar.setText("Conectando...");
DVRConnectionWorker worker = new DVRConnectionWorker(
hcNetSDK,
config.getDvrIP(),
config.getDvrPort(),
config.getUsername(),
config.getPassword()
);
worker.execute();
// Manejar el resultado cuando termine
new Thread(() -> {
try {
ConnectionResult result = worker.get();
SwingUtilities.invokeLater(() -> {
if (result.success) {
userID = result.userID;
logger.info("Conectado. Canales: " + result.deviceInfo.byChanNum);
JOptionPane.showMessageDialog(this,
"Conectado exitosamente\n"
+ "Canales analógicos: " + result.deviceInfo.byChanNum + "\n"
+ "Canales IP: " + result.deviceInfo.byIPChanNum,
"Éxito", JOptionPane.INFORMATION_MESSAGE);
bt_conectar.setText("Desconectar");
// NO habilitar play aquí. El listener se encargará.
// Si el canvas ya tiene tamaño, el listener ya se disparó.
// Si no, se disparará pronto.
if (videoCanvas.getWidth() > 0 && videoCanvas.getHeight() > 0) {
bt_reproducir.setEnabled(true);
}
} else {
String errorMessage = String.format("Error al conectar. Código: %d. IP: %s, Puerto: %d",
result.errorCode, config.getDvrIP(), config.getDvrPort());
logger.severe(errorMessage);
JOptionPane.showMessageDialog(this,
errorMessage,
"Error", JOptionPane.ERROR_MESSAGE);
bt_conectar.setText("Conectar");
bt_reproducir.setEnabled(false);
}
bt_conectar.setEnabled(true);
});
} catch (InterruptedException | ExecutionException e) {
SwingUtilities.invokeLater(() -> {
logger.severe("Error en conexión: " + e.getMessage());
bt_conectar.setText("Conectar");
bt_conectar.setEnabled(true);
bt_reproducir.setEnabled(false);
});
}
}).start();
}
private void startPreviewAsync() {
if (userID == null || userID.intValue() < 0) {
JOptionPane.showMessageDialog(this,
"Primero conecte al DVR",
"Advertencia", JOptionPane.WARNING_MESSAGE);
return;
}
bt_reproducir.setEnabled(false);
bt_reproducir.setText("Iniciando...");
PreviewWorker worker = new PreviewWorker(
hcNetSDK,
userID,
config.getChannel(),
config.getStreamType(),
videoCanvas
);
worker.execute();
new Thread(() -> {
try {
PreviewResult result = worker.get();
SwingUtilities.invokeLater(() -> {
if (result.success) {
realHandle = result.realHandle;
logger.info("Preview iniciado en canal " + config.getChannel());
bt_reproducir.setText("Parar");
} else {
String errorMessage = String.format("Error al iniciar video. Código: %d. Canal: %d",
result.errorCode, config.getChannel());
logger.severe(errorMessage);
JOptionPane.showMessageDialog(this,
errorMessage,
"Error", JOptionPane.ERROR_MESSAGE);
bt_reproducir.setText("play");
}
bt_reproducir.setEnabled(true);
});
} catch (InterruptedException | ExecutionException e) {
SwingUtilities.invokeLater(() -> {
logger.severe("Error en preview: " + e.getMessage());
bt_reproducir.setText("play");
bt_reproducir.setEnabled(true);
});
}
}).start();
}
private void stopPreview() {
if (realHandle != null && realHandle.intValue() >= 0) {
hcNetSDK.NET_DVR_StopRealPlay(realHandle);
logger.info("Preview detenido");
realHandle = null;
}
}
private void disconnectFromDVR() {
stopPreview();
if (userID != null && userID.intValue() >= 0) {
hcNetSDK.NET_DVR_Logout(userID);
logger.info("Desconectado del DVR");
userID = null;
}
}
private void cleanup() {
disconnectFromDVR();
if (hcNetSDK != null) {
hcNetSDK.NET_DVR_Cleanup();
logger.info("SDK limpiado");
}
}
// Cargar configuración a los campos de la UI
private void loadConfigToUI() {
txt_ip.setText(config.getDvrIP());
txt_puerto.setText(String.valueOf(config.getDvrPort()));
txt_usr.setText(config.getUsername());
txt_pasword.setText(config.getPassword());
cb_channel.setSelectedItem(String.valueOf(config.getChannel()));
txt_videoCrypt.setText(config.getVerificationCode());
ck_habilitaVerificacionCode.setSelected(config.getEnableVerificationCode());
txt_videoCrypt.setEnabled(ck_habilitaVerificacionCode.isSelected()); // Set initial state
}
// Guardar configuración desde los campos de la UI
private void saveConfigFromUI() {
try {
config.setDvrIP(txt_ip.getText().trim());
config.setDvrPort(Integer.parseInt(txt_puerto.getText().trim()));
config.setUsername(txt_usr.getText().trim());
config.setPassword(txt_pasword.getText().trim());
config.setChannel(Integer.parseInt((String) cb_channel.getSelectedItem()));
config.setVerificationCode(txt_videoCrypt.getText().trim());
config.setEnableVerificationCode(ck_habilitaVerificacionCode.isSelected());
config.saveConfig();
JOptionPane.showMessageDialog(this,
"Configuración guardada exitosamente",
"Éxito", JOptionPane.INFORMATION_MESSAGE);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this,
"Error: Puerto y Canal deben ser números",
"Error", JOptionPane.ERROR_MESSAGE);
}
}
private void setupLogging() {
try {
java.util.logging.FileHandler fileHandler = new java.util.logging.FileHandler("hikvision-player.log", true); // true for append
java.util.logging.SimpleFormatter formatter = new java.util.logging.SimpleFormatter();
fileHandler.setFormatter(formatter);
java.util.logging.Logger.getLogger("").addHandler(fileHandler);
logger.info("Logging to file configured.");
} catch (java.io.IOException | SecurityException e) {
logger.log(java.util.logging.Level.SEVERE, "Failed to set up logging to file", e);
}
}
private void cargar_logs(){
try {
String content = new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get("hikvision-player.log")));
txtPane_consola.setText(content);
} catch (java.io.IOException e) {
txtPane_consola.setText("Error al cargar el archivo de log: " + e.getMessage());
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ReflectiveOperationException | javax.swing.UnsupportedLookAndFeelException ex) {
logger.log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(() -> new panel().setVisible(true));
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bt_cargarConfig;
private javax.swing.JButton bt_conectar;
private javax.swing.JButton bt_guardarConfig;
private javax.swing.JButton bt_limpiarLogs;
private javax.swing.JButton bt_reproducir;
private javax.swing.JComboBox<String> cb_channel;
private javax.swing.JCheckBox ck_habilitaVerificacionCode;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JLabel jLabel6;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JPanel jPanel4;
private javax.swing.JPanel jPanel5;
private javax.swing.JPanel jPanel6;
private javax.swing.JPopupMenu jPopupMenu1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTabbedPane jTabbedPane1;
private javax.swing.JMenuItem menu_copiar;
private javax.swing.JPanel panel_video;
private javax.swing.JTextPane txtPane_consola;
private javax.swing.JTextField txt_ip;
private javax.swing.JTextField txt_pasword;
private javax.swing.JTextField txt_puerto;
private javax.swing.JTextField txt_usr;
private javax.swing.JTextField txt_videoCrypt;
// End of variables declaration//GEN-END:variables
}