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

El día de hoya vamos a continuar con la revisión del código de vencoder, en los post anterior ya vimos como es que el programa interactua con FFMpeg, el día de hoy veremos un par de funciones que también lo hacen.


Funcion PrepareWork



El código de la función PrepareWork es el siguiente:

/// <summary>
/// Prepara la linea de comandos y lo necesario para hacer la conversion
/// </summary>
/// <param name="HardWork">Parametro booleano que indica como se debe de hacer el trabajo</param>
/// <remarks>Si HardWork es true, todos lo parametros se pasaran a la conversion; en caso contrario,
/// solo se genera la linea de comandos para usarse de forma externa con FFMPEG</remarks>


private void PrepareWork(bool HardWork = false)

{

List<string> Lote = new List<string>();

List<int> DLote = new List<int>();

if (CHKAll.Checked == true)

{

foreach (ListViewItem LV in lvfilesin.Items)

{

if (LV.Checked)

{

if (CHK2pass.Checked == true)

{

Lote.Add(BuildCommandLine(LV.Text, CBOCodec.Text, CboResolucion.Text,

TXTVBit.Text, CBORatio.Text, CBOProfile.Text, "23.974", CBOBitsA.Text, CboFreq.Text, CBOAChannels.Text, TXTSavePath.Text, true, false, false));

DLote.Add(FixTimeDuration((int)TimeSpan.Parse(LV.SubItems[3].Text).TotalSeconds));

Lote.Add(BuildCommandLine(LV.Text, CBOCodec.Text, CboResolucion.Text,

TXTVBit.Text, CBORatio.Text, CBOProfile.Text, "23.974", CBOBitsA.Text, CboFreq.Text, CBOAChannels.Text, TXTSavePath.Text, false, true, false));

DLote.Add((int)TimeSpan.Parse(LV.SubItems[3].Text).TotalSeconds + 1);

}else{

Lote.Add(BuildCommandLine(LV.Text, CBOCodec.Text, CboResolucion.Text, TXTVBit.Text, CBORatio.Text, CBOProfile.Text, CboFreq.Text, CBOBitsA.Text, "44100", CBOAChannels.Text, TXTSavePath.Text, false, false, true));

DLote.Add(FixTimeDuration((int)TimeSpan.Parse(LV.SubItems[3].Text).TotalSeconds));

}

}

}

}else{

foreach (ListViewItem LV in lvfilesin.Items)

{

if (CHK2pass.Checked == true)

{

Lote.Add(BuildCommandLine(LV.Text, CBOCodec.Text, CboResolucion.Text,

TXTVBit.Text, CBORatio.Text, CBOProfile.Text, "23.974", CBOBitsA.Text,CboFreq.Text, CBOAChannels.Text, TXTSavePath.Text, true, false, false));

DLote.Add(FixTimeDuration((int)TimeSpan.Parse(LV.SubItems[3].Text).TotalSeconds));

Lote.Add(BuildCommandLine(LV.Text, CBOCodec.Text, CboResolucion.Text,

TXTVBit.Text, CBORatio.Text, CBOProfile.Text, "23.974", CBOBitsA.Text, CboFreq.Text, CBOAChannels.Text, TXTSavePath.Text, false, true, false));

DLote.Add(FixTimeDuration((int)TimeSpan.Parse(LV.SubItems[3].Text).TotalSeconds));

}else{

Lote.Add(BuildCommandLine(LV.Text, CBOCodec.Text, CboResolucion.Text,TXTVBit.Text, CBORatio.Text, CBOProfile.Text, CboFreq.Text, CBOBitsA.Text, "44100", CBOAChannels.Text, TXTSavePath.Text,false,false,true));

DLote.Add(FixTimeDuration((int)TimeSpan.Parse(LV.SubItems[3].Text).TotalSeconds));

}

}

}

if (HardWork)

{

TimerElapsed.Enabled = true;

DoWork(Lote, DLote);

}else{

foreach (String LineCom in Lote)

{

RTBCommandLine.Text = RTBCommandLine.Text + LineCom + "\n";

}

}

}

La función PrepareWork lo que hace es construir la linea de comandos para cada archivo que se encuentre en la lista, dependiendo si se le indicó al programa o no si se quiere hacer la conversion en dos pasadas, crea la linea de comandos lista para usarse.
La función PrepareWork recibe un parámetro del tipo booleano que indica que es lo que se debe de hacer después de crear todas las lineas de comandos. Si el valor del parametro HardWork se establece en true; al terminar de procesar todos los ajustes, llama a la funcón DoWork que es la encargada de iniciar la ejecución FFmpeg.
La construcción de la linea de comandos se realiza a la "mala"; es decir va recorriendo uno a uno los controles para obtener sus propiedades (Text por ejemplo). Ademas de que por ejemplo la cantidad de cuadros por segundo está fija, para evitar eso, en lugar de usar 23.974, podemos usar un TextBox en lugar de 23.974.
Esta función solo "recolecta" todos los datos y lo pone juntos, pero la función que realmente hace el trabajo sucio es la funcion BuildCommandLine.

Funcion BuildCommandLine.

