Attribute VB_Name = "Convertidor"
Option Explicit

Private Type ECodeCmdL
CmdLExtract As String
CmdLExtractVS As String 'Comandos de extracción para redimensionar video
CmdLExtractVR As String 'Comandos de extracción para cambiar la relación de aspecto del video
CodecCmdL As String
InExtension As String
OutExtension As String
ExePath As String
About As String
UsePipe As Byte
EnableWait4Msg As Byte
EnableCtrlC As Byte
End Type

Private Type EditCmdL
CmdLA As String
CmdLV As String
EliminarA As String
EliminarV As String
EliminarS As String
CmdLVideoSizeChan As Byte
CmdLVideoAspectChan As Byte
CmdLIn As String
CmdLOut As String
CmdLSetStart As String
CmdLDuration As String
MultiEntrada As Byte
End Type

Public Type FormatoCmdL
InCmdL As String
OutCmdL As String
EliminarA As String
EliminarV As String
EliminarS As String
TamanoVideo As String
RelAspect As String
CmdLA As String
CmdLV As String
CmdLS As String
Multisalida As Byte
OutExtension As String
ECANombre As String
ECVNombre As String
ECALineaCmd As ECodeCmdL
ECVLineaCmd As ECodeCmdL
OutMuxerIsCopy As Boolean
End Type

Public BatchCmd(1 To 8, 1 To 4) As String
'Columa
'1: exe
'2: comandos de entrada ó comandos (codec externo)
'3: comandos de salida
'4: extensión de salida
'Renglón
'1: extracción de audio
'2: codificación de audio
'3: codificación de audio (2o pase)
'4: extracción de video
'5: codificación de video
'6: codificación de video (2o pase)
'7: codificación av/mezclado av
'8: codificación av/mezclado av (2o pase)

Public Multisalida As Byte
Public DetenerConversion As Byte
Public BloquearCierreF12 As Byte
Public Errores() As String
Public DirectorioTemporal As String
Private CmdVideoEditIndex As Byte
Private OutMuxerIsCopy As Boolean
Private UsePipeAudio As Byte
Private UsePipeVideo As Byte
Private EnableWait4MsgAudio As Byte
Private EnableWait4MsgVideo As Byte
Private EnableCtrlCAudio As Byte
Private EnableCtrlCVideo As Byte

Public Function PerfilFormatoACmdL(PerfilF As Appfilesadm.FormatPerf, ByRef ErrorRet As Byte) As FormatoCmdL
Dim Ret As FormatoCmdL, RetError As Byte
'ErrorRet:
'0: Ningún error
'1: Error al interpretar comandos del códec externo de audio
'2: Error al interpretar comandos del códec externo de video
'3: Error al utilizar <copy> como muxer

With PerfilF

If .EliminarAudio <> 0 Then Ret.EliminarA = ffmpeg.FFmpegParametros.EliminarAudio
If .EliminarVideo <> 0 Then Ret.EliminarV = ffmpeg.FFmpegParametros.EliminarVideo
If .EliminarSubtitulos <> 0 Then Ret.EliminarS = ffmpeg.FFmpegParametros.EliminarSubtitulos

UsePipeAudio = 0
If .ECodecANombre <> "" Then
    Ret.ECANombre = .ECodecANombre
    Ret.ECALineaCmd = InfoCodecEACmdL(.InfoECodecA, 0, RetError)
    If RetError > 0 Then ErrorRet = 1
    If .InfoECodecA.RutaExe = "<ffmpeg.exe>" Then
        Ret.CmdLA = Ret.ECALineaCmd.CodecCmdL & " " & ffmpeg.FFmpegParametros.CodecAudio & " " & .InfoECodecA.ExtensionSalida
        Ret.ECANombre = ""
        EnableWait4MsgAudio = 0
        EnableCtrlCAudio = 1
    Else
        UsePipeAudio = Ret.ECALineaCmd.UsePipe
        EnableWait4MsgAudio = Ret.ECALineaCmd.EnableWait4Msg
        EnableCtrlCAudio = Ret.ECALineaCmd.EnableCtrlC
    End If
End If

UsePipeVideo = 0
If .ECodecVNombre <> "" And ErrorRet = 0 Then
    Ret.ECVNombre = .ECodecVNombre
    Ret.ECVLineaCmd = InfoCodecEACmdL(.InfoECodecV, 1, RetError)
    If RetError > 0 Then ErrorRet = 2
    If .InfoECodecV.RutaExe = "<ffmpeg.exe>" Then
        Ret.CmdLV = Ret.ECVLineaCmd.CodecCmdL & " " & ffmpeg.FFmpegParametros.CodecVideo & " " & .InfoECodecV.ExtensionSalida
        Ret.ECVNombre = ""
        EnableWait4MsgVideo = 0
        EnableCtrlCVideo = 1
    Else
        UsePipeVideo = Ret.ECVLineaCmd.UsePipe
        EnableWait4MsgVideo = Ret.ECVLineaCmd.EnableWait4Msg
        EnableCtrlCVideo = Ret.ECVLineaCmd.EnableCtrlC
    End If
End If

Ret.OutMuxerIsCopy = (LCase(PerfilF.ContenedorS) = "<copy>") 'Se seleccionó <copy> para contenedor de salida
If Ret.OutMuxerIsCopy Then
    'No se seleccionó codec externo para audio -> no se codifica
    If Ret.ECANombre = "" Then Ret.EliminarA = ffmpeg.FFmpegParametros.EliminarAudio
    'No se seleccionó codec externo para video -> no se codifica
    If Ret.ECVNombre = "" Then Ret.EliminarV = ffmpeg.FFmpegParametros.EliminarVideo
    If Ret.EliminarA <> "" And Ret.EliminarV <> "" Then ErrorRet = 3 'Error se seleccionó <copy> pero ningún codec externo
End If

If RetError > 0 Then Exit Function

If Ret.EliminarA = "" And .ECodecANombre = "" And Ret.CmdLA = "" Then
If .AudioCalidad <> "" Then Ret.CmdLA = Ret.CmdLA & " " & ffmpeg.FFmpegParametros.AudioCalidad & " " & .AudioCalidad
If .BitrateAudio <> "" Then Ret.CmdLA = Ret.CmdLA & " " & ffmpeg.FFmpegParametros.BitrateAudio & " " & .BitrateAudio
If .BitrateMaxAudio <> "" Then Ret.CmdLA = Ret.CmdLA & " " & ffmpeg.FFmpegParametros.BitrateMaxAudio & " " & .BitrateMaxAudio
If .BitrateMinAudio <> "" Then Ret.CmdLA = Ret.CmdLA & " " & ffmpeg.FFmpegParametros.BitrateMinAudio & " " & .BitrateMinAudio
If .Canales <> "" Then Ret.CmdLA = Ret.CmdLA & " " & ffmpeg.FFmpegParametros.Canales & " " & .Canales
If .CodecAudioS <> "" Then Ret.CmdLA = Ret.CmdLA & " " & ffmpeg.FFmpegParametros.CodecAudio & " " & .CodecAudioS
If .SampleRate <> "" Then Ret.CmdLA = Ret.CmdLA & " " & ffmpeg.FFmpegParametros.SampleRate & " " & .SampleRate
Ret.CmdLA = Trim(Ret.CmdLA)
End If

If Ret.EliminarV = "" And .ECodecVNombre = "" And Ret.CmdLV = "" Then
If .BitrateMaxVideo <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.BitrateMaxVideo & " " & .BitrateMaxVideo
If .BitrateMinVideo <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.BitrateMinVideo & " " & .BitrateMinVideo
If .BitrateVideo <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.BitrateVideo & " " & .BitrateVideo
If .CalidadMax <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.VideoCalidadMax & " " & .CalidadMax
If .CalidadMin <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.VideoCalidadMin & " " & .CalidadMin
If .CodecVideoS <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.CodecVideo & " " & .CodecVideoS
If .PixelFormatS <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.PixelFormat & " " & .PixelFormatS
If .VideoCalidad <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.VideoCalidad & " " & .VideoCalidad
If .Videofps <> "" Then Ret.CmdLV = Ret.CmdLV & " " & ffmpeg.FFmpegParametros.Videofps & " " & .Videofps
If .RelAspect <> "" Then Ret.RelAspect = ffmpeg.FFmpegParametros.RelAspect & " " & .RelAspect
If .TamanoCuadro <> "" Then Ret.TamanoVideo = ffmpeg.FFmpegParametros.TamanoCuadro & " " & .TamanoCuadro
Ret.CmdLV = Trim(Ret.CmdLV)
End If

If Ret.EliminarS = "" Then
If .CodecSubtituloS <> "" Then Ret.CmdLS = ffmpeg.FFmpegParametros.CodecSubtitulo & " " & .CodecSubtituloS
End If

Ret.Multisalida = .Multisalida
Ret.OutExtension = .ExtensionS

If .CodecAudioE <> "" Then Ret.InCmdL = Ret.InCmdL & " " & ffmpeg.FFmpegParametros.CodecAudio & " " & .CodecAudioE
If .CodecSubtituloE <> "" Then Ret.InCmdL = Ret.InCmdL & " " & ffmpeg.FFmpegParametros.CodecSubtitulo & " " & .CodecSubtituloE
If .CodecVideoE <> "" Then Ret.InCmdL = Ret.InCmdL & " " & ffmpeg.FFmpegParametros.CodecVideo & " " & .CodecVideoE
If .ContenedorE <> "" Then Ret.InCmdL = Ret.InCmdL & " " & ffmpeg.FFmpegParametros.Contenedor & " " & .ContenedorE
If .ReadInputAtNFR = 1 Then Ret.InCmdL = Ret.InCmdL & " " & ffmpeg.FFmpegParametros.ReadInputAtNFR
If .PixelFormatE <> "" Then Ret.InCmdL = Ret.InCmdL & " " & ffmpeg.FFmpegParametros.PixelFormat & " " & .PixelFormatE
If .ParAdicionalE <> "" Then Ret.InCmdL = Ret.InCmdL & " " & .ParAdicionalE

If .ContenedorS <> "" Then Ret.OutCmdL = Ret.OutCmdL & " " & ffmpeg.FFmpegParametros.Contenedor & " " & .ContenedorS
If .Objetivo <> "" Then Ret.OutCmdL = Ret.OutCmdL & " " & ffmpeg.FFmpegParametros.Objetivo & " " & .Objetivo
If .BufferSize <> "" Then Ret.OutCmdL = Ret.OutCmdL & " " & ffmpeg.FFmpegParametros.BufferSize & " " & .BufferSize
If .ParAdicionalS <> "" Then Ret.OutCmdL = Ret.OutCmdL & " " & .ParAdicionalS

ErrorRet = 0
PerfilFormatoACmdL = Ret
End With
End Function

Public Function InfoCodecEACmdL(InfoCodec As Appfilesadm.ExternalCodec, Tipo As Byte, ByRef ErrProc As Byte) As ECodeCmdL
Dim i As Integer, Ret As ECodeCmdL, ParValor As String, Pos1 As Long, Pos2 As Long, n As Byte
Dim FFModifs() As String, Posicion1 As Long, Posicion2 As Long, LenValS As Long
Dim Comando As String
On Error GoTo ErrH
ErrProc = 1
With InfoCodec
'Genera la línea de comandos para codificar
If ECodecEdit.ElementosEnMatrizPar(.Parametros) > 0 Then
    For i = LBound(.Parametros) To UBound(.Parametros)
        Select Case .Parametros(i).Tipo
            Case Is = 0 'Parametro opcional: se incluye si el usuario le da un valor ó si se le asigna un valor predeterminado
                ParValor = .Parametros(i).Valor
                If ParValor <> "" Then 'El usuario asignó un valor o etiqueta
                    'Saber si el usuario asignó una etiqueta
                    If Left(.Parametros(i).ValoresSugeridos, Len(ParValor) + 1) = ParValor & "*" Then
                        Pos1 = 1 'Etiqueta encontrada al inicio de la lista
                        n = 1
                    Else
                        Pos1 = InStr(1, .Parametros(i).ValoresSugeridos, vbCrLf & ParValor & "*")
                        n = 3 'Etiqueta encontrada enmedio de la lista
                    End If
                    If Pos1 > 0 Then 'El usuario asigó una etiqueta
                        LenValS = Len(.Parametros(i).ValoresSugeridos)
                        Pos1 = Pos1 + Len(ParValor) + n 'Posicion donde inicia el valor asignado a la etiqueta
                        Select Case Pos1
                            Case Is < LenValS 'Hay un valor asignado de mas de un caracter
                                'Posición donde finaliza el valor
                                Pos2 = InStr(Pos1, .Parametros(i).ValoresSugeridos, vbCrLf)
                                If Pos2 = Pos1 Then 'Valor nulo
                                    ParValor = vbNullString
                                Else
                                    If Pos2 > 0 Then 'Valor encontrado enmedio de la lista
                                        ParValor = Mid(.Parametros(i).ValoresSugeridos, Pos1, Pos2 - Pos1)
                                    Else 'Valor encontrado al final de la lista
                                        ParValor = Mid(.Parametros(i).ValoresSugeridos, Pos1, LenValS - Pos1 + 1)
                                    End If
                                End If
                            Case Is = LenValS: ParValor = Right(.Parametros(i).ValoresSugeridos, 1) 'Valor asignado de solo un caracter
                            Case Is > LenValS: ParValor = vbNullString 'No se asignó ningún valor
                        End Select
                    End If
                    If ParValor <> vbNullString Then Ret.CodecCmdL = Ret.CodecCmdL & " " & .Parametros(i).ModificadorCmd & " " & ParValor
                Else
                    If .Parametros(i).ValorDefault <> "" Then Ret.CodecCmdL = Ret.CodecCmdL & " " & .Parametros(i).ModificadorCmd & " " & .Parametros(i).ValorDefault
                End If
            Case Is = 1 'Parámetro obligatorio: siempre aparece
                Select Case .Parametros(i).Nombre
                    Case Is = "<InFile>"
                        If .Parametros(i).SoloValoresSugeridos = 1 And .Parametros(i).Valor = "pipe" Then
                            Ret.UsePipe = 1
                            Ret.CodecCmdL = Ret.CodecCmdL & " " & .Parametros(i).ValorDefault
                        Else
                            Ret.CodecCmdL = Ret.CodecCmdL & " " & .Parametros(i).ModificadorCmd & " <infile>"
                        End If
                    Case Is = "<OutFile>"
                        Ret.CodecCmdL = Ret.CodecCmdL & " " & .Parametros(i).ModificadorCmd & " <outfile>"
                        If .Parametros(i).SoloValoresSugeridos = 0 Then Ret.EnableWait4Msg = 1
                        If .Parametros(i).ValoresSugeridos = "." Then Ret.EnableCtrlC = 1
                    Case Else
                        Ret.CodecCmdL = Ret.CodecCmdL & " " & .Parametros(i).ModificadorCmd & " " & .Parametros(i).ValorDefault
                End Select
            Case Is = 2 'Parámetro opcional sin valor: aparece solo si el usuario lo habilita
                If .Parametros(i).Valor = "1" Then Ret.CodecCmdL = Ret.CodecCmdL & " " & .Parametros(i).ModificadorCmd
        End Select
    Next
