Vamos a programar #13 - El código de VEncoder 2

El día de hoy vamos a continuar con la revisión del código de VEncoder,

Funcion DoWork.

El Código de la función DoWork es el siguiente:

/// <summary>
         /// Inicia la conversion de los archivos
         /// </summary>
         /// <param name="Params">Una lista del tipo string que contiene las lineas de comandos a usarse</param>
         /// <param name="Durations">Una lista del tipo int que contiene las duraciones de los archivos</param>
         
         private void DoWork(List<string>  Params, List<int> Durations)
         {
             Thread DoConversion = new Thread(new ThreadStart(() => {
                                                                  int CD = 0;
                                                                  foreach (string Param in Params)
                                                                  {
                                                                      if (RequestForCancel == true)
                                                                      {
                                                                          break;
                                                                      }
                                                                      
                                                                      int TotalPercentConvert = CD * 100;
                                                                      int CurrentDuration = Durations[CD];
                                                                      Process Proc = new Process();
                                                                      StreamReader FFResult;
                                                                      string CurrentResult;
                                                                      ProcessStartInfo FFProcess = new ProcessStartInfo("ffmpeg.exe");
                                                                      FFProcess.Arguments = Param;
                                                                      FFProcess.UseShellExecute = false;
                                                                      FFProcess.WindowStyle = ProcessWindowStyle.Hidden;
                                                                      FFProcess.RedirectStandardError = true;
                                                                      FFProcess.RedirectStandardOutput = true;
                                                                      FFProcess.CreateNoWindow = true;
                                                                      Proc.StartInfo = FFProcess;
                                                                      Proc.Start();
                                                                      PBProgress.BeginInvoke(new Action(() => PBProgress.Maximum = CurrentDuration));
                                                                      PBGlobalProgress.BeginInvoke(new Action(() => PBGlobalProgress.Maximum = Durations.Count * 100));
                                                                      FFResult = Proc.StandardError;
                                                                      do
                                                                      {
                                                                          if (RequestForCancel == true)
                                                                          {
                                                                              Proc.Kill();
                                                                              break;
                                                                          }
                                                                          
                                                                          CurrentResult = FFResult.ReadLine();
                                                                          Debug.Print(CurrentResult);
                                                                          this.BeginInvoke(new Action(() => {
                                                                                                          this.lblProgressInfo.Text = TimeSpan.FromSeconds(GetPositionFromFFline(CurrentResult)).ToString();
                                                                                                          this.PBProgress.Value = (int)GetPositionFromFFline(CurrentResult);
                                                                                                          this.PBGlobalProgress.Value = TotalPercentConvert + (int)Porcentaje(GetPositionFromFFline(CurrentResult),CurrentDuration);
                                                                                                          TaskbarProgress.SetValue(this.Handle, this.PBGlobalProgress.Value, this.PBGlobalProgress.Maximum);
                                                                                                      }));
                                                                      }while (Proc.HasExited == false & string.Compare(CurrentResult, "") == 1);
                                                                      CD = CD + 1;
                                                                      ElapsedTimeCurrent = 0;
                                                                  }
                                                                  IsConvertingSomething = false;
                                                                  RequestForCancel = false;
                                                                  ElapsedTimeCurrent = 0;
                                                                  ElapsedTimeGlobal = 0;
                                                                  this.BeginInvoke(new Action(() => {
                                                                                                  this.lblProgressInfo.Text = "Esperando";
                                                                                                  this.PBProgress.Value = 0;
                                                                                                  this.PBGlobalProgress.Value = 0;
                                                                                                  TaskbarProgress.SetState(this.Handle, TaskbarProgress.TaskbarStates.NoProgress);
                                                                                              }));
}));

DoConversion.Start();

}