El código de la funcion BuildCommandLine es el siguiente:


 /// <summary>
 /// Genera la linea de comados para usarse con FFMPEG
 /// </summary>
 /// <param name="InFile">Archivo de entrada</param>
 /// <param name="VCodec">Codec de video a usarse</param>
 /// <param name="VideoSize">Resolucion del video</param>
 /// <param name="VideoBit">Velocidad de bits del video</param>
 /// <param name="VAspect">Ratio para el video</param>
 /// <param name="VProfile">Perfil para usarse en el video</param>
 /// <param name="FrameRate">Cantidad de cuadros por segundo para el video</param>
 /// <param name="AudioBit">Veocidad de Bits para el audio</param>
 /// <param name="AudioFreq">Frecuencia de muestreo para el audio</param>
 /// <param name="AChannels">Numero de canales para el audio</param>
 /// <param name="OutPath">Donde se gurdara la salida; debe de ser una ruta a un carpeta</param>
 /// <param name="ForFirstPass">La linea de comandos se hará para la primera pasada de dos</param>
 /// <param name="AfterPass1">La Linea de comandos se hará para la segunda pasada</param>
 /// <param name="SinglePass">La linea de comandos se hara para una unica pasada</param>
 
 private string BuildCommandLine(string InFile,string VCodec,string VideoSize,string VideoBit,string VAspect,string VProfile,string FrameRate,string AudioBit,
                                string AudioFreq, string AChannels,string OutPath,bool ForFirstPass= false,bool AfterPass1=false,bool SinglePass= true)
 {
 if (ForFirstPass){
 return string.Concat("-y -i ","\"",InFile,"\""," -c:v ",VCodec," -s ",VideoSize, " -b:v ",VideoBit,"k -aspect ",VAspect," -profile:v ",VProfile," -threads 0 -r ",FrameRate,
                     " -level 4.1 -crf 22 -f mp4 -pass 1 -an NUL");
 }
 if(AfterPass1){
 return string.Concat("-y -i ","\"",InFile,"\""," -c:v ",VCodec," -s ",VideoSize, " -b:v ",VideoBit,"k -aspect ",VAspect," -profile:v ",VProfile," -threads 0 -r ",FrameRate,
                     " -level 4.1 -crf 22 -f mp4 -pass 2 -c:a libvo_aacenc -b:a ",AudioBit,"k -ar ", AudioFreq," -ac ",AChannels," \"",OutPath,"\\",GetFileName(InFile),".mp4","\"");
 }
 if (SinglePass) {
 return string.Concat("-y -i ","\"",InFile,"\""," -c:v ",VCodec," -s ",VideoSize, " -b:v ",VideoBit,"k -aspect ",VAspect," -profile:v ",VProfile," -threads 0 -r ",FrameRate,
                     " -level 4.1 -crf 22 -f mp4 -c:a libvo_aacenc -b:a ",AudioBit,"k -ar ", AudioFreq," -ac ",AChannels," \"",OutPath,"\\",GetFileName(InFile),".mp4","\"");
 }else{
 return "Test";
 }
 }

La funcion BuildCommandLine se encarga de crear la linea de comandos para usarse con FFMpeg, recibe 14 parametros y regresa un valor del tipo string con los datos listos para usarse.

  1. InFile. Es el archivo para el cual queremos crear la linea de comandos.
  2. VCodec. Es el codec que vamos a usar para el archivo, aunque ahora solo esta configurado para que la linea de comandos sea compatible  con el codec X264, mas adelante la modificaremos para agregar soporte a otros codecs (Xvid,MPEG4, etc)
  3. VideosSize. Es la resolución que tendrá el vídeo, puede ser cualquier valor que tenga la forma WWWWxHHHH, donde W es el largo y H es el ancho (1280x720 es un valor valido).
  4. VideoBit. Es la cantidad de bits que se usaran por segundo.
  5. VAspect. Indica el aspecto que deberá tener el vídeo (16:9).
  6. VProfile. Es el tipo de perfil que debe de tener el vídeo.
  7. FrameRate. Sirve para indicar la cantidad de cuadros por segundo que se deben de usar.
  8. AudioBit.Cantidad en bits para el audio
  9. AudioFreq. La frecuencia del audio en Hz.
  10. AChannels. Cantidad de canales de audio que debe de tener el vídeo.
  11. OutPath. La ruta en donde se guardaran los vídeos.
  12. ForFirstPass. Este parámetro indica como se crea la linea de comandos, si el parámetro es true, se crea la linea de comandos para la primer pasada
  13. AfterPass1. Este parámetro indica como se crea la linea de comandos, si el parámetro es true, se crea la linea de comandos para la segunda pasada
  14. SinglePass. Crea la linea de comandos para proceso de una sola pasada.
Al igual que la función anterior está diseñada para hacer la linea de comando por un archivo a la vez, la función anterior, usaba está como base y creaba la linea de comandos para todos los archivos. Al usar la función, se debe de tener cuidado con los valores que se usan al final (parametros), por ejemplo si se usa lña linea de comandos para hacer la conversion de un video en una sola pasada, los 3 parametros finales, no pueden establecerse en true, ya que modificaría valores que ya se tenían previamente.
La forma mas adecuada para manejar para que tipo de "pasada" la linea de comandos es crear una enumeracion y definir solo los casos posibles por ejemplo:

private enum CommandType

{
ForPass1,
ForPass2,
ForSinglePass
}


Y solo restaría adaptar la condiciones para cada caso.
Bien, por ahora es todo, recomiendo revisar el código para que entiendas de lo que hablo.
Los leo luego.

No hay comentarios.