End If

'Genera la línea de comandos para extraer
ReDim FFModifs(LBound(.FFParUserValues) To UBound(.FFParUserValues))
If Tipo = 0 Then 'Lista de parámetros que el usuario puede modificar
    FFModifs(LBound(FFModifs)) = ffmpeg.FFmpegParametros.BitrateAudio
    FFModifs(LBound(FFModifs) + 1) = ffmpeg.FFmpegParametros.BitrateMaxAudio
    FFModifs(LBound(FFModifs) + 2) = ffmpeg.FFmpegParametros.BitrateMinAudio
    FFModifs(LBound(FFModifs) + 3) = ffmpeg.FFmpegParametros.AudioCalidad
    FFModifs(LBound(FFModifs) + 4) = ffmpeg.FFmpegParametros.Canales
    FFModifs(LBound(FFModifs) + 5) = ffmpeg.FFmpegParametros.SampleRate
Else
    FFModifs(LBound(FFModifs)) = ffmpeg.FFmpegParametros.BitrateVideo
    FFModifs(LBound(FFModifs) + 1) = ffmpeg.FFmpegParametros.BitrateMaxVideo
    FFModifs(LBound(FFModifs) + 2) = ffmpeg.FFmpegParametros.BitrateMinVideo
    FFModifs(LBound(FFModifs) + 3) = ffmpeg.FFmpegParametros.VideoCalidad
    FFModifs(LBound(FFModifs) + 4) = ffmpeg.FFmpegParametros.VideoCalidadMax
    FFModifs(LBound(FFModifs) + 5) = ffmpeg.FFmpegParametros.VideoCalidadMin
    FFModifs(LBound(FFModifs) + 6) = ffmpeg.FFmpegParametros.Videofps
    FFModifs(LBound(FFModifs) + 7) = ffmpeg.FFmpegParametros.TamanoCuadro
    FFModifs(LBound(FFModifs) + 8) = ffmpeg.FFmpegParametros.RelAspect
    FFModifs(LBound(FFModifs) + 9) = ffmpeg.FFmpegParametros.PixelFormat
End If

Ret.CmdLExtract = " " & .CmdLffmpeg & " "
For i = LBound(FFModifs) To UBound(FFModifs)
    If .FFParUserValues(i) <> "" Then
        Posicion1 = InStr(1, Ret.CmdLExtract, " " & FFModifs(i) & " ")
        If Posicion1 > 0 Then
            Posicion1 = Posicion1 + 2 + Len(FFModifs(i))
            Posicion2 = InStr(Posicion1, Ret.CmdLExtract, " ")
            If Posicion2 > 0 Then
                Comando = Mid(Ret.CmdLExtract, Posicion1 - 2 - Len(FFModifs(i)), Posicion2 - Posicion1 + 2 + Len(FFModifs(i)))
                Ret.CmdLExtract = Replace(Ret.CmdLExtract, Comando, " " & FFModifs(i) & " " & .FFParUserValues(i))
            End If
        Else
            Ret.CmdLExtract = Ret.CmdLExtract & " " & FFModifs(i) & " " & .FFParUserValues(i)
        End If
    End If
Next

'Separar los comandos para redimensionar cuadro y cambiar relación de aspecto
Posicion1 = InStr(1, Ret.CmdLExtract, " " & ffmpeg.FFmpegParametros.TamanoCuadro & " ")
If Posicion1 > 0 Then
    Posicion1 = Posicion1 + 2 + Len(ffmpeg.FFmpegParametros.TamanoCuadro)
    Posicion2 = InStr(Posicion1, Ret.CmdLExtract, " ")
    If Posicion2 > 0 Then
        Ret.CmdLExtractVS = ffmpeg.FFmpegParametros.TamanoCuadro & " " & Mid(Ret.CmdLExtract, Posicion1, Posicion2 - Posicion1)
        Ret.CmdLExtract = Replace(Ret.CmdLExtract, Ret.CmdLExtractVS, "")
    End If
End If
Posicion1 = InStr(1, Ret.CmdLExtract, " " & ffmpeg.FFmpegParametros.RelAspect & " ")
If Posicion1 > 0 Then
    Posicion1 = Posicion1 + 2 + Len(ffmpeg.FFmpegParametros.RelAspect)
    Posicion2 = InStr(Posicion1, Ret.CmdLExtract, " ")
    If Posicion2 > 0 Then
        Ret.CmdLExtractVR = ffmpeg.FFmpegParametros.RelAspect & " " & Mid(Ret.CmdLExtract, Posicion1, Posicion2 - Posicion1)
        Ret.CmdLExtract = Replace(Ret.CmdLExtract, Ret.CmdLExtractVR, "")
    End If
End If

If .RutaExe = "<ffmpeg.exe>" Then
    Ret.CodecCmdL = Ret.CodecCmdL & " " & Ret.CmdLExtract
    Ret.CmdLExtract = ""
End If

Ret.CodecCmdL = Trim(Ret.CodecCmdL)
Ret.CmdLExtract = Trim(Ret.CmdLExtract)
Ret.InExtension = .ffFileExtension
Ret.OutExtension = .ExtensionSalida
Ret.ExePath = .RutaExe
Ret.About = .AcercaDe
End With
InfoCodecEACmdL = Ret
ErrProc = 0
Exit Function
ErrH:
End Function

Public Function PerfilEditACmdL(EPerfil As Appfilesadm.PerfEdit, ByRef ErrIndex As Byte, ByRef ErrPath As String) As EditCmdL
Dim Ret As EditCmdL, FiltroBuffer As Appfilesadm.FFFiltro, NumArchivo As Integer
Dim Filtros(1 To 3) As String, i As Integer, Comandos As String
On Error GoTo ErrH
With EPerfil

ErrIndex = 1
If .ElimA_Val = 1 Then Ret.EliminarA = ffmpeg.FFmpegParametros.EliminarAudio 'Eliminar audio
If .ElimV_Val = 1 Then Ret.EliminarV = ffmpeg.FFmpegParametros.EliminarVideo 'Eliminar video
If .ElimS_Val = 1 Then Ret.EliminarS = ffmpeg.FFmpegParametros.EliminarSubtitulos 'Eliminar subtitulos
If .ElimA_Val = 1 And .ElimV_Val = 1 And .ElimS_Val = 1 Then Exit Function

ErrIndex = 2
'Aplicar filtros
If Len(Join(.ApFiltros, ":")) > 0 Then
    For i = LBound(.ApFiltros) To UBound(.ApFiltros)
        NumArchivo = FreeFile
        ErrPath = App.Path & "\appfiles\filters\" & .ApFiltros(i) & ".lfl"
        If ScriptObj.ExisteArchivo(ErrPath) = False Then GoTo ErrH
        Open ErrPath For Binary As NumArchivo
        Get NumArchivo, , FiltroBuffer
        Close NumArchivo
        If FiltroBuffer.Comandos <> "" Then
            Select Case FiltroBuffer.Tipo
                Case Is = 0
                    If .ElimA_Val <> 1 Then
                        Filtros(1) = Filtros(1) & " " & ffmpeg.FFmpegParametros.FiltroAudio & " " & FiltroBuffer.Comandos
                        If FiltroBuffer.MultiEntrada = 1 Then Ret.MultiEntrada = 1
                    End If
                Case Is = 1
                    If .ElimV_Val <> 1 Then
                        Filtros(2) = Filtros(2) & " " & ffmpeg.FFmpegParametros.FiltroVideo & " " & FiltroBuffer.Comandos
                        If FiltroBuffer.MultiEntrada = 1 Then Ret.MultiEntrada = 1
                    End If
                Case Is = 2
                    Filtros(3) = Filtros(3) & " " & ffmpeg.FFmpegParametros.Filtro & " " & FiltroBuffer.Comandos
                    If FiltroBuffer.MultiEntrada = 1 Then Ret.MultiEntrada = 1
            End Select
        End If
    Next
End If
ErrPath = ""

ErrIndex = 3
If .ElimA_Val <> 1 Then
    'Ecualizar
    Comandos = CmdEcualizar(EPerfil)
    If Comandos <> "" Then Ret.CmdLA = Ret.CmdLA & " " & Comandos
    'Cambiar volumen
    Comandos = CmdCambiarVolumen(EPerfil)
    If Comandos <> "" Then Ret.CmdLA = Ret.CmdLA & " " & Comandos
    Ret.CmdLA = Ret.CmdLA & " " & Filtros(1)
    Ret.CmdLA = Trim(Ret.CmdLA)
End If

If .ElimV_Val <> 1 Then
    'Agregar bordes
    Comandos = CmdAgregarBordes(EPerfil)
    If Comandos <> "" Then Ret.CmdLV = Ret.CmdLV & " " & Comandos
    'Redimensionar cuadro
    Comandos = CmdRedimensionarCuadro(EPerfil)
    If Comandos <> "" Then
        Ret.CmdLVideoSizeChan = 1
        Ret.CmdLV = Ret.CmdLV & " " & Comandos
    End If
    'Recortar cuadro
    Comandos = CmdRecortarCuadro(EPerfil)
    If Comandos <> "" Then Ret.CmdLV = Ret.CmdLV & " " & Comandos
    'Grabar subtítulos
    Comandos = CmdGrabarSubtitulos(EPerfil)
    If Comandos <> "" Then Ret.CmdLV = Ret.CmdLV & " " & Comandos
    'Overlay
    Comandos = CmdOverlay(EPerfil)
    If Comandos <> "" Then Ret.CmdLV = Ret.CmdLV & " " & Comandos
    Ret.CmdLV = Ret.CmdLV & " " & Filtros(2)
    Ret.CmdLV = Trim(Ret.CmdLV)
End If

ErrIndex = 5
'Recortar secuencia
If .RecSec_Inicio <> "" And .RecSec_Inicio <> "0" Then
    Comandos = ffmpeg.FFConvertirCronometroASegungos(.RecSec_Inicio)
    If Comandos = "" Then GoTo ErrH
    Ret.CmdLSetStart = ffmpeg.FFmpegParametros.SetStart & " " & Comandos
End If
If .RecSec_Opt = 1 Then
    If .RecSec_Fin <> "" Then
        If Comandos = "" Then Comandos = "0"
        Comandos = Trim(CStr(CSng(ffmpeg.FFConvertirCronometroASegungos(.RecSec_Fin)) - CSng(Comandos)))
        Ret.CmdLDuration = ffmpeg.FFmpegParametros.Duracion & " " & Comandos
    End If
Else
    Select Case .RecSec_DuracionU
        Case Is = 0
            If .RecSec_Duracion(1) <> "" And .RecSec_Duracion(1) <> "0" Then Ret.CmdLDuration = ffmpeg.FFmpegParametros.Duracion & " " & .RecSec_Duracion(1)
        Case Is = 1
            If .RecSec_Duracion(2) <> "" And .RecSec_Duracion(2) <> "0" Then Ret.CmdLDuration = ffmpeg.FFmpegParametros.Vframes & " " & .RecSec_Duracion(2)
        Case Is = 2
            If .RecSec_Duracion(3) <> "" And .RecSec_Duracion(3) <> "0" Then Ret.CmdLDuration = ffmpeg.FFmpegParametros.Filesizelimit & " " & .RecSec_Duracion(3)
    End Select
End If

Ret.CmdLIn = Trim(.CmdL_Entrada)
Ret.CmdLOut = Trim(.CmdL_Salida & " " & Filtros(3))

End With
PerfilEditACmdL = Ret
ErrIndex = 0
Exit Function
ErrH:
'0: ningún error
'1: se eligió eliminar todas las pistas del archivo
'2: error al leer el filtro ubicado en errpath
'3: error al generar comandos de edición de audio
'4: error al generar comandos de edición de video
'5: error al generar comandos para recortar secuencia
End Function

Public Function GenerarLineaDeComandos(Optional TestTime As String) As Boolean
Dim ErrRet As Byte, RutaError As String, CmdLFormato As FormatoCmdL
Dim CmdLEdicion As EditCmdL, TestDurCmd As String, OutExt As String
Dim i As Byte, j As Byte, OutMuxer As String

GenerarLineaDeComandos = False
CmdVideoEditIndex = 0

'Validar perfiles de formato y edición
    Call Aplicacion.ValidarOutEdit
    Call Aplicacion.ValidarOutFmt

