Archivo de la categoría: C#

Cosas varias sobre programación con c#

C Sharp y .Net Core con Linux

.Net Core permite la portabilidad de nuestras aplicaciones ha cualquier sistemas, ya sea Linux, OSx o Windows.

La nueva versión del framework .Net nos permite desarrollar nuestras aplicaciones y poder ejecutarlas en cualquier sistema.

.Net Core logo

Como en Linux, pudiendo compilar nuestro código en las distribuciones más populares, como RedHat, Fedora, Suse, CentOS, Oracle, Debian, Linux Mint, Ubuntu, etc. .En sistemas Linux solo podremos crear aplicaciones en 64 bits. Para sistemas de microsoft podemos crear aplicaciones, no solo para pc’s, donde podemos personalizar la compilación desde versiones 7 de windows, hasta la

ultima de windows 10, pero también podemos compilar nuestros códigos para la XBox, la Raspberry Pi 3, con Windows 10, tanto para versiones de 32 como de 64. Para sistemas de apple podemos compilar para las versiones 10 de OSx, en concreto para las versiones 10.10, 10.11 y 10.12, solo en 64 bits. También podemos hacer correr nuestros programas en Android, aunque para este ultimo no esta muy preparado.

Como instalar .Net Core en Ubuntu.

En mi caso la instalación del framework de .Net Core lo he realizado en mi sistema con Ubuntu 17.04. Para ello tenemos que agregar las fuentes donde se encuentra el framework. Para que nuestro Ubuntu nos reconozca estas fuentes como fuentes seguras, lo primero que debemos hacer es agregar las firmas de estas.

Una vez que ya tenemos añadidas las firmas, añadimos la direccion del repositorio donde esta alojado el framework del .Net Core.