La función DoWork inicia la ejecución de FFMpeg indicándole todos los parámetros para realizar la conversión de todos los archivos que se contenían en la lista, recibe dos parámetros: el primero, una lista del tipo string; que contiene todas las lineas de comandos generadas previamente con la función BuildCommandLine junto con la funcion PrepareWork.
El segundo parámetro es una lista del tipo int, que contiene la duración de los archivos en segundos.
Esta función se ejecuta dentro de la funcion PrepareWork  si se pasa el parámetro booleano HardWork cómo true.
Para la ejecución de FFMpeg se usa un Thread y se implementa de forma básica, dentro de la ejecución de este hilo, creamos un proceso que sera el encargado de abrir FFMpeg, ademas de que le diremos que todo la salida la redireccione a nuestro programa para poder extraer los datos que necesitamos.
Debido a que la conversión se hace en lotes, se usa un ciclo for para recorrer todos los elementos contenidos en la lista "Params" y ya dentro de ese mismo ciclo, se usa un bucle while que estará activo mientras nuestro proceso (ffmpeg) no haya finalizado o mientras el proceso no devuelva una cadena vacía.
Para cancelar enteramente el proceso usamos dos comprobaciones, una de ellas en el ciclo for y otra en el bucle while, esto para poder detener en cualquier parte. Si la interrupción se da cuando se esta ejecutando el bucle while, al salir de este continuara en el ciclo for y nuevamente iniciaría el bucle while si aun quedan elementos en la lista Params, entonces para evitar esto, lo único que hacemos es crear las interrupciones en ambos lugares.
Todas las instrucciones "invoke" se usan para interactuar con la interfaz principal, siempre le resulta al usuario útil saber cuanto es el progreso que se lleva.
En esta función se usa de forma muy básica todas las características de la clase Thread, en realidad es muy potente, pero para fines prácticos solo usamos lo mas importante: iniciar y detener Threads, analizando todos los elementos contenidos en esta clase, podemos encontrar que se puede tener un control más preciso de cada Thread: su estado, si responde o no, etc.
Lo mismo sucede con la clase Procces, pero por ahora solo usamos los métodos que están implementados en la función.

Funcion SetInfo.

El codigo de la funcion SetInfo es el siguiente:


         /// <summary>
         /// Obtiene la informacion de los archivos de entrada
         /// </summary>
         /// <param name="Files">Archivos de los que se obtendra la informacion.</param>
         
         private void SetInfo(List<string> Files)
         {
             Thread GetInfo = new Thread(new ThreadStart(() => {
                                                             foreach (string Archivo in Files)
                                                             {
                                                                 ListViewItem InfoItem = new ListViewItem(Archivo);
                                                                 MediaFile mFile = new MediaFile(Archivo);
                                                                 InfoItem.SubItems.AddRange(new string[] { mFile.Video[0].FrameSize.ToString(),mFile.Video[0].FrameRate.ToString(),
                                                                                                mFile.Video[0].DurationString,mFile.Video[0].Bitrate.ToString(),mFile.Audio.Count.ToString(),
                                                                                                mFile.Audio[0].SamplingRate.ToString(),mFile.Audio[0].Bitrate.ToString(),mFile.Audio[0].Channels.ToString()});
                                                                 lvfilesin.BeginInvoke(new Action(() => lvfilesin.Items.Add(InfoItem)));
                                                             }
                                                             this.BeginInvoke(new Action(() => TaskbarProgress.SetState(this.Handle,TaskbarProgress.TaskbarStates.NoProgress)));
                                                         }));
             GetInfo.Start();
         }

La función SetInfo se encarga de obtener la información de los archivos. La información incluye: Tamaño, resolución, cuadros por segundo, aspecto, velocidad de bits, etc.
Recibe como parámetro una lista del tipo string que contiene las rutas de los archivos de los cuales se quiere obtener la información.
Al igual que en la función anterior, se usa un Thread para hacer este proceso, esto debido a que cuando se procesan algunos archivos, dependiendo de sus características, puede tomar un poco de tiempo para obtener la información, y esto causaría que la interfaz principal se bloquee, para evitar esto, se inicia un thread diferente y se usa el TaskBar de windows para mostrar el progreso. Hay resaltar que debido a que se usan características disponibles a partir de Windows vista, no es posible hacer compatible la aplicación con versiones anteriores a vista.
Finalmente esta función agrega toda la información a lvfilesin, que es un ListView de la interfaz principal.

Y bien, esas son todas las funciones que componen a VEncoder, como verás, no es tan complejo y el resultado es muy útil, en el siguiente Post vamos a implementar una nueva función que apagará el equipo cuando todas la conversiones se hayan realizado.

Por ahora es todo, nuevamente les agradezco por el interés en el código de VEncoder y por el apoyo recibido en el post anterior.

Los leo luego.

No hay comentarios.