'Obtener los comandos para la duración de prueba
    If TestTime <> "" Then
        TestDurCmd = ffmpeg.FFConvertirCronometroASegungos(TestTime)
        If TestDurCmd = "" Then
            Lang.Convert_Error_GenerarCmdL_TesTime
            Exit Function
        Else
            TestDurCmd = ffmpeg.FFmpegParametros.Duracion & " " & TestDurCmd
        End If
    End If

    'Obtener comandos para el formato
    If Aplicacion.OutputFormat <> "" Then
        CmdLFormato = InterpretarPFormato(Aplicacion.OutputFormat, ErrRet)
        Select Case ErrRet
            Case Is = 1: Lang.Convert_Error_GenerarCmdL_FormatoNotFound
            Case Is = 2: Lang.Convert_Error_GenerarCmdL_LeerFmt
            Case Is = 3: Lang.Convert_Error_GenerarCmdL_ECodecA
            Case Is = 4: Lang.Convert_Error_GenerarCmdL_ECodecV
            Case Is = 5: Lang.Msg_OutputMuxerCannotbecopy
        End Select
        OutMuxerIsCopy = CmdLFormato.OutMuxerIsCopy
        If ErrRet > 0 Then Exit Function
    
        'Obtener la ruta del codec externo de audio
        If CmdLFormato.ECANombre <> "" Then
            CmdLFormato.ECALineaCmd.ExePath = LocalizarRutaEC(CmdLFormato.ECALineaCmd.ExePath, CmdLFormato.ECANombre, 0)
            If CmdLFormato.ECALineaCmd.ExePath = "" Then
                If Lang.Convert_Error_GenerarCmdL_ECodecANotFound = vbYes Then
                    CmdLFormato.ECALineaCmd.ExePath = AboutCodecView.ACInicializarVisor(Form1, Aplicacion.OutputFormat, 0)
                    CmdLFormato.ECALineaCmd.ExePath = Aplicacion.CompletarRuta(CmdLFormato.ECALineaCmd.ExePath)
                    If ScriptObj.ExisteArchivo(CmdLFormato.ECALineaCmd.ExePath) = False Then Exit Function
                Else
                    Exit Function
                End If
            End If
        End If
        'Obtener la ruta del codec externo de video
        If CmdLFormato.ECVNombre <> "" Then
            CmdLFormato.ECVLineaCmd.ExePath = LocalizarRutaEC(CmdLFormato.ECVLineaCmd.ExePath, CmdLFormato.ECVNombre, 1)
            If CmdLFormato.ECVLineaCmd.ExePath = "" Then
                If Lang.Convert_Error_GenerarCmdL_ECodecVNotFound = vbYes Then
                    CmdLFormato.ECVLineaCmd.ExePath = AboutCodecView.ACInicializarVisor(Form1, Aplicacion.OutputFormat, 1)
                    CmdLFormato.ECVLineaCmd.ExePath = Aplicacion.CompletarRuta(CmdLFormato.ECVLineaCmd.ExePath)
                    If ScriptObj.ExisteArchivo(CmdLFormato.ECVLineaCmd.ExePath) = False Then Exit Function
                Else
                    Exit Function
                End If
            End If
        End If
    Else
        OutMuxerIsCopy = False
    End If
Multisalida = CmdLFormato.Multisalida

'Obtener extensión de salida
If Form1.Combo1.ListIndex < 2 Then OutExt = ScriptObj.DevolverExtension(Aplicacion.OutFile) 'Se eligió archivo de salida -> buscar extensión en ruta de archivo de salida
If OutExt = "" And Form1.Combo2.Text <> Form1.Combo2.List(0) Then OutExt = Form1.Combo2.Text 'Usar extensión especificada en el cuadro 'Extension de archivo' del main
If OutExt = "" Then OutExt = CmdLFormato.OutExtension 'Usar extensión especificada en el perfil de formato
If OutExt = "" And OutMuxerIsCopy = False Then OutExt = DeterminarExtension(ObtenerContenedorDeCmdL(CmdLFormato.OutCmdL)) 'Determinar extensión en base al formato de contenedor
If OutExt = "" And OutMuxerIsCopy = False Then 'No se pudo determinar ninguna extensión para el archivo de salida
    'Se seleccionó perfil de formato 'Automatico' y Extensión de archivo 'Automatico'
    If LCase(Form1.Combo3.Text) = LCase("<" & Lang.PerfilName_Automatic & ">") And LCase(Form1.Combo2.Text) = LCase("<" & Lang.PerfilName_Automatic & ">") Then
        'Es necesario especificar extensión de archivo para poder convertirlo
        Lang.Convert_Error_GenerarCmdL_OutExt
        Exit Function
    End If
    'Advertir al usuario que es necesario ingresar una extensión de archivo para que Windows lo pueda reconocer
    If Lang.MsgSuspenderParaIngresarExtension <> vbNo Then Exit Function
Else
    CmdLFormato.OutExtension = OutExt
    OutExt = ""
End If

'Agregar "-f concat", si se selecciona concatenar los archivos
If Form1.Combo1.ListIndex = 0 Then
    If InStr(1, " " & CmdLFormato.InCmdL & " ", " " & ffmpeg.FFmpegParametros.Contenedor & " concat ", vbTextCompare) = 0 Then CmdLFormato.InCmdL = CmdLFormato.InCmdL & " " & ffmpeg.FFmpegParametros.Contenedor & " concat -safe 0 "
End If

'Obtener los comandos de edición
If Aplicacion.OutputEdit <> "" Then
    CmdLEdicion = InterpretarPEdicion(Aplicacion.OutputEdit, ErrRet, RutaError)
    Select Case ErrRet
        Case Is = 1: Lang.Convert_Error_GenerarCmdL_PEditNotFound
        Case Is = 2: Lang.Convert_Error_GenerarCmdL_LeerPEdit
        Case Is = 3: Lang.Convert_Error_GenerarCmdL_DelAll
        Case Is = 4: Lang.Convert_Error_GenerarCmdL_LeerFilto (RutaError)
        Case Is = 5: Lang.Convert_Error_GenerarCmdL_CmdLEditA
        Case Is = 6: Lang.Convert_Error_GenerarCmdL_CmdLEditV
        Case Is = 7: Lang.Convert_Error_GenerarCmdL_CmdLRecSec
    End Select
    If ErrRet > 0 Then Exit Function
    If CmdLEdicion.MultiEntrada = 1 And Form1.Combo1.ListIndex <> 1 Then
        Lang.Convert_Error_GenerarCmdL_MultiE
        Exit Function
    End If
End If


If CmdLEdicion.EliminarA = "" Then CmdLEdicion.EliminarA = CmdLFormato.EliminarA
If CmdLEdicion.EliminarV = "" Then CmdLEdicion.EliminarV = CmdLFormato.EliminarV
If CmdLEdicion.EliminarS = "" Then CmdLEdicion.EliminarS = CmdLFormato.EliminarS
If CmdLEdicion.EliminarA <> "" And CmdLEdicion.EliminarV <> "" And CmdLEdicion.EliminarS <> "" Then
    Lang.Convert_Error_GenerarCmdL_DelAll
    Exit Function
End If
If CmdLEdicion.EliminarA <> "" Then
    CmdLEdicion.CmdLA = ""
    CmdLFormato.CmdLA = ""
    CmdLFormato.ECANombre = ""
End If
If CmdLEdicion.EliminarV <> "" Then
    CmdLEdicion.CmdLV = ""
    CmdLEdicion.CmdLVideoAspectChan = 0
    CmdLEdicion.CmdLVideoSizeChan = 0
    CmdLFormato.CmdLV = ""
    CmdLFormato.ECVNombre = ""
    CmdLFormato.RelAspect = ""
    CmdLFormato.TamanoVideo = ""
End If
If CmdLEdicion.EliminarS <> "" Then CmdLFormato.CmdLS = ""

'Modificar los comandos de edición
If TestDurCmd <> "" Then CmdLEdicion.CmdLDuration = TestDurCmd

If CmdLEdicion.EliminarV = "" Then
    If CmdLEdicion.CmdLVideoSizeChan = 0 Then
        If CmdLFormato.ECVNombre <> "" Then CmdLEdicion.CmdLV = Trim(CmdLEdicion.CmdLV & " " & CmdLFormato.ECVLineaCmd.CmdLExtractVS) Else CmdLEdicion.CmdLV = Trim(CmdLEdicion.CmdLV & " " & CmdLFormato.TamanoVideo)
    End If
    If CmdLEdicion.CmdLVideoAspectChan = 0 Then
        If CmdLFormato.ECVNombre <> "" Then CmdLEdicion.CmdLV = Trim(CmdLEdicion.CmdLV & " " & CmdLFormato.ECVLineaCmd.CmdLExtractVR) Else CmdLEdicion.CmdLV = Trim(CmdLEdicion.CmdLV & " " & CmdLFormato.RelAspect)
    End If
End If

With CmdLFormato
    .EliminarA = ""
    .EliminarS = ""
    .EliminarV = ""
    .ECVLineaCmd.CmdLExtractVR = ""
    .ECVLineaCmd.CmdLExtractVS = ""
    .RelAspect = ""
    .TamanoVideo = ""
End With
TestDurCmd = ""

'GENERAR LA LÍNEA DE COMANDOS
For i = 1 To 8
    For j = 1 To 4: BatchCmd(i, j) = "": Next
Next

With CmdLFormato
    'OutMuxer = LCase(ObtenerContenedorDeCmdL(.OutCmdL))
    'OutMuxerIsCopy = (OutMuxer = ffmpeg.FFmpegParametros.Contenedor & " <copy>")
    If .ECANombre <> "" Then
        BatchCmd(1, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34) 'Extraer audio
        BatchCmd(1, 2) = " " & .InCmdL & " " & CmdLEdicion.CmdLIn & " " & CmdLEdicion.CmdLSetStart & " -i "
        BatchCmd(1, 3) = " " & .ECALineaCmd.CmdLExtract & " " & CmdLEdicion.CmdLDuration & " " & CmdLEdicion.CmdLA & " " & CmdLEdicion.CmdLOut & " " & ffmpeg.FFmpegParametros.SobreescribirYes & " " & ffmpeg.FFmpegParametros.EliminarVideo & " " & ffmpeg.FFmpegParametros.EliminarSubtitulos & " "
        BatchCmd(1, 4) = .ECALineaCmd.InExtension
        BatchCmd(2, 1) = Chr(34) & .ECALineaCmd.ExePath & Chr(34) 'codificar la pista de audio con un codec externo
        BatchCmd(2, 2) = " " & .ECALineaCmd.CodecCmdL
        BatchCmd(2, 3) = ""
        BatchCmd(2, 4) = .ECALineaCmd.OutExtension
    Else
        If .ECVNombre <> "" And CmdLEdicion.EliminarA = "" And Not OutMuxerIsCopy Then 'Codificar la pista de audio con ffmpeg
            BatchCmd(2, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34)
            BatchCmd(2, 2) = " " & .InCmdL & " " & CmdLEdicion.CmdLSetStart & " " & CmdLEdicion.CmdLIn & " -i "
            BatchCmd(2, 3) = " " & .OutCmdL & " " & .CmdLA & " " & .CmdLS & " " & CmdLEdicion.CmdLA & " " & CmdLEdicion.CmdLDuration & " " & CmdLEdicion.CmdLOut & " " & ffmpeg.FFmpegParametros.SobreescribirYes & " " & ffmpeg.FFmpegParametros.EliminarVideo & " " & CmdLEdicion.EliminarS & " "
            BatchCmd(2, 4) = .OutExtension
            If Form1.Conv_Opt_2pass.Checked = True Then
                BatchCmd(3, 1) = BatchCmd(2, 1)
                BatchCmd(3, 2) = BatchCmd(2, 2)
                BatchCmd(3, 3) = BatchCmd(2, 3)
                BatchCmd(3, 4) = BatchCmd(2, 4)
                BatchCmd(2, 3) = BatchCmd(2, 3) & " " & ffmpeg.FFmpegParametros.CPase & " 1 "
                BatchCmd(3, 3) = BatchCmd(3, 3) & " " & ffmpeg.FFmpegParametros.CPase & " 2 "
            End If
        End If
    End If

    If .ECVNombre <> "" Then
        BatchCmd(4, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34) 'Extraer video
        BatchCmd(4, 2) = " " & .InCmdL & " " & CmdLEdicion.CmdLIn & " " & CmdLEdicion.CmdLSetStart & " -i "
        If InStr(1, CmdLEdicion.CmdLV, "<AnchoInput>", vbTextCompare) > 0 Then CmdVideoEditIndex = 4
        BatchCmd(4, 3) = " " & .ECVLineaCmd.CmdLExtract & " " & CmdLEdicion.CmdLDuration & " " & CmdLEdicion.CmdLOut & " " & CmdLEdicion.CmdLV & " " & ffmpeg.FFmpegParametros.SobreescribirYes & " " & ffmpeg.FFmpegParametros.EliminarAudio & " " & ffmpeg.FFmpegParametros.EliminarSubtitulos & " "
        BatchCmd(4, 4) = .ECVLineaCmd.InExtension
        BatchCmd(5, 1) = Chr(34) & .ECVLineaCmd.ExePath & Chr(34) 'Codificar video con un codec externo
        BatchCmd(5, 2) = " " & .ECVLineaCmd.CodecCmdL
        BatchCmd(5, 3) = ""
        BatchCmd(5, 4) = .ECVLineaCmd.OutExtension
    Else
        If .ECANombre <> "" And CmdLEdicion.EliminarV = "" And Not OutMuxerIsCopy Then
            BatchCmd(5, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34) 'Codificar video con ffmpeg
            BatchCmd(5, 2) = " " & .InCmdL & " " & CmdLEdicion.CmdLSetStart & " " & CmdLEdicion.CmdLIn & " -i "
            If InStr(1, CmdLEdicion.CmdLV, "<AnchoInput>", vbTextCompare) > 0 Then CmdVideoEditIndex = 5
            BatchCmd(5, 3) = " " & .OutCmdL & " " & .CmdLV & " " & .CmdLS & " " & CmdLEdicion.CmdLV & " " & CmdLEdicion.CmdLDuration & " " & CmdLEdicion.CmdLOut & " " & ffmpeg.FFmpegParametros.SobreescribirYes & " " & ffmpeg.FFmpegParametros.EliminarAudio & " " & CmdLEdicion.EliminarS & " "
            BatchCmd(5, 4) = .OutExtension
            If Form1.Conv_Opt_2pass.Checked = True Then
                BatchCmd(6, 1) = BatchCmd(5, 1)
                BatchCmd(6, 2) = BatchCmd(5, 2)
                BatchCmd(6, 3) = BatchCmd(5, 3)
                BatchCmd(6, 4) = BatchCmd(5, 4)
                BatchCmd(5, 3) = BatchCmd(5, 3) & " " & ffmpeg.FFmpegParametros.CPase & " 1 "
                BatchCmd(6, 3) = BatchCmd(6, 3) & " " & ffmpeg.FFmpegParametros.CPase & " 2 "
            End If
        End If
    End If

    If .ECANombre <> "" Or .ECVNombre <> "" Then 'Unir pistas de audio y video
        If Not OutMuxerIsCopy Then
            BatchCmd(7, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34)
            BatchCmd(7, 2) = " -i "
            BatchCmd(7, 3) = " " & ObtenerContenedorDeCmdL(.OutCmdL) & " " & ffmpeg.FFmpegParametros.CodecAudio & " copy " & ffmpeg.FFmpegParametros.CodecVideo & " copy " & ffmpeg.FFmpegParametros.CodecSubtitulo & " copy " & ffmpeg.FFmpegParametros.SobreescribirYes & " "
            BatchCmd(7, 4) = .OutExtension
        Else
            BatchCmd(7, 1) = "<copy>"
            BatchCmd(7, 4) = .OutExtension
        End If
    End If

    If .ECANombre = "" And .ECVNombre = "" Then 'Convertir el archivo con ffmpeg
        BatchCmd(7, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34)
        BatchCmd(7, 2) = " " & .InCmdL & " " & CmdLEdicion.CmdLSetStart & " " & CmdLEdicion.CmdLIn & " -i "
        If InStr(1, CmdLEdicion.CmdLV, "<AnchoInput>", vbTextCompare) > 0 Then CmdVideoEditIndex = 7
        BatchCmd(7, 3) = " " & .OutCmdL & " " & .CmdLA & " " & .CmdLS & " " & .CmdLV & " " & CmdLEdicion.CmdLA & " " & CmdLEdicion.CmdLDuration & " " & CmdLEdicion.CmdLOut & " " & CmdLEdicion.CmdLV & " " & ffmpeg.FFmpegParametros.SobreescribirYes & " " & CmdLEdicion.EliminarA & " " & CmdLEdicion.EliminarS & " " & CmdLEdicion.EliminarV & " "
        BatchCmd(7, 4) = .OutExtension
        If Form1.Conv_Opt_2pass.Checked = True Then
            BatchCmd(8, 1) = BatchCmd(7, 1)
            BatchCmd(8, 2) = BatchCmd(7, 2)
            BatchCmd(8, 3) = BatchCmd(7, 3)
            BatchCmd(8, 4) = BatchCmd(7, 4)
            BatchCmd(7, 3) = BatchCmd(7, 3) & " " & ffmpeg.FFmpegParametros.CPase & " 1 "
            BatchCmd(8, 3) = BatchCmd(8, 3) & " " & ffmpeg.FFmpegParametros.CPase & " 2 "
        End If
    End If