Este repositorio es para la versión 17.04 de Ubuntu, si necesitas instalar el framework en otra versión puedes ir a esta pagina ( https://www.microsoft.com/net/core#linuxubuntu ) para encontrar las direcciones para versiones anteriores de Ubuntu.

Una vez que tengamos el repositorio cargado, actualizamos las librerías de nuestro Ubuntu.

E instalamos el framework de .Net Core.

En este caso es la versión 2.0 del .Net Core, ultima versión a la fecha de escribir este post.

Llegados a este punto ya podemos desarrollar nuestra aplicación en C#. El framework nos proporciona una serie de comandos, tanto para crear unas plantillas que nos facilitara la creación de nuestras aplicaciones, como para la compilación o la publicación de la aplicación.

Crear un nuevo proyecto con .Net Core en C#

Para probar si todo funciona correctamente, podemos crear la típica aplicación de “Hola mundo”, para ellos solo tenemos que crear un proyecto de tipo “Console”.

Esta crea en la carpeta que le indiquemos un proyecto en lenguaje C# para ejecutarse en la consola de Linux, o de cualquier otro sistema compatible.

Si estamos usando la versión 1.0 de .Net Core, después de crear el nuevo proyecto, del tipo que sea, tendremos que ejecutar el comando “dotnet restore” para restaurar el árbol de dependencias del proyecto. En el caso de estar utilizando la versión 2.0, esto no es necesario, ya que este proceso esta incluido en la ejecución del comando “dotnet new”.

Ejecutar el proyecto .Net Core

Para probar la aplicación podemos utilizar el comando de compilar y ejecutar nuestro.

Este comando compilara y ejecutara el proyecto que se encuentre en el directorio. Si queremos indicarle donde se encuentra el proyecto tendremos que utilizar le parámetro “-p” seguido de la ruta donde se encuentre nuestro proyecto.

 Publicar un proyecto en .Net Core

Para distribuir nuestro proyecto debemos crear el paquete con nuestro ejecutable y todas sus dependencias. Para esto debemos usar el comando “dotnet publish”. Este comando nos creara una carpeta con todos los ficheros necesarios para la distribucion de la aplicación

Con el parametro “-c” le indicamos que utilice la configuración para crear un compilado utilizado el tipo “Release”. Si no se indica este paramentro, se utilizara por defecto “Debug”.

El parámetro “-o” le indicamos la carpeta donde queremos que nos cree el paquete. Si no indicamos este parámetro lo creara en una carpeta dentro de la propia del proyecto.

El parámetro “-r” le indicamos que “runtime” o RID se va utilizar para crear la distribución. En este punto es donde le indicamos bajo que sistema operativo queremos que se ejecute nuestra distribución. Si no indicamos este parámetro, el paquete que se cree sera para el sistema operativo bajo el que estemos ejecutando el programa.

Las diferentes opciones son las siguiente:

RID de Windows
  • Portátil
  • win-x86
  • win-x64

Windows 7/Windows Server 2008 R2

  • win7-x64
  • win7-x86

Windows 8/Windows Server 2012

  • win8-x64
  • win8-x86
  • win8-arm

Windows 8.1/Windows Server 2012 R2

  • win81-x64
  • win81-x86
  • win81-arm

Windows 10/Windows Server 2016

  • win10-x64
  • win10-x86
  • win10-arm
  • win10-arm64
RID de Linux

Portátil

  • linux-x64

CentOS

  • centos-x64
  • centos.7-x64

Debian

  • debian-x64
  • debian.8-x64

Fedora

  • fedora-x64
  • fedora.24-x64
  • fedora.25-x64 (.NET Core 2.0 o versiones posteriores)
  • fedora.26-x64 (.NET Core 2.0 o versiones posteriores)

Gentoo (.NET Core 2.0 o versiones posteriores)

  • gentoo-x64

openSUSE

  • opensuse-x64
  • opensuse.42.1-x64

Oracle Linux

  • ol-x64
  • ol.7-x64
  • ol.7.0-x64
  • ol.7.1-x64
  • ol.7.2-x64

Red Hat Enterprise Linux

  • rhel-x64
  • rhel.6-x64 (.NET Core 2.0 o versiones posterores)
  • rhel.7-x64
  • rhel.7.1-x64
  • rhel.7.2-x64
  • rhel.7.3-x64 (.NET Core 2.0 o versiones posteriores)
  • rhel.7.4-x64 (.NET Core 2.0 o versiones posteriores)

Tizen (.NET Core 2.0 o versiones posteriores)

  • tizen

Ubuntu

  • ubuntu-x64
  • ubuntu.14.04-x64
  • ubuntu.14.10-x64
  • ubuntu.15.04-x64
  • ubuntu.15.10-x64
  • ubuntu.16.04-x64
  • ubuntu.16.10-x64

Derivados de Ubuntu

  • linuxmint.17-x64
  • linuxmint.17.1-x64
  • linuxmint.17.2-x64
  • linuxmint.17.3-x64
  • linuxmint.18-x64
  • linuxmint.18.1-x64 (.NET Core 2.0 o versiones posteriores)
RID de OS X
  • osx-x64 (.NET Core 2.0 o versiones posteriores)
  • osx.10.10-x64
  • osx.10.11-x64
  • osx.10.12-x64 (.NET Core 1.1 o versiones posteriores)
RID de Android (.NET Core 2.0 o versiones posteriores)
  • android
  • android.21

 

Esto seria lo básico para poder desarrollar en .Net Core bajo Linux.

Para facilitar el desarrolo en .Net  hay varias extensiones para  los principales editores que los desarrollados solemos utilizar, como puede Atom, Brackets, Sublime Text, Emacs, Vim o Visual Studio Code.

Hacer ping con visual C#

h-pingLa forma más fácil de comprobar que un equipo esta “vivo” en nuestra red es haciendo un ping. Lo que hace este comando es enviar un paquete ICMP al equipo que queremos verificar, el equipo al recibir este paquete devuelve una confirmación de recepción. Con esta acción ya hemos comprobado que el equipo esta funcionando y conectado.

Cuando nuestro programa en Visual C# tiene que conectarse a cualquier otro equipo, nos puede interesar antes de ejecutar las funciones de conexión es si ese equipo esta disponible o no. Podemos confirmarlo fácilmente haciéndole un ping.

Hacer ping con Visual C#

En la biblioteca de .Net “System.Net.NetworkInformation” tenemos disponible una función que nos hará ese trabajo. Para poder usarla tendremos que agregar a nuestro proyecto la siguiente referencia “System.Net”, podemos agregar tambien el namespace “System.Net.NetworkInformation” para facilitar el trabajo con las funciones.

Para hacer ping tendremos que crear dos objetos, un objeto “ping” como tal, este el que enviara el paquete ICMP. Y el objeto PingReply, este manejara la información devuelta.

Ejemplo de uso:

Explicación:

Creamos el objeto Ping.

Creamos una variable de tipo “int” para almacenar el tiempo de espera, este valor esta en milisegundos.

Creamos el objeto PingReply para el manejo de la respuesta del ping.

Variable de tipo “string” donde guardaremos la dirección IP del equipo que queremos verificar.

Hacemos el Ping, le pasamos como parámetros los la dirección Ip que queremos comprobar y el valor de tiempo de espera en milisegundos, este ultimo parámetro es opcional, indicándole la dirección Ip o el nombre del equipo seria suficiente. La respuesta se la pasamos al objeto PingReply.

Para comprobar el estado comprobamos el valor que nos devuelve PingReply.Status, este valor es del tipo “IPStatus”. Para saber si ha sido satisfactorio solo tenemos que comprobar que el estado es “IPStatus.Success”. Si se ha producido un error podemos comprobar el tipo de estado devuelto del “IPStatus”. Más información sobre “IPStatus” en la librería de MSDN

Desde el objeto PingReply podemos obtener otras informaciones, como puede ser la dirección Ip de la maquina remota, el tiempo que se ha tardado en realizar, valor devuelto en milisegundos, opciones que se ha utilizado para el envio del paquete ICMP o el buffer de los datos recibidos por el ICMP.

Personalizar la serialización de tipos en XML

Serialización con XML
Serialización con XML

Cuando queremos guardar en fichero XML alguna estructura de datos podemos recurrir a la serialización.

Con las funciones actuales disponibles para el manejo de XML en C# la serialización de estructuras de datos es relativamente sencilla. Pero el problema nos surge cuando en la estructura de datos hay algún tipo de objeto que, o no nos interesa el modo en que hace la conversión, por la razón que sea, o por que la serialización de ese objeto no esta soportada.

Para solucionar este problema C# nos proporciona los atributos [XMLIgnore], para indicarle al proceso de serialización que ignore ese objeto, y [XmlElement], donde le indicamos como se va ha convertir ese objeto.

Para indicar al proceso de serialización del XML que ese objeto lo ignore, solo tendremos que anteponer el atributo [XMLIgnore] delante del objeto que queremos. Por ejemplo:

En este caso el tipo “Image” no soporta serialización, por lo que la conversión la tendremos que realizar nosotros mismos.

Una que le hemos dicho que ignore ese objeto le tenemos que indicar como vamos a convertirlo. Para ello tendremos que crear nuestra función de conversión he indicarle que la use en para ese elemento. Para indicarle que objeto vamos a utilizar solo tenemos que utilizar el atributo [XmlElement(“Nombre_del_objeto”], le indicamos el nombre que le hemos dado al objeto, no el tipo. Por ejemplo:

En el ejemplo se utiliza el objeto “Imagen” del ejemplo anterior que es de tipo “Image”, que no esta soportado por la serialización de XML. Lo que hacemos es convertilo en un array de byte para poderlo guardar en el fichero.

La parte del “get” la serialización de XML la utilizara cuando va ha grabar los datos, leeremos desde el objeto “Imagen” la imagen que queremos y con ayuda de la función “ImageConverter” la convertimos en un array de byte, le indicamos el formato que vamos a utilizar en el segundo parámetro que le pasamos a la función en este caso “typeof(byte[]).

La parte del “set” la serialización de XML la usa cuando lee los datos desde el fichero de XML. Le pasara la cadena de byte que tiene grabada y cargara en la variable “Imagen” la imagen es su formato correcto, tipo “Image”. Para la conversión volvemos a utilizar la función “ImageConverter”, en este caso nos devolverá un objeto, para pasárselo a la variable solo tenemos que indicar que ese objeto es de tipo “Image”

Si lo aplicamos a un objeto que es de un tipo soportado por la serialización de XML, lo que hará, sera ignorar su método de serialización y utilizar el que le indiquemos.

Si tienes alguna sugerencia sera bienvenida, deja un comentario.

Ajustar color de la fuente según el color de fondo en Visual C#

En ocasiones podemos necesitar ajustar el color de la fuente según el color del fondo del control. Por ejemplo poner el color de la fuente a blanco, por que el color del fondo es negro, o de cualquier otro color oscuro.

Esto se puede hacer calculando en nivel del color. Para este calculo yo utilizo la siguiente formula.

Lo que hacemos es crear un coeficiente multiplicando cada valor de los calores básico por un coeficiente, ya que según el color básico hará que el color final sea mas o menos oscuro. Y por ultimo sumamos los resultado.

Según el valor devuelto podemos jugar con el color que deseemos.

Por ejemplo, si el coeficiente “coefienteOscuridad” es superior a 100, el color de la fuente sera negro, y por el contrario si el coeficiente es inferior el color de la fuente lo pongo a blanco.

El valor 100 lo he sacado de probar diferentes colores y ver como se distingue el texto.

Podemos jugar con el para ajustar el color de la fuente al color que más se ajuste a nuestras necesidades.

Ejemplo completo, en este ejemplo ajusta el color de la fuente, ha blanco o negro, de una celda de un dataGridView según el color de fondo de la celda:

Y con esto ya tendríamos ajustado el color de nuestra fuente para que sea totalmente legible, independientemente del color del fondo.

Si tienes alguna sugerencia o duda, no tengas ningún reparo en escribir un comentario.

Ejecutar aplicaciones con permisos de administrador en Visual Studio c#

En algunas ocasiones necesitamos que nuestras aplicaciones se ejecuten con lo privilegios de administrador. Para hacer esto en una aplicación desarrollada con Visual C# tenemos que añadir a nuestro proyecto un fichero de “Archivo de manifiesto de aplicación”. Para agregar el fichero, accedemos “Proyecto” – “Agregar nuevo elemento”, y seleccionamos “Archivo de manifiesto de aplicación”.

Captura_Agregar_Nuevo_Elemento

Esto nos creara el fichero “app.manifest”.

Captura_Archivo_manifiesto_aplicacion
Este fichero contiene varias opciones de configuración, pero las opciones que nos interesan son:

requestedPrivileges
En la parte comentada nos muestra los niveles disponibles:

asInvoke: Nivel de seguridad por defecto.

requireAdministrator: Nivel de seguridad como administrador.

highestAvailable: Nivel de seguridad el mayor posible.

Para indicar que nuestra aplicación va a trabajar con nivel de seguridad de administrador, solo tenemos que copiar la linea:

requestedExecutionLevel_administrador
de la parte comentada, y sobre escribir:

de la parte no comentada.

requestedExecutionLevel_administrador_sobreescrito
Después de guardar los cambios, si le damos al botón de “Inicar”, el Visual Studio se reiniciara para ejecutarse con permisos de administrado.

Si ejecutamos el ejecutable de la aplicación nos mostrar la típica ventana para aceptar los privilegios de administrador.

OPC el idioma de los sistemas industriales

La comunicación de los sistemas industriales siempre a sido un tema muy complicado. Cada fabricante de plc’s utilizaba un sistema de comunicación propio, sin ofreces ningún tipo de información a tercera partes para poder realizar productos que pudieran trabajar con el. Esto hacia que el montaje de un sistema fuera complicado, ya que te tenias que basar en los productos que el fabricante elegido te ofrecía.

PROBLEOPC

Pero esto, se terminó con la aparición del sistema OPC, (OLE for Process Control, por sus siglas en ingles) es un sistema creado en un principio por Microsoft para la comunicación de sistemas industriales. En la actualidad este estándar esta gestionado por la fundación OPC Foundation. La aparición de este protocolo ha permitido una comunicación mas fácil entre los sistemas de control, sistemas SCADA, HMI, etc. con los sistemas de control, PLC’s.

SOLUCIOPC

En un principio este estándar se basó en la tecnología de Microsoft, Este, se baso en la tecnologia OLE, que emplea el formato COM/DCOM, que Micorosft desarrolo para el intercambio de innfomarcion entre aplicaciones y sistemas, como es normal, pero con el traspaso de la gestión a la fundación, esta ha impulsado un sistema libre, sin basarse en ninguna tecnología propietaria.

Por eso en la actualidad, con la versión UA, se puede encontrar desarrollos de sistemas OPC para cualquier sistema, ya se Windows, Linux, OsX, etc. Aunque el sistema principal, y el que dispone de un mayor catalogo de productos para el desarrollo sigue siendo Windows. Esto es debido en parte utilización de este sistema por parte de la industria de equipos industriales.

RTEmagicC_oemgatewayproxy_08.png

En la actualidad podemos encontrar librerías para el desarrollo para cualquier sistema, .Net, Python, Java, etc.

 

 

Crear gráficos de datos en c#

graph_fixed_x_rangeLa mejor formar de ver y entender los datos que capturamos desde nuestros sensores, es mediante la utilización de gráficos.

Si trabajamos con C# esta tarea es relativamente sencilla, gracias al controlador que por defecto trae el Visual C#. Este controlador nos permite crear gráficos de diferentes formas, de lineas, tarta, columnas,  puntos, etc.

Los datos se los podemos facilitar tanto en tiempo real añadiéndolos directamente los valores al gráfico, o mediante una base de datos.

Para añadir el gráfico a nuestro formulario solo tendremos que añadir el controlador “Chart” que se encuentra dentro de la sección “Datos”.

Con esto, ya podríamos empezar a mostrar nuestros datos, el tipo de gráfico por defecto es un gráfico de columnas. para añadir los datos solo tendríamos que utilizar el siguiente comando.

Pero el sistema de gráficos de columnas no es que sea el más idóneo para mostrar la información de sensores, lo normal sera utilizar un gráfico de lineas, para cambiar el tipo de gráficos tendremos que ir  a:

  1. Propiedades del gráfico
  2. Series, Seleccionar la serie que queremos modificar (por defecto “Series1”.
  3.   En la sección “Gráfico”, en “ChartType”, seleccionar el tipo de gráfico.
  4.  Pulsar en “Aceptar”, y listo ya tenemos cambiado nuestro tipo de gráfico.

Si lo queremos hacer mediante código, tendremos que introducir la siguiente instrucción:

En la parte de “Series[“Series1″]”, en este caso hacemos la llamada utilizando el nombre de la serie, en este caso es el de por defecto “Series1”, también podemos hacer la llamada utilizando su posición en la lista de las series, acordándose que toda lista empiezan en el “0” (cero). Esto “Series[“Series1″]”, y esto “Series[0]”, seria lo mismo.

Y con esto ya tendríamos creado nuestro gráfico y seleccionado el tipo de gráfico para la muestra de datos básica, pero funcional.

Ejemplo simple de lo descrito en el artículo, ejemplo creado con Visual Studio Express 2012:

Como recorrer todos los componentes de un form o un panel

En determinadas ocasiones tenemos que realizar una misma operación en todos los componentes, ya sean iguales o distintos, que están en un formulario, dentro de un panel, etc.

Lo mas fácil seria ir uno por uno haciendo el cambio deseado, si son unos pocos, no seria mucho problemas, pero cuando son muchos esto puede ser un engorro, pudiendo llevarnos a introducir errores en nuestros código.

Otra opción es ir recorriendo todos los componentes que están dentro de nuestro formulario y comprobar de que clase es, y si es del tipo que tenemos que hacer el cambio, entonces pasamos a hacérselo.

Esto lo podemos hacer de la siguiente forma:

Para saber cuantos componentes tiene nuestro formulario utilizaremos la opción “Controls”.  Este tiene varios parámetros que nos indican cuantos “controles” hay en nuestro formulario, el tipo, etc. Con esta información que nos facilita “Controls” podemos recorrer todos los componentes que hay.

Este código nos permite recorrer todos los controles que tenemos situados en nuestro formulario.

Ahora tenemos que saber de que tipo es el control, para ello solo tenemos que preguntárselo.

En este caso queremos saber si es un “PictureBox”, pero si queremos saber si es de otro tipo, por ejemplo, si queremos modificar un “TextBox”, cambiamos el “PictureBox” por “TextBox”. Y así según el tipo deseado.

Ejemplo:

Pero puede suceder que no a todos los componentes que tenenos en nuestro formulario queramos modificarlos. Para esto, yo me aprovecho de la opción “Tag” que tienen todos los controles. En esta opción podemos introducir  el texto que deseemos. Solo tengo que marcar todos los controles que no quiero modificar y cuando lo recorro comprobar que quiero cambiarlo.

y con esto ya podemos realizar cualquier cambio a nuestros controles, sin tener que repetir el código para cada unos de ellos.

Y tu, si utilizas otro método puedes compartirlo con nosotros, solo tienes que dejar un comentario.

Hacer que un Label sea realmente transparente en C#

En ocasiones necesitamos que en los “label” se vea el fondo, por que es una foto, cambia de color y no queremos ir cambiando el fondo de cada label, etc.

En la opción de color de fondo del “label”, en la pestaña de web, podemos elegir que el fondo sea transparente, que fácil, pongo el color en transparente y listo, ya podemos cambiar el fondo cuando queramos.

Opcion BackColor del Label
Parámetro para seleccionar el color de fondo
Color transparente Label
Poner el color del fondo en transparente

Pues no, esto funciona si lo que cambiamos es el fondo de formulario, pero si tenemos un “picturebox” o un “panel” o cualquier otra cosa que no sea el fondo del formulario, esto no funciona.

Esto se debe a que cuando añadimos un nuevo componente a nuestro formulario, este es automáticamente propiedad del formulario, y por ello el “label”, toma por defecto el color de fondo de su dueño.

Esto nos da la solución, si el color de fondo es el del propietario, lo que tenemos que hacer, para que nos funcione, es decirle quien es el dueño de nuestro “label” para que este, pueda coger el fondo que nosotros deseamos.

Esto, para la mayoría de los casos, funciona, pero si el “label” lo vamos a mover por el formulario en tiempo de ejecución, este método nos puede causar un error. Debido a que el “label” esta fuera de su dueño.

Para solucionarlo tenemos que controlar en cada momento por donde movemos el “label”, y si esta fuera del “panel” o del “picturebox”, etc. bloquearlo y que no salga.

Para este problema se puede utilizar componentes externos al C#. pero como no era mi caso, no los he probado.

Otra cosa, si lo que queremos es hacer una especie de “OSD” para un vídeo (poner un texto y que se vea el vídeo por detrás), esto tampoco funciona. Los componentes de vídeo, ya sea el media player o VLC, son una especie de derivados de un panel, por lo que si le pasamos como propietaria a nuestro “label” el componente de vídeo, este tomara el color del fondo del componente que soporta el vídeo, es decir, el color del panel.

Aun así, con todos los “peros”, este método es la solución para el 90% de los casos.

Si tienes otra solución puedes compartirla en los comentarios.

 

 

Conocer la duración del video en VideoLan (VLC) con C#

VLMC-IconTrasteando un poco con el activeX del VLC no encontraba como podía obtener la duración del vídeo que estaba reproduciendo. No tenia que ser muy difícil, es su reproductor se muestra, así que por algún lado tenia que haber una función  que devolviera el dichoso valor.  Encontré una que te devolvía todos los metadatos del vídeo, e incluso la posición actual en la que esta la reproducción del vídeo. Pero nada sobre la duración.

Después de darle varias vueltas, encontré una que, una vez que ha comenzado ha reproducirse el vídeo, nos devuelve esa información. Mientras tanto devuelve 0, lo que me engaño vilmente.

Para poder ver el valor tenemos que capturar el evento.

Este evento salta cuando se pone a reproducir el vídeo.

Dentro de este evento podemos llamar a la función que ya nos devuelve la duración del vídeo.

La función “input.Legnth” nos devuelve la duración del vídeo en milisegundos.

Una vez que conocemos la duración del vídeo, podemos pasar ha obtener la posición actual de la reproducción. Esto es más fácil, solo tenemos que capturar el evento.

Este evento se producirá cada vez que la posición del vídeo cambie, para saber la posición solo tenemos que poner.

Teniendo estos datos, ya se puede hacer la típica barra de progreso para saber cuanto falta para terminar el vídeo.

Pero resulta que tenemos un problema, no se, si es una fallo del VLC o que, pero el valor de “input.Length” y el valor final de “e.time” no son el mismo. El valor final de “e.time”, y todas la variantes que se puede obtener para sacar la misma información que he encontrada en el VLC, es unos milisegundos superior. Por lo que si lo ponemos de esta forma en una barra de progresos.

Al llegar al final del vídeo, nos genera un error que le valor el superior al valor maximo. La diferencia es pequeña, no llega un segundo, por las pruebas que he hecho, ronda los 500 – 800 milisegundos, varia con cada video, no es fija. Por lo que, antes de pasar el valor actual de la posición del vídeo a la barra de progreso, compruebo que el valor sea igual o inferior.

Y así es como lo he solucionado, si alguien sabe como obtener la duración del vídeo de otra forma o como solucionar el problema del desfase de la duración puede dejar un comentario.