End With

For i = 1 To 8
    For j = 1 To 4: BatchCmd(i, j) = QuitarDoblesEspacios(BatchCmd(i, j)): Next
Next

GenerarLineaDeComandos = True
End Function

Private Function ObtenerContenedorDeCmdL(CmdlStr As String) As String
Dim Posicion1 As Long, Posicion2 As Long, BufferStr As String
BufferStr = " " & CmdlStr & " "
Posicion1 = InStr(1, BufferStr, " " & ffmpeg.FFmpegParametros.Contenedor & " ")
If Posicion1 > 0 Then
Posicion1 = Posicion1 + 2 + Len(ffmpeg.FFmpegParametros.Contenedor)
Posicion2 = InStr(Posicion1, BufferStr, " ")
If Posicion2 > 0 Then
ObtenerContenedorDeCmdL = ffmpeg.FFmpegParametros.Contenedor & " " & Mid(BufferStr, Posicion1, Posicion2 - Posicion1)
End If
End If
End Function

Private Function QuitarDoblesEspacios(Cadena As String) As String
Dim CadenaSplit() As String, i As Integer, Ret As String
If Cadena = "" Then Exit Function
CadenaSplit = Split(Cadena, Chr(34))
i = LBound(CadenaSplit)
While i <= UBound(CadenaSplit)
While InStr(1, CadenaSplit(i), "  ") > 0: CadenaSplit(i) = Replace(CadenaSplit(i), "  ", " "): Wend
i = i + 2
If i - 1 < UBound(CadenaSplit) Then CadenaSplit(i - 1) = Chr(34) & CadenaSplit(i - 1) & Chr(34)
Wend
For i = LBound(CadenaSplit) To UBound(CadenaSplit)
Ret = Ret & CadenaSplit(i)
Next
If Left(Cadena, 1) = Chr(34) And Left(Ret, 1) <> Chr(34) Then Ret = Chr(34) & Ret
If Right(Cadena, 1) = Chr(34) And Right(Ret, 1) <> Chr(34) Then Ret = Chr(34) & Ret
QuitarDoblesEspacios = Ret
End Function

Public Sub IniciarConversion(Optional TestTime As String)
Dim ErrCount As Integer
Dim ConvCount As Integer, Ruta() As String, n As Integer, i As Integer
Dim Comandos As String, BufferConsola As String, BufferError As Long
Dim InRuta() As String, OcurrioError As Byte
Dim RutaAV(1 To 2) As String, RutaOut As String
Dim RutaOut2 As String, InputRutaAV(1 To 2) As String
Dim DestinoPistas() As String
Dim ComandosVideo As String
Dim CodecExternoOutPath As String
Dim DirectorioInicial As String
If ffmpeg.ComprobarExistenciaFFmpeg = False Then Exit Sub
If Aplicacion.InFilesCount = 0 Then 'Comprobar que se han agregado archivo a la lista
    Lang.Convert_AddFiles2List
    Exit Sub
End If
If TestTime = "" Then
    If VerificarMapeados = False Then Exit Sub 'Verifica que existen archivos mapeados con streams subseleccionados y que no se ha seleccionado la opcion para concatenar archivos ya que es incompatible
End If
If Form1.Text1.Text = "" And TestTime = "" And Form1.Combo1.ListIndex <> 2 Then 'Comprobar que se ha especificado una ruta de salida
    Lang.Convert_EspecifiqueSalida
    Exit Sub
End If

If TestTime = "" Then
    'Comprobar que exista el directorio seleccionado para guardar convertidos
    Select Case Form1.Combo1.ListIndex
    Case Is < 2
        If ScriptObj.ExisteCarpeta(ScriptObj.DirectorioPadre(Aplicacion.OutFile)) = False Then
            Call Lang.MsgOutDirNotFound(ScriptObj.DirectorioPadre(Aplicacion.OutFile))
            Exit Sub
        End If
    Case 3
        If ScriptObj.ExisteCarpeta(Aplicacion.OutDir) = False Then
            Call Lang.MsgOutDirNotFound(Aplicacion.OutDir)
            Exit Sub
        End If
    End Select
    'Comprobar que ruta de salida no sea directorio temporal
    n = Len(App.Path) + 14
    If Form1.Combo1.ListIndex = 0 Or Form1.Combo1.ListIndex = 1 Or Form1.Combo1.ListIndex = 3 Then
        If Len(Form1.Text1.Text) >= n Then
            If LCase(Left(Form1.Text1.Text, n)) = LCase(App.Path & "\appfiles\temp") Then
                Call Lang.MsgNoSePuedenGuardarEnTemp(Form1.Text1.Text)
                Exit Sub
            End If
        End If
    Else
        For i = 1 To Aplicacion.InFilesCount
            If Len(Aplicacion.InFiles(i)) >= n Then
                If LCase(Left(Aplicacion.InFiles(i), n)) = LCase(App.Path & "\appfiles\temp") Then
                    Call Lang.MsgNoSePuedenGuardarEnTemp(Aplicacion.InFiles(i))
                    Exit Sub
                End If
            End If
        Next
    End If
End If
If TestTime <> "" And Form1.Combo1.ListIndex > 1 And Form1.List1.ListIndex = -1 And Form1.List1.ListCount > 1 Then 'Comprobar que se ha seleccionado un archivo para la prueba
    Lang.Convert_SelectFile4Test
    Exit Sub
End If
If GenerarLineaDeComandos(TestTime) = False Then Exit Sub  'Generar línea de comandos

'Generar lista de rutas de entrada
Select Case Form1.Combo1.ListIndex
    Case Is = 0 'Se seleccionó concatenar los archivos
        ReDim Ruta(1 To 1)
        Ruta(1) = GenerarListaConcat 'Concatenar los archivos
        If Ruta(1) = "" Then Exit Sub
    Case Is = 1 'Se seleccionó guardar como un solo archivo
        ReDim Ruta(1 To 1)
        For i = 1 To Aplicacion.InFilesCount
            Ruta(1) = Ruta(1) & "*" & ScriptObj.Archivo_RutaCorta(Aplicacion.InFiles(i))
        Next
        Ruta(1) = Right(Ruta(1), Len(Ruta(1)) - 1)
    Case Else 'Se seleccionó procesar cada archivo por separado
        If TestTime <> "" Then 'Se realizará una prueba, la ruta de entrada será la seleccionada
            ReDim Ruta(1 To 1)
            If Form1.List1.ListIndex = -1 Then Form1.List1.ListIndex = 0
            Ruta(1) = ScriptObj.Archivo_RutaCorta(Aplicacion.InFiles(Form1.List1.ListIndex + 1))
        Else 'No se realizará una prueba, se generará una lista con los archivos a convertir
            ReDim Ruta(1 To Aplicacion.InFilesCount)
            For i = 1 To Aplicacion.InFilesCount
                Ruta(i) = ScriptObj.Archivo_RutaCorta(Aplicacion.InFiles(i))
            Next
        End If
End Select

'Crear directorio temporal si:
'-se realizará una prueba de conversión
'-se eligió la opción '2 pases' para la codificación
'-se utilizarán codecs externos
If BatchCmd(2, 1) <> "" Or BatchCmd(5, 1) <> "" Or TestTime <> "" Or Form1.Conv_Opt_2pass.Checked = True Then
DirectorioTemporal = Aplicacion.CrearDirectorioTemporal(1)
If DirectorioTemporal = "" Then Exit Sub
End If

DetenerConversion = 0 '0 para continuar, 1 para detener
BloquearCierreF12 = 1 'Bloquea el cierre del Form12
ConvCount = 0 'Contador de archivos convertidos
n = UBound(Ruta) 'Número de archivos a convertir
Load Form12

'Ruta de archivo actual: "<Todos los archivos>"
If Form1.Combo1.ListIndex < 2 Then Form12.Text1.Text = Lang.Convert_Str_AllFiles
Form12.Text3.Text = Trim(Lang.Convert_Str_Errores) & " 0"
Form12.Show

''''       ''''''''       ''''
 ''''     ''''''''''     ''''
  ''''   '''''   ''''   ''''
   '''' '''''     '''' ''''
    '''''''        '''''''
'INICIAR CICLO DE CONVERSIÓN

If CmdVideoEditIndex > 0 Then ComandosVideo = BatchCmd(CmdVideoEditIndex, 3)

While ConvCount < n And DetenerConversion = 0
    If Form1.Combo1.ListIndex > 1 Then Form12.Text1.Text = Aplicacion.InFiles(ConvCount + 1) 'Muestra la ruta del archivo que sera convertido
    Form12.Text2.Text = Trim(CStr(ConvCount)) & "/" & Trim(CStr(n)) 'Actualiza el contador de archivos convertidos
    Form12.Text4.Text = "" 'Mensaje de Tarea actual
    RutaAV(1) = Ruta(ConvCount + 1) 'Ruta de la pista de audio=Ruta del archivo
    RutaAV(2) = Ruta(ConvCount + 1) 'Ruta de la pista de video=Ruta del archivo
    'hacer una copia de las rutas de entrada originales
    InputRutaAV(1) = RutaAV(1)
    InputRutaAV(2) = RutaAV(2)

    'Generar ruta de salida
    If TestTime = "" Then 'No se ralizará una prueba
        Select Case Form1.Combo1.ListIndex
            Case Is = 2 'Guardar en directorio de archivo original
                RutaOut = ScriptObj.DirectorioPadre(Aplicacion.InFiles(ConvCount + 1)) & "\" & ScriptObj.NombreBase(Aplicacion.InFiles(ConvCount + 1))
            Case Is = 3 'Guardar en directorio específico
                RutaOut = Aplicacion.OutDir & "\" & ScriptObj.NombreBase(Aplicacion.InFiles(ConvCount + 1))
            Case Else 'Guardar como un archivo
                RutaOut = ScriptObj.DirectorioPadre(Aplicacion.OutFile) & "\" & ScriptObj.NombreBase(Aplicacion.OutFile)
        End Select
        If Multisalida = 1 Then 'Múltiples archivos de salida: agregar el comodín %03d al nombre
            RutaOut = ScriptObj.ResolverConflictoDeNombres(RutaOut)
            If ScriptObj.CrearCarpeta(RutaOut) = False Then OcurrioError = 3
            RutaOut = RutaOut & "\%03d"
        End If
        If BatchCmd(7, 4) <> "" Then RutaOut = RutaOut & "." & BatchCmd(7, 4) 'Agregar la extensión
        RutaOut2 = RutaOut 'Hacer una copia de la ruta generada
    End If
    
    'Se realizará una prueba de conversión
    If TestTime <> "" Then
        If Multisalida = 0 Then 'No se generán múltiples archivos de salida
            RutaOut = DirectorioTemporal & "\test." & BatchCmd(7, 4)
        Else 'Se van a generar múltiples archivos de salida -> crear un directorio de salida temporal
            RutaOut = DirectorioTemporal & "\test"
            If ScriptObj.CrearCarpeta(RutaOut) = False Then 'No se pudo crear el directorio
                OcurrioError = 3
            Else
                RutaOut = DirectorioTemporal & "\test\%03d." & BatchCmd(7, 4)
            End If
        End If
        RutaOut2 = RutaOut
    End If

    If CmdVideoEditIndex > 0 Then
        Form12.Text4.Text = Lang.Str_ObteniendoDimensionesDeVideo
        BatchCmd(CmdVideoEditIndex, 3) = ComandosVideo
        If ReemplazarDimensionesVideo(BatchCmd(CmdVideoEditIndex, 3), InputRutaAV(1)) = False Then OcurrioError = 5
    End If

    'Extraer audio
    If BatchCmd(1, 1) <> "" And DetenerConversion = 0 And OcurrioError = 0 Then
        Comandos = BatchCmd(1, 1)
        InRuta = Split(RutaAV(1), "*")
        For i = LBound(InRuta) To UBound(InRuta)
            Comandos = Comandos & BatchCmd(1, 2) & Chr(34) & InRuta(i) & Chr(34)
        Next
        Comandos = Comandos & GenerarComandosMapeado(ConvCount)
        Erase InRuta
        Comandos = Comandos & BatchCmd(1, 3)
        If UsePipeAudio = 1 Then
            Comandos = Comandos & " -loglevel 8 pipe:1"
        Else
            Comandos = Comandos & Chr(34) & DirectorioTemporal & "\auext." & BatchCmd(1, 4) & Chr(34)
            Form12.Text4.Text = Lang.Convert_Str_ExtrayendoAudio
            BufferConsola = ""
            If CaptureConsole.ExecAndCapture(Comandos, , , , Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
                OcurrioError = 1
            Else
                If BufferError > 0 Then OcurrioError = 2 Else RutaAV(1) = ScriptObj.Archivo_RutaCorta(DirectorioTemporal & "\auext." & BatchCmd(1, 4))
            End If
        End If
    End If

    'Codificar audio (pase 1)
    If BatchCmd(2, 1) <> "" And OcurrioError = 0 And DetenerConversion = 0 Then
        Form12.Text4.Text = Lang.Convert_Str_CodificandoAudio
        InRuta = Split(RutaAV(1), "*")
        If LCase(BatchCmd(2, 1)) = LCase(Chr(34) & ffmpeg.ffmpegPath & Chr(34)) Then 'Se usará ffmpeg para codificar la pista de audio
            If Form1.Conv_Opt_2pass.Checked = True Then Form12.Text4.Text = Form12.Text4.Text & " " & Lang.Convert_Str_Pase1
            Comandos = BatchCmd(2, 1)
            For i = LBound(InRuta) To UBound(InRuta): Comandos = Comandos & BatchCmd(2, 2) & Chr(34) & InRuta(i) & Chr(34): Next
            Comandos = Comandos & GenerarComandosMapeado(ConvCount)
            Erase InRuta
            Comandos = Comandos & BatchCmd(2, 3) & Chr(34) & DirectorioTemporal & "\aucod." & BatchCmd(2, 4) & Chr(34)
            DirectorioInicial = vbNullString
        Else 'Se usará un ejecutable externo para codificar el audio
            'Obtener la ruta de salida
            If OutMuxerIsCopy = False Then 'la pista será guardada en un archivo temporal para después mezclarse con el video
                CodecExternoOutPath = Chr(34) & DirectorioTemporal & "\aucod." & BatchCmd(2, 4) & Chr(34)
            Else 'Se seleccionó '<copy>' para contenedor de salida (se omite el mezclado de pistas)
                If BatchCmd(7, 4) = "" Then RutaOut = RutaOut & "." & BatchCmd(2, 4)
                RutaOut = ScriptObj.ResolverConflictoDeNombres(RutaOut)
                If TestTime <> "" Then
                    ReDim DestinoPistas(1 To 2)
                    DestinoPistas(1) = RutaOut
                End If
                CodecExternoOutPath = Chr(34) & RutaOut & Chr(34)
            End If
            If UsePipeAudio = 1 Then
                Comandos = "cmd.exe /C " & Chr(34) & Comandos & " | " & BatchCmd(2, 1) & Replace(BatchCmd(2, 2), "<outfile>", CodecExternoOutPath) & Chr(34)
            Else
                Comandos = BatchCmd(2, 1) & Replace(Replace(BatchCmd(2, 2), "<infile>", Chr(34) & InRuta(LBound(InRuta)) & Chr(34)), "<outfile>", CodecExternoOutPath)
            End If
            DirectorioInicial = Mid(BatchCmd(2, 1), 2, Len(BatchCmd(2, 1)) - 2)
            DirectorioInicial = ScriptObj.DirectorioPadre(DirectorioInicial)
        End If
        BufferConsola = ""
        Form12.Command1.Enabled = (EnableCtrlCAudio = 1)
        If CaptureConsole.ExecAndCapture(Comandos, DirectorioInicial, 0, EnableWait4MsgAudio, Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
            OcurrioError = 1
        Else
            If BatchCmd(2, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34) And BufferError > 0 Then OcurrioError = 2
            If BatchCmd(2, 1) <> Chr(34) & ffmpeg.ffmpegPath & Chr(34) Then If ScriptObj.TamanoArchivo(Mid(CodecExternoOutPath, 2, Len(CodecExternoOutPath) - 2)) = 0 Then OcurrioError = 2
        End If
        Form12.Command1.Enabled = True
        If OcurrioError = 0 And (Form1.Conv_Opt_2pass.Checked = False Or BatchCmd(2, 1) <> Chr(34) & ffmpeg.ffmpegPath & Chr(34)) Then RutaAV(1) = ScriptObj.Archivo_RutaCorta(DirectorioTemporal & "\aucod." & BatchCmd(2, 4))
    End If

'Codificar audio (pase 2)
    If BatchCmd(3, 1) <> "" And OcurrioError = 0 And DetenerConversion = 0 Then
        Form12.Text4.Text = Lang.Convert_Str_CodificandoAudio & " " & Lang.Convert_Str_Pase2
        Comandos = BatchCmd(3, 1)
        InRuta = Split(RutaAV(1), "*")
        For i = LBound(InRuta) To UBound(InRuta)
            Comandos = Comandos & BatchCmd(3, 2) & Chr(34) & InRuta(i) & Chr(34)
        Next
        Comandos = Comandos & GenerarComandosMapeado(ConvCount)
        Erase InRuta
        BufferConsola = ""
        Comandos = Comandos & BatchCmd(3, 3) & Chr(34) & DirectorioTemporal & "\aucod." & BatchCmd(3, 4) & Chr(34)
        If CaptureConsole.ExecAndCapture(Comandos, , , , Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
            OcurrioError = 1
        Else
            If BufferError > 0 Then OcurrioError = 2 Else RutaAV(1) = ScriptObj.Archivo_RutaCorta(DirectorioTemporal & "\aucod." & BatchCmd(2, 4))
        End If
    End If

    'Borrar el archivo con el audio extraído
    If DirectorioTemporal <> "" Then Call ScriptObj.BorrarArchivo(DirectorioTemporal & "\auext." & BatchCmd(1, 4))

    'Extraer video
    If BatchCmd(4, 1) <> "" And DetenerConversion = 0 And OcurrioError = 0 Then
        Comandos = BatchCmd(4, 1)
        InRuta = Split(RutaAV(2), "*")
        For i = LBound(InRuta) To UBound(InRuta)
            Comandos = Comandos & BatchCmd(4, 2) & Chr(34) & InRuta(i) & Chr(34)
        Next
        Comandos = Comandos & GenerarComandosMapeado(ConvCount)
        Erase InRuta
        Comandos = Comandos & BatchCmd(4, 3)
        If UsePipeVideo = 1 Then
            Comandos = Comandos & " -loglevel 8 pipe:1"
        Else
            Comandos = Comandos & Chr(34) & DirectorioTemporal & "\viext." & BatchCmd(4, 4) & Chr(34)
            Form12.Text4.Text = Lang.Convert_Str_ExtrayendoVideo
            BufferConsola = ""
            If CaptureConsole.ExecAndCapture(Comandos, , , , Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
                OcurrioError = 1
            Else
                If BufferError > 0 Then OcurrioError = 2 Else RutaAV(2) = ScriptObj.Archivo_RutaCorta(DirectorioTemporal & "\viext." & BatchCmd(4, 4))
            End If
        End If
    End If

    'Codificar video(pase 1)
    If BatchCmd(5, 1) <> "" And OcurrioError = 0 And DetenerConversion = 0 Then
        Form12.Text4.Text = Lang.Convert_Str_CodificandoVideo
        InRuta = Split(RutaAV(2), "*")
        If LCase(BatchCmd(5, 1)) = LCase(Chr(34) & ffmpeg.ffmpegPath & Chr(34)) Then 'Se usará ffmpeg para codificar la pista de video
            If Form1.Conv_Opt_2pass.Checked = True Then Form12.Text4.Text = Form12.Text4.Text & " " & Lang.Convert_Str_Pase1
            Comandos = BatchCmd(5, 1)
            For i = LBound(InRuta) To UBound(InRuta): Comandos = Comandos & BatchCmd(5, 2) & Chr(34) & InRuta(i) & Chr(34): Next
            Comandos = Comandos & GenerarComandosMapeado(ConvCount)
            Erase InRuta
            Comandos = Comandos & BatchCmd(5, 3) & Chr(34) & DirectorioTemporal & "\vicod." & BatchCmd(5, 4) & Chr(34)
            DirectorioInicial = vbNullString
        Else 'Se usará un ejecutable externo para codificar el video
            'Obtener la ruta de salida
            If OutMuxerIsCopy = False Then 'la pista será guardada en un archivo temporal para después mezclarse con el audio
                CodecExternoOutPath = Chr(34) & DirectorioTemporal & "\vicod." & BatchCmd(5, 4) & Chr(34)
            Else 'Se seleccionó '<copy>' para contenedor de salida (se omite el mezclado de pistas)
                If BatchCmd(7, 4) = "" Then RutaOut = RutaOut & "." & BatchCmd(5, 4)
                RutaOut = ScriptObj.ResolverConflictoDeNombres(RutaOut)
                If TestTime <> "" Then
                    ReDim Preserve DestinoPistas(1 To 2)
                    DestinoPistas(2) = RutaOut
                End If
                CodecExternoOutPath = Chr(34) & RutaOut & Chr(34)
            End If
            If UsePipeVideo = 1 Then
                Comandos = "cmd.exe /C " & Chr(34) & Comandos & " | " & BatchCmd(5, 1) & Replace(BatchCmd(5, 2), "<outfile>", CodecExternoOutPath) & Chr(34)
            Else
                Comandos = BatchCmd(5, 1) & Replace(Replace(BatchCmd(5, 2), "<infile>", Chr(34) & InRuta(LBound(InRuta)) & Chr(34)), "<outfile>", CodecExternoOutPath)
            End If
            DirectorioInicial = Mid(BatchCmd(5, 1), 2, Len(BatchCmd(5, 1)) - 2)
            DirectorioInicial = ScriptObj.DirectorioPadre(DirectorioInicial)
        End If
        BufferConsola = ""
        Form12.Command1.Enabled = (EnableCtrlCVideo = 1)
        If CaptureConsole.ExecAndCapture(Comandos, DirectorioInicial, 0, EnableWait4MsgVideo, Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
            OcurrioError = 1
        Else
            If BatchCmd(5, 1) = Chr(34) & ffmpeg.ffmpegPath & Chr(34) And BufferError > 0 Then OcurrioError = 2
            If BatchCmd(5, 1) <> Chr(34) & ffmpeg.ffmpegPath & Chr(34) Then If ScriptObj.TamanoArchivo(Mid(CodecExternoOutPath, 2, Len(CodecExternoOutPath) - 2)) = 0 Then OcurrioError = 2
        End If
        Form12.Command1.Enabled = True
        If OcurrioError = 0 And (Form1.Conv_Opt_2pass.Checked = False Or BatchCmd(5, 1) <> Chr(34) & ffmpeg.ffmpegPath & Chr(34)) Then RutaAV(2) = ScriptObj.Archivo_RutaCorta(DirectorioTemporal & "\vicod." & BatchCmd(5, 4))
    End If

    'Codificar video (pase 2)
    If BatchCmd(6, 1) <> "" And OcurrioError = 0 And DetenerConversion = 0 Then
        Form12.Text4.Text = Lang.Convert_Str_CodificandoVideo & " " & Lang.Convert_Str_Pase2
        Comandos = BatchCmd(6, 1)
        InRuta = Split(RutaAV(2), "*")
        For i = LBound(InRuta) To UBound(InRuta)
            Comandos = Comandos & BatchCmd(6, 2) & Chr(34) & InRuta(i) & Chr(34)
        Next
        Comandos = Comandos & GenerarComandosMapeado(ConvCount)
        Erase InRuta
        BufferConsola = ""
        Comandos = Comandos & BatchCmd(6, 3) & Chr(34) & DirectorioTemporal & "\vicod." & BatchCmd(6, 4) & Chr(34)
        If CaptureConsole.ExecAndCapture(Comandos, , , , Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
            OcurrioError = 1
        Else
            If BufferError > 0 Then OcurrioError = 2 Else RutaAV(2) = ScriptObj.Archivo_RutaCorta(DirectorioTemporal & "\vicod." & BatchCmd(6, 4))
        End If
    End If

    'Borrar el archivo con el video extraído
    If DirectorioTemporal <> "" Then Call ScriptObj.BorrarArchivo(DirectorioTemporal & "\viext." & BatchCmd(4, 4))

    'Generar la ruta de salida final (sin conflictos de nombres)

    If DetenerConversion = 0 And OcurrioError = 0 And TestTime = "" And Multisalida = 0 And OutMuxerIsCopy = False Then
        RutaOut = ScriptObj.ResolverConflictoDeNombres(RutaOut)
    End If

    'Mezclar audio y video
    If RutaAV(1) <> RutaAV(2) And OcurrioError = 0 And DetenerConversion = 0 And OutMuxerIsCopy = False Then
        Form12.Text4.Text = Lang.Convert_Str_MezclandoAV
        Comandos = BatchCmd(7, 1)
        If InputRutaAV(1) <> RutaAV(1) Then Comandos = Comandos & BatchCmd(7, 2) & Chr(34) & RutaAV(1) & Chr(34)
        If InputRutaAV(2) <> RutaAV(2) Then Comandos = Comandos & BatchCmd(7, 2) & Chr(34) & RutaAV(2) & Chr(34)
        Comandos = Comandos & BatchCmd(7, 3) & Chr(34) & RutaOut & Chr(34)
        BufferConsola = ""
        If CaptureConsole.ExecAndCapture(Comandos, , , , Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
            OcurrioError = 1
        Else
            If BufferError > 0 Then OcurrioError = 2
        End If
    End If

    'Codificar audio y video (pase 1)
    If RutaAV(1) = RutaAV(2) And DetenerConversion = 0 And OcurrioError = 0 And OutMuxerIsCopy = False Then
        Form12.Text4.Text = Lang.Convert_Str_Convirtiendo
        If Form1.Conv_Opt_2pass.Checked = True Then Form12.Text4.Text = Form12.Text4.Text & " " & Lang.Convert_Str_Pase1
        Comandos = BatchCmd(7, 1)
        InRuta = Split(RutaAV(1), "*")
        For i = LBound(InRuta) To UBound(InRuta)
            Comandos = Comandos & BatchCmd(7, 2) & Chr(34) & InRuta(i) & Chr(34)
        Next
        Comandos = Comandos & GenerarComandosMapeado(ConvCount)
        Erase InRuta
        Comandos = Comandos & BatchCmd(7, 3) & Chr(34) & RutaOut & Chr(34)
        BufferConsola = ""
        If CaptureConsole.ExecAndCapture(Comandos, , , , Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
            OcurrioError = 1
        Else
            If BufferError > 0 Then OcurrioError = 2
        End If
    End If

    'Codificar audio y video (pase 2)
    If BatchCmd(8, 1) <> "" And OcurrioError = 0 And DetenerConversion = 0 And OutMuxerIsCopy = False Then
        Form12.Text4.Text = Lang.Convert_Str_Convirtiendo & " " & Lang.Convert_Str_Pase2
        Comandos = BatchCmd(8, 1)
        InRuta = Split(RutaAV(1), "*")
        For i = LBound(InRuta) To UBound(InRuta)
            Comandos = Comandos & BatchCmd(8, 2) & Chr(34) & InRuta(i) & Chr(34)
        Next
        Comandos = Comandos & GenerarComandosMapeado(ConvCount)
        Erase InRuta
        BufferConsola = ""
        Comandos = Comandos & BatchCmd(8, 3) & Chr(34) & RutaOut & Chr(34)
        If CaptureConsole.ExecAndCapture(Comandos, , , , Form12.Text5, False, 3, BufferConsola, 4096, BufferError) = False Then
            OcurrioError = 1
        Else
            If BufferError > 0 Then OcurrioError = 2
        End If
    End If

    If DirectorioTemporal <> "" And OutMuxerIsCopy = False Then 'Borrar los archivos con las pistas de audio y video codificadas
        Call ScriptObj.BorrarArchivo(DirectorioTemporal & "\aucod." & BatchCmd(2, 4))
        Call ScriptObj.BorrarArchivo(DirectorioTemporal & "\vicod." & BatchCmd(5, 4))
    End If

    If OcurrioError = 0 And DetenerConversion = 0 And TestTime = "" Then
        If Form1.Conv_Opt_DelFiles.Checked = True Then 'manda los archivos originales a la papelera de reciclaje
            If Form1.Combo1.ListIndex < 2 Then
                For i = 1 To Aplicacion.InFilesCount: Call APIS.APIDeletePath(Aplicacion.InFiles(i), 1): Next
            Else
                Call APIS.APIDeletePath(Aplicacion.InFiles(ConvCount + 1), 1)
            End If
        End If
        If RutaOut <> RutaOut2 And Form1.Conv_Opt_Reemplazar.Checked = True And OutMuxerIsCopy = False Then 'Se eligió reemplazar archivos
            If APIS.APIDeletePath(RutaOut2, 1) = True Then Call ScriptObj.CambiarNombreBaseArchivo(RutaOut, ScriptObj.NombreBase(RutaOut2))
        End If
    End If

    If OcurrioError > 0 And DetenerConversion = 0 Then 'Si ocurrió error -> agregar descripción a la lista
        ErrCount = ErrCount + 1
        ReDim Preserve Errores(1 To 6, 1 To ErrCount)
        Errores(1, ErrCount) = Form12.Text1.Text 'Ruta de archivo
        Errores(2, ErrCount) = Form12.Text4.Text 'Tarea efectuada
        Select Case OcurrioError 'Descripción del error
            Case Is = 1: Errores(3, ErrCount) = Lang.Convert_Str_CantIniProc 'No se pudo iniciar el proceso (no se pudo ejecutar ffmpeg ó el exe del codec externo)
            Case Is = 2: Errores(3, ErrCount) = Lang.Convert_Str_ConvError 'Error al convertir el archivo: se determina que ocurrió cuando ffmpeg devuelve un código de error mayor a 0 ó (en el caso de los exes de codecs externos) el archivo convertido no existe ó tiene un tamaño de 0 Bytes
            Case Is = 3: Errores(3, ErrCount) = Lang.Convert_str_CantCreateOutDir & ":" & RutaOut 'No se pudo crear el directorio de salida (ocurre cuando se generan múltiples archivos de salida, entonces se debe crear un directorio dentro del cúal se guarden los archivos)
            Case Is = 4: Errores(3, ErrCount) = Lang.Conv_Str_CantMoviendoPistas 'No se pudieron mover las pistas de audio y/o video
            Case Is = 5: Errores(3, ErrCount) = Lang.Msg_NoSePudoObtenerDimensionWxH 'No se pudo determinar el ancho y alto del video de entrada
        End Select
        If OcurrioError < 3 Then Errores(4, ErrCount) = Comandos 'Comandos ejecutados que provocaron el error
        If OcurrioError = 2 Then Errores(5, ErrCount) = BufferConsola 'Mensaje de la consola
        If Form1.CnvOpt_QuitarConv.Checked And (Form1.Combo1.ListIndex > 1 Or Aplicacion.InFilesCount = 1) Then Errores(6, ErrCount) = Aplicacion.InFilesMap(ConvCount + 1) 'Streams seleccionados del archivo
        Form12.Text3.Text = Trim(Lang.Convert_Str_Errores) & " " & Trim(CStr(ErrCount)) 'actualiza el contador de errores
        OcurrioError = 0
    End If

    If DetenerConversion = 0 Then ConvCount = ConvCount + 1
Wend

''''       ''''''''       ''''
 ''''     ''''''''''     ''''
  ''''   '''''   ''''   ''''
   '''' '''''     '''' ''''
    '''''''        '''''''
'FINALIZA LA CONVERSIÓN

Form12.Text4.Text = ""
Form12.Text5.Text = ""
If DetenerConversion = 1 Then
    Form12.Text1.Text = Lang.Convert_Str_ProcesoDetenido
Else
    Form12.Text1.Text = Lang.Convert_Str_ProcesoTermino
    Form12.Text2.Text = ""
End If
BloquearCierreF12 = 0
DetenerConversion = 0

If TestTime <> "" And DetenerConversion = 0 And ErrCount = 0 Then 'Informar resultado de prueba y ofrecer ver el segment convertido
    If Multisalida = 0 Then
        If OutMuxerIsCopy = False Then
            If MsgBox(Lang.Convert_str_PruebaFinalizada & vbCrLf & Lang.Convert_str_PruebaFileSize & " " & Trim(CStr(Round(ScriptObj.TamanoArchivo(RutaOut) / 1024 / 1024, 2))) & "MB " & "(" & Trim(CStr(Round(ScriptObj.TamanoArchivo(RutaOut) / CSng(TestTime) * 60 / 1024 / 1024, 2))) & "MB/min)" & vbCrLf & Lang.Convert_str_PruebaQstPlay, vbYesNo, Form1.Caption) = vbYes Then Call ffmpeg.PlayFile(RutaOut)
        Else
            ReDim Preserve DestinoPistas(1 To 2)
            If MsgBox(Lang.Convert_str_PruebaFinalizada & vbCrLf & Lang.Convert_str_PruebaFileSize & " " & Trim(CStr(Round((ScriptObj.TamanoArchivo(DestinoPistas(1)) + ScriptObj.TamanoArchivo(DestinoPistas(2))) / 1024 / 1024, 2))) & "MB" & vbCrLf & Convert_str_PruebaQstPlay, vbYesNo, Form1.Caption) = vbYes Then
                Comandos = DestinoPistas(1) & "|" & DestinoPistas(2)
                Call ffmpeg.PlayFile(Comandos)
            End If
        End If
    Else
        If MsgBox(Lang.Convert_str_PruebaFinalizada & vbCrLf & Lang.Convert_str_PruebaFileSize & " " & Trim(CStr(Round(ScriptObj.TamanoCarpeta(ScriptObj.DirectorioPadre(RutaOut)) / 1024 / 1024, 2))) & "MB" & vbCrLf & Lang.Convert_str_PruebaQstViewFiles, vbYesNo, Form1.Caption) = vbYes Then Shell "explorer.exe " & Chr(34) & ScriptObj.DirectorioPadre(RutaOut) & Chr(34), vbNormalFocus
    End If
End If

Form12.Command3.Visible = (ErrCount > 0) 'Hacer visible el botón para ver lista de errores
Form12.Command2.Visible = True 'Hacer visible el botón 'Hecho'
Form12.Command1.Visible = False 'Ocultar botón 'detener'
Form12.Command4.Visible = False 'Ocultar boton 'detener (force)'
If ErrCount > 0 Then 'llenar la lista de rutas con error
For i = 1 To ErrCount: Form12.List1.AddItem Errores(1, i): Next
End If

'Quitar archivos convertidos de la lista
   'No se esta realizando prueba    'Selecciono quitar archivos           'Al menos un archivo se proceso sin errores
If TestTime = vbNullString And Form1.CnvOpt_QuitarConv.Checked = True And ConvCount - ErrCount > 0 Then
    If n - ConvCount + ErrCount = 0 Then 'Todos los archivos fueron convertidos
        Erase Aplicacion.InFiles
        Erase Aplicacion.InFilesMap
        Aplicacion.InFilesCount = 0
        Form1.List1.Clear
    Else
        For i = 1 To ErrCount 'Agrega los archivos no convertidos debido a errores
            Aplicacion.InFiles(i) = Errores(1, i)
            Aplicacion.InFilesMap(i) = Errores(6, i)
        Next
        n = ErrCount
        For i = ConvCount + 1 To Aplicacion.InFilesCount
            n = n + 1
            Aplicacion.InFiles(n) = Aplicacion.InFiles(i)
            Aplicacion.InFilesMap(n) = Aplicacion.InFilesMap(i)
        Next
        ReDim Preserve Aplicacion.InFiles(1 To n)
        ReDim Preserve Aplicacion.InFilesMap(1 To n)
        Aplicacion.InFilesCount = n
        Aplicacion.RefreshInListBox
    End If
End If

End Sub

Public Function GenerarListaConcat() As String
Dim i As Integer, Buffer As String, TemporalD As String, NumArchivo As Integer
TemporalD = Aplicacion.CrearDirectorioTemporal(0)
If TemporalD = "" Then GoTo ErrH
For i = 1 To Aplicacion.InFilesCount
Buffer = Buffer & "file '" & ScriptObj.Archivo_RutaCorta(Aplicacion.InFiles(i)) & "'" & vbCrLf
Next
On Error GoTo ErrH
NumArchivo = FreeFile
Open TemporalD & "\concat.txt" For Binary As NumArchivo
Put NumArchivo, , Buffer
Close NumArchivo
GenerarListaConcat = ScriptObj.Archivo_RutaCorta(TemporalD & "\concat.txt")
Exit Function
ErrH:
Lang.MsgCantWriteFile (TemporalD & "\concat.txt")
End Function

Public Function InterpretarPFormato(Ruta As String, ByRef VError As Byte) As FormatoCmdL
Dim NumArchivo As Integer, BufF As Appfilesadm.FormatPerf
Dim VRet As FormatoCmdL, BufError As Byte
'Verror
'0: ningún error
'1: el perfil no existe
'2: error al leer el perfil
'3: error al generar la línea de comandos para el codec externo de audio
'4: error al generar la línea de comandos para el codec externo de video
'5: error al seleccionar copy para el muxer de salida
If ScriptObj.ExisteArchivo(Ruta) = False Then
VError = 1
If ScriptObj.NombreBase(Ruta) = "" Then VError = 0
GoTo ErrH
End If
On Error GoTo ErrH
VError = 2
NumArchivo = FreeFile
Open Ruta For Binary As NumArchivo
Get NumArchivo, , BufF
Close NumArchivo
VRet = PerfilFormatoACmdL(BufF, BufError)
If BufError > 0 Then
VError = BufError + 2
GoTo ErrH
End If
VError = 0
InterpretarPFormato = VRet
ErrH:
End Function

Public Function InterpretarPEdicion(Ruta As String, ByRef VError As Byte, ByRef ErrPathFiltro As String) As EditCmdL
'Verror
'0: ningún error
'1: el archivo no existe
'2: error al leer el archivo
'3: se eligió eliminar todas las pistas
'4: error al leer el filtro ubicado en ErrPathFiltro
'5: error al generar comandos de edición de audio
'6: error al generar comandos de edición de video
'7: error al generar comandos para recortar secuencia
Dim NumArchivo As Integer, BufPE As Appfilesadm.PerfEdit
Dim VRet As EditCmdL, BufError As Byte
If ScriptObj.ExisteArchivo(Ruta) = False Then
VError = 1
If ScriptObj.NombreBase(Ruta) = "" Then VError = 0
GoTo ErrH
End If
On Error GoTo ErrH
VError = 2
NumArchivo = FreeFile
Open Ruta For Binary As NumArchivo
Get NumArchivo, , BufPE
Close NumArchivo
VRet = PerfilEditACmdL(BufPE, BufError, ErrPathFiltro)
If BufError > 0 Then
VError = BufError + 2
GoTo ErrH
End If
VError = 0
InterpretarPEdicion = VRet
ErrH:
End Function

Private Function LocalizarRutaEC(Ruta As String, CodecName As String, CodecTipo As Byte) As String
'Ruta: la ruta inicial en dónde buscar el exe
'CodecName: el nombre base del archivo del codec
'CodecTipo: 0-audio, 1-video
Dim NumArchivo As String, RutaRet As String, RutaCodec As String
Dim BufferEC As Appfilesadm.ExternalCodec, FExt As String
Dim NombreExe As String, Rutas() As String, i As Long
If Ruta = "" Then Exit Function
If CodecTipo = 0 Then FExt = ".lca" Else FExt = ".lcv"
'Busca el exe en la ruta indicada por el codec adjunto al perfil de formato
RutaRet = Aplicacion.CompletarRuta(Ruta)
If ScriptObj.ExisteArchivo(RutaRet) = True Then
LocalizarRutaEC = RutaRet
Exit Function
End If
'Busca el exe en la ruta indicada por el codec
On Error GoTo Salir
RutaCodec = App.Path & "\appfiles\ecodec\" & CodecName & FExt
If ScriptObj.ExisteArchivo(RutaCodec) = True Then
    NumArchivo = FreeFile
    Open RutaCodec For Binary As NumArchivo
    Get NumArchivo, , BufferEC
    Close NumArchivo
    RutaRet = Aplicacion.CompletarRuta(BufferEC.RutaExe)
    If ScriptObj.ExisteArchivo(RutaRet) = True Then
        LocalizarRutaEC = RutaRet
        Exit Function
    End If
End If
Salir:
End Function

Private Function MoverPistasCodificadas(Entrada As String, RSalida As String) As String()
Dim Rutas() As String, i As Integer
Dim DirectorioSalida As String, ExtensionSalida As String
Dim NombreSalida As String
Dim NombreBase As String, Ret() As String
ReDim MoverPistasCodificadas(1 To 1)
Rutas = Split(Entrada, "|")
DirectorioSalida = ScriptObj.DirectorioPadre(RSalida) & "\"
NombreBase = ScriptObj.NombreBase(RSalida)
ExtensionSalida = ScriptObj.DevolverExtension(RSalida)
NombreSalida = NombreBase
i = 2
If Rutas(LBound(Rutas)) <> "" And Rutas(UBound(Rutas)) <> "" Then
While ScriptObj.ExisteArchivo(DirectorioSalida & NombreSalida & "_audio." & ExtensionSalida) = True Or ScriptObj.ExisteArchivo(DirectorioSalida & NombreSalida & "_video." & ExtensionSalida) = True
NombreSalida = NombreBase & " (" & Trim(CStr(i)) & ")"
i = i + 1
Wend
ReDim Ret(1 To 2)
Ret(1) = DirectorioSalida & NombreSalida & "_audio." & ExtensionSalida
Ret(2) = DirectorioSalida & NombreSalida & "_video." & ExtensionSalida
If ScriptObj.MoverArchivo(Rutas(LBound(Rutas)), Ret(1)) = False Then GoTo Salir
If ScriptObj.MoverArchivo(Rutas(LBound(Rutas)), Ret(2)) = False Then GoTo Salir
Else
While ScriptObj.ExisteArchivo(DirectorioSalida & NombreSalida & "." & ExtensionSalida) = True
NombreSalida = NombreBase & " (" & Trim(CStr(i)) & ")"
i = i + 1
Wend
ReDim Ret(1 To 1)
Ret(1) = DirectorioSalida & NombreSalida & "." & ExtensionSalida
If Rutas(LBound(Rutas)) <> "" Then
If ScriptObj.MoverArchivo(Rutas(LBound(Rutas)), Ret(1)) = False Then GoTo Salir
Else
If ScriptObj.MoverArchivo(Rutas(UBound(Rutas)), Ret(1)) = False Then GoTo Salir
End If
End If
MoverPistasCodificadas = Ret
Salir:
End Function

Private Function DeterminarExtension(FormatoContenedor As String) As String
Dim Comandos As String, BuferCmd As String, Posicion1 As Long, Posicion2 As Long
Dim Fmt As String
On Error GoTo Salir
If FormatoContenedor = "" Then Exit Function
Fmt = Right(FormatoContenedor, Len(FormatoContenedor) - Len(ffmpeg.FFmpegParametros.Contenedor) - 1)
Comandos = Chr(34) & ffmpeg.ffmpegPath & Chr(34) & " -h muxer=" & Fmt
Call CaptureConsole.ExecAndCapture(Comandos, , , , , , , BuferCmd)
If BuferCmd = "" Then Exit Function
Posicion1 = InStr(1, BuferCmd, vbCrLf & "    Common extensions:")
If Posicion1 = 0 Then Exit Function
Posicion1 = Posicion1 + 25
Posicion2 = InStr(Posicion1, BuferCmd, vbCrLf)
If Posicion2 = 0 Then Exit Function
BuferCmd = Mid(BuferCmd, Posicion1, Posicion2 - Posicion1)
Posicion1 = InStr(1, BuferCmd, ",")
If Posicion1 = 0 Then Posicion1 = InStr(1, BuferCmd, ".")
If Posicion1 = 0 Then Exit Function
DeterminarExtension = Trim(Left(BuferCmd, Posicion1 - 1))
Salir:
End Function

Public Function CmdAgregarBordes(ByRef PerfilEdicion As PerfEdit) As String
Dim EAncho As String, EAlto As String, EPosX As String, EPosY As String, ColorR As String
Dim Comandos As String
With PerfilEdicion
EAncho = "iw+"
If .AgBorde_Izquierda <> "" Then
    EAncho = EAncho & .AgBorde_Izquierda
    EPosX = .AgBorde_Izquierda
    Select Case .AgBorde_IzquierdaU
        Case 1
            EAncho = EAncho & "*iw"
            EPosX = EPosX & "*iw"
        Case 2
            EAncho = EAncho & "*ih"
            EPosX = EPosX & "*ih"
    End Select
End If
If .AgBorde_Derecha <> "" Then
    EAncho = EAncho & "+" & .AgBorde_Derecha
    Select Case .AgBorde_DerechaU
        Case 1: EAncho = EAncho & "*iw"
        Case 2: EAncho = EAncho & "*ih"
    End Select
End If
EAlto = "ih+"
If .AgBorde_Arriba <> "" Then
    EAlto = EAlto & .AgBorde_Arriba
    EPosY = .AgBorde_Arriba
    Select Case .AgBorde_ArribaU
        Case 1
            EAlto = EAlto & "*iw"
            EPosY = EPosY & "*iw"
        Case 2
            EAlto = EAlto & "*ih"
            EPosY = EPosY & "*ih"
    End Select
End If
If .AgBorde_Abajo <> "" Then
    EAlto = EAlto & "+" & .AgBorde_Abajo
    Select Case .AgBorde_AbajoU
        Case 1: EAlto = EAlto & "*iw"
        Case 2: EAlto = EAlto & "*ih"
    End Select
End If
If EPosX = "" Then EPosX = "0"
If EPosY = "" Then EPosY = "0"
If EAncho = "iw+" Then EAncho = "iw"
If EAlto = "ih+" Then EAlto = "ih"
If EAncho = "iw" And EAlto = "ih" Then Exit Function 'No hay nada que hacer

Select Case .RellenoBordeOpt
    Case 0 'Agrega bordes con relleno color sólido
        If Len(.AgBorde_Color) < 6 Then ColorR = "000000" Else ColorR = .AgBorde_Color
        Comandos = ffmpeg.FFmpegParametros.FiltroVideo & " pad=w=" & EAncho & ":h=" & EAlto & ":x=" & EPosX & ":y=" & EPosY & ":color=" & ColorR
    Case 1 'Agrega bordes con relleno de imagen o video
            EAncho = Replace(Replace(EAncho, "iw", "<AnchoInput>"), "ih", "<AltoInput>")
            EAlto = Replace(Replace(EAlto, "iw", "<AnchoInput>"), "ih", "<AltoInput>")
            EPosX = Replace(Replace(EPosX, "iw", "<AnchoInput>"), "ih", "<AltoInput>")
            EPosY = Replace(Replace(EPosY, "iw", "<AnchoInput>"), "ih", "<AltoInput>")
            Comandos = ffmpeg.FFmpegParametros.Filtro & " " & Chr(34)
            Comandos = Comandos & " movie=filename=\'" & Replace(Replace(.RutaImagenBorde, "\", "/"), ":", "\:") & "\'," & "scale=w=" & EAncho & ":h=" & EAlto & ",setdar [a];"
            Comandos = Comandos & " color=color=white:size=20x20,scale=w=" & EAncho & ":" & "h=" & EAlto & ",setdar [b];"
            Comandos = Comandos & " color=color=black:size=<AnchoInput>x<AltoInput>" & " [tmp];"
            Comandos = Comandos & " [b][tmp] overlay=x=" & EPosX & ":y=" & EPosY & " [b];"
            Comandos = Comandos & " [a][b] alphamerge [b];"
            Comandos = Comandos & " pad=w=" & EAncho & ":h=" & EAlto & ":x=" & EPosX & ":y=" & EPosY & ":color=black [a];"
            Comandos = Comandos & " [a][b] overlay" & Chr(34)
    Case 2
        Comandos = ffmpeg.FFmpegParametros.Filtro & " " & Chr(34) & "scale=w=" & EAncho & ":h=" & EAlto & ",setdar [tmp];"
        Select Case .EfectoRelleno
            'blur
            Case 1: Comandos = Comandos & " [tmp] boxblur=9:1 [tmp];"
            'ruido
            Case 2: Comandos = Comandos & " [tmp] noise=alls=100:allf=t [tmp];"
            'pixelado
             Case 3: Comandos = Comandos & " [tmp] scale=w=0.1*iw:h=0.1*ih:flags=neighbor,scale=w=10*iw:h=10*ih:flags=neighbor [tmp];"
            'pixelado & blur
             Case 4: Comandos = Comandos & " [tmp] scale=w=0.1*iw:h=0.1*ih:flags=neighbor,scale=w=10*iw:h=10*ih:flags=neighbor, boxblur=7:1 [tmp];"
            'viñeta
            Case 5: Comandos = Comandos & " [tmp] vignette=PI/4 [tmp];"
            'detectar bordes
            Case 6: Comandos = Comandos & " [tmp] edgedetect=low=0.1:high=0.4 [tmp];"
            'detectar bordes negativo
            Case 7: Comandos = Comandos & " [tmp] edgedetect=low=0.1:high=0.4,curves=negative [tmp];"
            'desaturar
            Case 8: Comandos = Comandos & " [tmp] hue=s=0.4 [tmp];"
            'saturar
            Case 9: Comandos = Comandos & " [tmp] hue=s=2 [tmp];"
            'brillo
            Case 10: Comandos = Comandos & " [tmp] eq=brightness=0.5 [tmp];"
            'apagar
            Case 11: Comandos = Comandos & " [tmp] eq=brightness=-0.4:saturation=0.3 [tmp];"
            'negativizar
            Case 12: Comandos = Comandos & " [tmp] curves=negative [tmp];"
            '8 bits
            Case 13: Comandos = Comandos & " [tmp] format=pix_fmts=rgb8 [tmp];"
            '8 bits negativo
            Case 14: Comandos = Comandos & " [tmp] format=pix_fmts=rgb8,curves=negative [tmp];"
            'grises
            Case 15: Comandos = Comandos & " [tmp] eq=saturation=0 [tmp];"
            'gris negativo
            Case 16: Comandos = Comandos & " [tmp] eq=saturation=0,curves=negative [tmp];"
            'bitonal
            Case 17: Comandos = Comandos & " [tmp] format=pix_fmts=monob [tmp];"
            'bitonal negativo
            Case 18: Comandos = Comandos & " [tmp] format=pix_fmts=monob,curves=negative [tmp];"
            'sepia
            Case 19: Comandos = Comandos & " [tmp] eq=saturation=0:gamma_r=2:gamma_g=1.5:gamma_b=0.8 [tmp];"
            'blue
            Case 20: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_b=2.0 [tmp];"
            'dark blue
             Case 21: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_b=2.0:brightness=-0.35 [tmp];"
             'sky blue
             Case 22: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_b=2.0:gamma_g=1.6 [tmp];"
            'rojo
             Case 23: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_r=2.0 [tmp];"
            'dark red
             Case 24: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_r=2.0:brightness=-0.35 [tmp];"
            'green
             Case 25: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_g=2.0 [tmp];"
             'dark green:
             Case 26: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_g=2.0:brightness=-0.35 [tmp];"
            'pink
             Case 27: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_r=2.5:gamma_b=1.3:gamma_g=1.2 [tmp];"
            'yellow
             Case 28: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_r=3:gamma_g=3 [tmp];"
             'purple
             Case 29: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_b=2.0:gamma_r=1.5 [tmp];"
            'brown
             Case 30: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_r=2.0:gamma_g=1.2:brightness=-0.3 [tmp];"
             'light brown
             Case 31: Comandos = Comandos & " [tmp] eq=saturation=0.3:gamma_r=2.5:gamma_g=1.2 [tmp];"
        End Select
        EPosX = Replace(Replace(EPosX, "iw", "w"), "ih", "h")
        EPosY = Replace(Replace(EPosY, "iw", "w"), "ih", "h")
        Comandos = Comandos & " [tmp][0:v] overlay=x=" & EPosX & ":y=" & EPosY & Chr(34)
End Select
End With
CmdAgregarBordes = Comandos
End Function

Public Function ReemplazarDimensionesVideo(ByRef Comandos As String, InputFile As String) As Boolean
Dim CmdLinea As String, ConsoleRet As String
Dim StreamSplit() As String, i As Integer, IndexStreamVideo As Integer
Dim Posicion1 As Long, Posicion2 As Long, Ancho As String, Alto As String

ReemplazarDimensionesVideo = False
CmdLinea = Chr(34) & ffprobePath & Chr(34) & " -show_streams -i " & Chr(34) & ScriptObj.Archivo_RutaCorta(InputFile) & Chr(34)
If CaptureConsole.ExecAndCapture(CmdLinea, , , , , , , ConsoleRet) = False Then Exit Function
StreamSplit = Split(ConsoleRet, "[/STREAM]" & vbCrLf)
ConsoleRet = ""
For i = LBound(StreamSplit) To UBound(StreamSplit)
    If InStr(1, StreamSplit(i), "codec_type=video" & vbCrLf) > 0 Then
        IndexStreamVideo = i
        Exit For
    End If
Next

Posicion1 = InStr(1, StreamSplit(IndexStreamVideo), "width=")
If Posicion1 > 0 Then
    Posicion1 = Posicion1 + 6
    Posicion2 = InStr(Posicion1, StreamSplit(IndexStreamVideo), vbCrLf)
    If Posicion2 > 0 Then Ancho = Mid(StreamSplit(IndexStreamVideo), Posicion1, Posicion2 - Posicion1)
End If

Posicion1 = InStr(1, StreamSplit(IndexStreamVideo), "height=")
If Posicion1 > 0 Then
    Posicion1 = Posicion1 + 7
    Posicion2 = InStr(Posicion1, StreamSplit(IndexStreamVideo), vbCrLf)
    If Posicion2 > 0 Then Alto = Mid(StreamSplit(IndexStreamVideo), Posicion1, Posicion2 - Posicion1)
End If
If Ancho = "" Or Alto = "" Then Exit Function
Comandos = Replace(Replace(Comandos, "<AnchoInput>", Ancho), "<AltoInput>", Alto)
ReemplazarDimensionesVideo = True
End Function

Public Function CmdRecortarCuadro(ByRef PerfilEdicion As PerfEdit) As String
Dim Comandos As String, EAncho As String, EAlto As String
Dim EPosX As String, EPosY As String

With PerfilEdicion
    If .RecCua_Ancho <> "" Then
        EAncho = .RecCua_Ancho
        Select Case .RecCua_AnchoU
            Case Is = 0: EAncho = Trim(CStr(Int(CSng(EAncho))))
            Case Is = 1: EAncho = EAncho & "*iw"
            Case Is = 2: EAncho = EAncho & "*ih"
            Case Is = 3: EAncho = EAncho & "*oh"
        End Select
    End If
    If EAncho = "0" Or EAncho = "" Then EAncho = "iw"
    If .RecCua_Alto <> "" Then
        EAlto = .RecCua_Alto
        Select Case .RecCua_AltoU
            Case Is = 0: EAlto = Trim(CStr(Int(CSng(EAlto))))
            Case Is = 1: EAlto = EAlto & "*iw"
            Case Is = 2: EAlto = EAlto & "*ih"
            Case Is = 3: EAlto = EAlto & "*ow"
        End Select
    End If
    If EAlto = "0" Or EAlto = "" Then EAlto = "ih"
    If .RecCua_PosX <> "" Then
        EPosX = .RecCua_PosX
        Select Case .RecCua_PosXU
            Case Is = 0: EPosX = Trim(CStr(Int(CSng(EPosX))))
            Case Is = 1: EPosX = EPosX & "*iw"
            Case Is = 2: EPosX = EPosX & "*ih"
            Case Is = 3: EPosX = EPosX & "*ow"
            Case Is = 4: EPosX = EPosX & "*oh"
        End Select
    End If
    If EPosX = "" Then EPosX = "(iw-ow)/2"
    If .RecCua_PosY <> "" Then
        EPosY = .RecCua_PosY
        Select Case .RecCua_PosYU
            Case Is = 0: EPosY = Trim(CStr(Int(CSng(EPosY))))
            Case Is = 1: EPosY = EPosY & "*iw"
            Case Is = 2: EPosY = EPosY & "*ih"
            Case Is = 3: EPosY = EPosY & "*ow"
            Case Is = 4: EPosY = EPosY & "*oh"
        End Select
    End If
    If EPosY = "" Then EPosY = "(ih-oh)/2"
    If Not (EAlto = "ih" And EAncho = "iw") Then Comandos = ffmpeg.FFmpegParametros.FiltroVideo & " crop=" & EAncho & ":" & EAlto & ":" & EPosX & ":" & EPosY
End With
CmdRecortarCuadro = Comandos
End Function

Public Function CmdRedimensionarCuadro(ByRef PerfilEdicion As PerfEdit) As String
Dim EAncho As String, EAlto As String, Comandos As String, EAspecto As String
With PerfilEdicion
If .CamTam_Ancho <> "" Then
    EAncho = .CamTam_Ancho
    Select Case .CamTam_AnchoU
        Case Is = 0: EAncho = Trim(CStr(Int(CSng(EAncho))))
        Case Is = 1: EAncho = EAncho & "*iw"
        Case Is = 2: EAncho = EAncho & "*ih"
        Case Is = 3: EAncho = EAncho & "*oh"
    End Select
End If
If EAncho = "0" Or EAncho = "" Then EAncho = "iw"
If .CamTam_Alto <> "" Then
    EAlto = .CamTam_Alto
    Select Case .CamTam_AltoU
        Case Is = 0: EAlto = Trim(CStr(Int(CSng(EAlto))))
        Case Is = 1: EAlto = EAlto & "*iw"
        Case Is = 2: EAlto = EAlto & "*ih"
        Case Is = 3: EAlto = EAlto & "*ow"
    End Select
End If
If EAlto = "0" Or EAlto = "" Then EAlto = "ih"
If .CamTam_RelAspOp = 3 And .CamTam_RelAspVal <> "" Then EAspecto = ",setdar=" & .CamTam_RelAspVal
If .CamTam_RelAspOp = 2 Then EAspecto = ",setdar"
If EAlto = "ih" And EAncho = "iw" Then Exit Function
Comandos = ffmpeg.FFmpegParametros.FiltroVideo & " scale=w=" & EAncho & ":h=" & EAlto
If .AlgoritmoReescale > 0 Then
    Comandos = Comandos & ":flags="
    Select Case .AlgoritmoReescale
        Case 1: Comandos = Comandos & "fast_bilinear"
        Case 2: Comandos = Comandos & "bilinear"
        Case 3: Comandos = Comandos & "bicubic"
        Case 4: Comandos = Comandos & "experimental"
        Case 5: Comandos = Comandos & "neighbor"
        Case 6: Comandos = Comandos & "area"
        Case 7: Comandos = Comandos & "bicublin"
        Case 8: Comandos = Comandos & "gauss"
        Case 9: Comandos = Comandos & "sinc"
        Case 10: Comandos = Comandos & "lanczos"
        Case 11: Comandos = Comandos & "spline"
    End Select
End If
End With
Comandos = Comandos & EAspecto
CmdRedimensionarCuadro = Comandos
End Function

Public Function CmdCambiarVolumen(ByRef PerfilEdicion As PerfEdit) As String
Dim Comandos As String
With PerfilEdicion
    If IsNumeric(.CamVol_Val) = False Then Exit Function
    If .CamVol_Val <> "" Or CSng(.CamVol_Val) <> 100 Then Comandos = ffmpeg.FFmpegParametros.Volumen & Trim(CStr(CSng(.CamVol_Val) / 100))
End With
CmdCambiarVolumen = Comandos
End Function

Public Function CmdEcualizar(ByRef PerfilEdicion As PerfEdit) As String
Dim Comandos As String, i As Byte
With PerfilEdicion
    For i = 1 To 10
        If .Equ_Val(2, i) <> "0" And .Equ_Val(2, i) <> "" Then Comandos = Comandos & ",equalizer=f=" & .Equ_Val(1, i) & ":width_type=o:width=" & .Equ_Val(3, i) & ":gain=" & .Equ_Val(2, i)
    Next
    If Comandos <> "" Then Comandos = ffmpeg.FFmpegParametros.FiltroAudio & " " & Right(Comandos, Len(Comandos) - 1)
End With
CmdEcualizar = Comandos
End Function

Public Function CmdGrabarSubtitulos(ByRef PerfilEdicion As PerfEdit) As String
Dim Comandos As String
With PerfilEdicion
    If .GrabarSubtitulos = 0 Then Exit Function
    Comandos = Chr(34) & Replace(Replace(.RutaSubtitulos, "\", "/"), ":/", "\\:/") & Chr(34)
    Comandos = ffmpeg.FFmpegParametros.FiltroVideo & " ass=filename=" & Comandos
    If .UsarIndiceSubtitulos = 1 Then
        Comandos = Comandos & ":si=" & Trim(CStr(.IndiceSubtitulos))
    End If
End With
CmdGrabarSubtitulos = Comandos
End Function

Public Function CmdOverlay(ByRef PerfilEdicion As PerfEdit) As String
Dim Comandos As String, EAncho As String, EAlto As String, EPosX As String, EPosY As String
Dim RGBcolor() As String, Opacidad As Byte
With PerfilEdicion
    If .OverlayPath = "" Then Exit Function 'No hay nada que sobreponer
    
    Comandos = "movie=filename=\'" & Replace(Replace(.OverlayPath, "\", "/"), ":", "\:") & "\'"
    
    Opacidad = (100 - .OverlayOpacidadPor) / 100 * 255
    If .OverlayTrans = 1 Then
        
        Comandos = Comandos & ",format=rgba,geq=r='r(X,Y)':a='if(eq(r(X,Y)," & Trim(CStr(.OverlayTransColorR)) & _
        ")*eq(g(X,Y)," & Trim(CStr(.OverlayTransColorG)) & _
        ")*eq(b(X,Y)," & Trim(CStr(.OverlayTransColorB)) & "),0," & Trim(CStr(Opacidad)) & ")'"
    Else
        If Opacidad < 255 Then Comandos = Comandos & ",format=rgba,geq=r='r(X,Y)':a='" & Trim(CStr(Opacidad)) & "'"
    End If
    
    If .OVerlayRedim = 1 Then
        If .OverlayRedimAncho <> "" And .OverlayRedimAncho <> "0" Then
            EAncho = .OverlayRedimAncho
            Select Case .OverlayRedimAnchoUnit
                Case 1: EAncho = EAncho & "*<AnchoInput>"
                Case 2: EAncho = EAncho & "*<AltoInput>"
                Case 3: EAncho = EAncho & "*iw"
                Case 4: EAncho = EAncho & "*ih"
            End Select
        Else
            EAncho = "iw"
        End If
        If .OverlayRedimAlto <> "" And .OverlayRedimAlto <> "0" Then
            EAlto = .OverlayRedimAlto
            Select Case .OverlayRedimAltoUnit
                Case 1: EAlto = EAlto & "*<AnchoInput>"
                Case 2: EAlto = EAlto & "*<AltoInput>"
                Case 3: EAlto = EAlto & "*iw"
                Case 4: EAlto = EAlto & "*ih"
            End Select
        Else
            EAlto = "ih"
        End If
        Comandos = Comandos & ",scale=w=" & EAncho & ":h=" & EAlto & ",setdar"
    End If
    
    Comandos = Comandos & " [over];"
    
    If .OverlayPos = 0 Or .OverlayPos = 3 Or .OverlayPos = 6 Then
        If .OverlayMargenIzq <> "" And .OverlayMargenIzq <> "0" Then
            EPosX = .OverlayMargenIzq
            Select Case .OverlayMargenIzqUnit
                Case 1: EPosX = EPosX & "*W"
                Case 2: EPosX = EPosX & "*H"
                Case 3: EPosX = EPosX & "*w"
                Case 4: EPosX = EPosX & "*h"
            End Select
        Else
            EPosX = "0"
        End If
    End If
    If .OverlayPos = 1 Or .OverlayPos = 4 Or .OverlayPos = 7 Then EPosX = "0.5*(W-w)"
    If .OverlayPos = 2 Or .OverlayPos = 5 Or .OverlayPos = 8 Then
        If .OverlayMargenDer <> "" And .OverlayMargenDer <> "0" Then
            EPosX = "W-w-" & .OverlayMargenDer
            Select Case .OverlayMargenDerUnit
                Case 1: EPosX = EPosX & "*W"
                Case 2: EPosX = EPosX & "*H"
                Case 3: EPosX = EPosX & "*w"
                Case 4: EPosX = EPosX & "*h"
            End Select
        Else
            EPosX = "W-w"
        End If
    End If
    
    If .OverlayPos = 0 Or .OverlayPos = 1 Or .OverlayPos = 2 Then
        If .OverlayMargenSup <> "" And .OverlayMargenSup <> "0" Then
            EPosY = .OverlayMargenSup
            Select Case .OverlayMargenSupUnit
                Case 1: EPosY = EPosY & "*W"
                Case 2: EPosY = EPosY & "*H"
                Case 3: EPosY = EPosY & "*w"
                Case 4: EPosY = EPosY & "*h"
            End Select
        Else
            EPosY = "0"
        End If
    End If
    If .OverlayPos = 3 Or .OverlayPos = 4 Or .OverlayPos = 5 Then EPosY = "0.5*(H-h)"
    If .OverlayPos = 6 Or .OverlayPos = 7 Or .OverlayPos = 8 Then
        If .OverlayMargenInf <> "" And .OverlayMargenInf <> "0" Then
            EPosY = "H-h-" & .OverlayMargenInf
            Select Case .OverlayMargenInfUnit
                Case 1: EPosY = EPosY & "*W"
                Case 2: EPosY = EPosY & "*H"
                Case 3: EPosY = EPosY & "*w"
                Case 4: EPosY = EPosY & "*h"
            End Select
        Else
            EPosY = "H-h"
        End If
    End If
    
    Comandos = ffmpeg.FFmpegParametros.Filtro & " " & Chr(34) & Comandos & " [0:v][over] overlay=x=" & EPosX & ":y=" & EPosY & Chr(34)
End With
CmdOverlay = Comandos
End Function

Private Function GenerarComandosMapeado(Indice As Integer) As String
Dim i As Integer, Ret As String, j As Long, n As Integer
Dim k As Integer
Select Case Form1.Combo1.ListIndex
    Case Is = 0
        Exit Function
    Case Is = 1
        n = Aplicacion.InFilesCount
        i = 1
    Case Else
        n = Indice + 1
        i = n
End Select
While i <= n
    If Aplicacion.InFilesMap(i) <> "" Then
        j = InStr(1, Aplicacion.InFilesMap(i), Chr(0))
        If j > 0 Then Ret = Ret & " " & Replace(Mid(Aplicacion.InFilesMap(i), j + 1, Len(Aplicacion.InFilesMap(i)) - j), "#", Trim(CStr(k)))
    End If
    k = k + 1
    i = i + 1
Wend
If Ret <> "" Then GenerarComandosMapeado = Ret & " "
End Function

Private Function VerificarMapeados() As Boolean
Dim i As Integer, HayMapeados As Byte
If Form1.Combo1.ListIndex = 0 Then
    For i = 1 To Aplicacion.InFilesCount
        If Aplicacion.InFilesMap(i) <> "" Then
            HayMapeados = 1
            Exit For
        End If
    Next
    If HayMapeados = 1 Then
        If Lang.Msg_MapeadoNoDisponibleConConcat = vbYes Then VerificarMapeados = True
    Else
        VerificarMapeados = True
    End If
Else
    VerificarMapeados = True
End If
End Function

Private Sub DetenerEjecutableExterno(RutaProceso As String)
'Procedimiento usado para detener la conversión cuando se utiliza codec externo con pipe
Dim ListProcesos() As Long
Dim NumProcesos As Integer, i As Integer
Dim ProcesoPadre As Long
If CaptureConsole.IDProcesoPrincipal = 0 Then Exit Sub 'IDProcesoPrincipal es el ID de la instancia de cmd.exe iniciada por el modulo CaptureConsole
'Busca todos los procesos asociados a la ruta del ejecutable externo
NumProcesos = APIS.BuscarProcesosAsociadosARuta(ByVal RutaProceso, ListProcesos)
For i = 1 To NumProcesos
    'Determina el ID del proceso que inició la ejecución de la instancia del binario externo
    ProcesoPadre = APIS.GetParentProcessID(ListProcesos(i))
    'Si el proceso que inició la ejecución del binario externo es la instancia
    'de cmd.exe entonces finaliza la ejecución de dicho binario
    'Esto rompe la canalizacion o el pipe y finalizan tanto cmd.exe como ffmpeg.exe
    If ProcesoPadre = CaptureConsole.IDProcesoPrincipal Then
        Call APIS.MatarProcesoPorID(ListProcesos(i))
        Exit For
    End If
Next
End Sub

Public Sub DetenerConversion_Force()
Dim RutaProceso As String
If Form12.Text4.Text = Lang.Convert_Str_CodificandoAudio And UsePipeAudio = 1 Then
    RutaProceso = Mid(BatchCmd(2, 1), 2, Len(BatchCmd(2, 1)) - 2)
Else
    If Form12.Text4.Text = Lang.Convert_Str_CodificandoVideo And UsePipeVideo = 1 Then RutaProceso = Mid(BatchCmd(5, 1), 2, Len(BatchCmd(5, 1)) - 2)
End If
If RutaProceso <> "" Then Call DetenerEjecutableExterno(RutaProceso) Else Call CaptureConsole.StopProcess
Convertidor.DetenerConversion = 1
End Sub
