VB中的异步无法按预期工作

时间:2017-11-05 02:39:54

标签: vb.net asynchronous progress-bar

更新 看起来罪魁祸首是状态报告

ffStatus = procFFMPEG.StandardError         'Send standard error to ffStatus
strFFout = ffStatus.ReadLine                'Read every line of output and send to strFFout

它看起来像打破了那部分的异步。注释掉时,选取框滚动条的行为与预期一致。

有没有办法在不破坏异步显示选框进度条的情况下获取这些数据并更新状态?

原始帖子

我对这个问题有类似的问题 VB.NET Marquee Progress Until Process Exits

我使用接受的答案并获取此代码

Public Async Sub GoConvert(theVCodec As String, theHeight As String)
    Dim theOptions As String, theApp As String, theSourcePath As String, theDestPath As String
    Dim theFilename As String, theACodec As String, theFormat As String, theLosslessOpt As String
    Dim theNewFilename As String, theNewFileTag As String, theInterlaced As String, theMsg As String
    Dim thePreset As String, theCRF As String

    Dim ffStatus As StreamReader, strFFout As String

    'On Error GoTo Handler
    'SET DEFAULT VALUES

    theApp = "ffmpeg.exe"
    theSourcePath = txtSource.Text
    theDestPath = txtOutput.Text & "\"
    theACodec = "libmp3lame"
    thePreset = "veryfast"
    theCRF = "22"

    theInterlaced = ""
    theNewFileTag = ""
    theLosslessOpt = ""

    Select Case theVCodec
        Case "libx264"
            theNewFileTag = "x264"
        Case "libxvid"
            theNewFileTag = "xvid"
        Case "libx265"
            theNewFileTag = "x265"
    End Select

    If cmbUseCodec.Text = "x264 vegas" Then
        theACodec = "aac"
        theNewFileTag = "x264forVegas"
    End If

    theMsg = "IF FILE EXISTS, IT WILL BE OVERWRITTEN!" & vbCrLf & vbCrLf & "Please make sure that there is no filename conflict in the destination folder," & vbCrLf & "Encoder will overwrite existing files." _
        & vbCrLf & vbCrLf & "Do you want to continue?"

    If MessageBox.Show(theMsg, "WARNING!", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) = DialogResult.Yes Then

        For i As Integer = 0 To lstSourceFiles.Items.Count - 1

            If chkToFileType.CheckedItems.Count <> 0 Then
                Dim x As Integer
                Dim forVegas As String

                For x = 0 To chkToFileType.CheckedItems.Count - 1

                    theFormat = chkToFileType.CheckedItems(x).ToString

                    'GET FILENAMES ON FILES LISTBOX
                    theFilename = lstSourceFiles.Items(i).ToString
                    theNewFilename = System.IO.Path.GetFileNameWithoutExtension(theFilename)

                    If chkSameOutputFolder.CheckedItems.Count > 0 Then
                        theDestPath = Path.GetDirectoryName(theFilename) & "\"
                    End If

                    If (theVCodec = "libx265") Then
                        theCRF = "28"
                        thePreset = "medium"
                    End If
                    If (chkLossLess.CheckedItems.Count > 0) And (theVCodec = "libx265") Then
                        theLosslessOpt = "-x265-params lossless=1 "
                    End If


                    If theFormat = "mp3" Then
                        '-i "%%a" -qa 0 - map a "%%~na.mp3"
                        theOptions = " -i " & Chr(34) & theFilename & Chr(34) & " -y -q:a 0 -map a " & Chr(34) & theDestPath & theNewFilename & "." & theFormat & Chr(34)
                    Else
                        'PREPARE NEW FILENAME OF CONVERTED FILE
                        theNewFilename = theNewFilename & "-" & theNewFileTag & "-" & theHeight & "p"

                        theOptions = " -i " & Chr(34) & theFilename & Chr(34) & " -y -vcodec " & theVCodec
                        theOptions = theOptions & " -vf " & theInterlaced & "scale=" & Chr(34) & "trunc(oh*a/2)*2:" & theHeight & Chr(34)

                        If cmbUseCodec.Text = "x264 vegas" Then
                            forVegas = " -strict experimental -tune fastdecode -pix_fmt yuv420p -b:a 192k -ar 48000"
                            theOptions = theOptions & " -preset " & thePreset & " -crf " & theCRF & " -acodec " & theACodec & forVegas
                            theOptions = theOptions & " -threads 4 " & theLosslessOpt & Chr(34) & theDestPath & theNewFilename & "." & theFormat & Chr(34)
                        Else
                            theOptions = theOptions & " -b 1750k -preset " & thePreset & " -crf " & theCRF & " -acodec " & theACodec
                            theOptions = theOptions & " -ac 2 -ab 160k -threads 4 " & theLosslessOpt & Chr(34) & theDestPath & theNewFilename & "." & theFormat & Chr(34)
                        End If
                    End If
                    theOptions = theOptions & " -loglevel error -stats"


                    'LET'S GET READY TO CONVERT
                    ConvertProcessInfo.FileName = theApp
                    ConvertProcessInfo.Arguments = theOptions

                    'LET'S TRY TO CAPTURE STATUS
                    ConvertProcessInfo.RedirectStandardError = True
                    ConvertProcessInfo.RedirectStandardOutput = True
                    ConvertProcessInfo.UseShellExecute = False
                    ConvertProcessInfo.CreateNoWindow = True

                    'LET'S PROVIDE SOME MEANINGFUL INFO
                    procFFMPEG.StartInfo = ConvertProcessInfo
                    lstStatus.Items(i) = "Encoding: " & theFormat
                    txtProcessInfo.Text = "Encoding file: " & theNewFilename & "." & theFormat

                    'LET'S DISABLE CONTROLS WHILE CONVERT IS WORKING AND ENABLE PROGRESSBAR
                    prgrssConvert.Visible = True
                    DisableControls()

                    'LET'S CONVERT
                    procFFMPEG.Start()

                    Do
                        Application.DoEvents()
                        ffStatus = procFFMPEG.StandardError         'Send standard error to ffStatus
                        strFFout = ffStatus.ReadLine                'Read every line of output and send to strFFout
                        Debug.Print(strFFout)
                        txtProcessInfo.Text = strFFout

                        'THESE LINES IS NOT NEEDED IF ASYNC WILL WORK
                        txtProcessInfo.Refresh()
                        lstSourceFiles.Refresh()
                        lstStatus.Refresh()
                        prgrssConvert.Refresh()

                    Loop Until procFFMPEG.HasExited

                    'LET'S WAIT FOR PROCESS TO EXIT
                    Await Task.Run(Sub() procFFMPEG.WaitForExit())

                    'UPDATE STATUS AFTER EVERY FILE
                    prgrssConvert.Visible = False
                    lstStatus.Items(i) = "DONE"
                Next
            End If
        Next
        'WHEN ALL FILES DONE, UPDATE STATUS
        txtProcessInfo.Text = "Encoding completed. Waiting for new task"
        EnableControls()
    End If

End Sub

我的问题是进度条(prgrssConvert.Visible = True)没有异步更新,这就是为什么我必须在DO LOOP中添加刷新但它不具有视觉吸引力,因为它是& #34;机器人&#34;而不是流畅的流动。

在我看来,异步并没有做到这一点。我希望在等待ffmpeg进程完成时保持进度条选框运行。

知道为什么异步不能处理我的代码吗?

谢谢

2 个答案:

答案 0 :(得分:1)

有一个好问题的完美答案。我没有看到你将输出返回到文本框。抱歉。您必须使用readlineasync,否则您正在等待输出中可能仅在结尾处出现的行。如果它永远不会出现,你的应用程序将被卡在那里。

这是用于读取错误procFFMPEG.StandardError 如果您确实希望流程的输出使用此功能 相反或两者都是procMMFPEG.StandardOutput,但您需要调整代码

some reference for StandardOutput

Public Async Sub GoConvert(theVCodec As String, theHeight As String)
    Dim theOptions As String, theApp As String, theSourcePath As String, theDestPath As String
    Dim theFilename As String, theACodec As String, theFormat As String, theLosslessOpt As String
    Dim theNewFilename As String, theNewFileTag As String, theInterlaced As String, theMsg As String
    Dim thePreset As String, theCRF As String

    Dim ffStatus As StreamReader, strFFout As String

    'On Error GoTo Handler
    'SET DEFAULT VALUES

    theApp = "ffmpeg.exe"
    theSourcePath = txtSource.Text
    theDestPath = txtOutput.Text & "\"
    theACodec = "libmp3lame"
    thePreset = "veryfast"
    theCRF = "22"

    theInterlaced = ""
    theNewFileTag = ""
    theLosslessOpt = ""

    Select Case theVCodec
        Case "libx264"
            theNewFileTag = "x264"
        Case "libxvid"
            theNewFileTag = "xvid"
        Case "libx265"
            theNewFileTag = "x265"
    End Select

    If cmbUseCodec.Text = "x264 vegas" Then
        theACodec = "aac"
        theNewFileTag = "x264forVegas"
    End If

    theMsg = "IF FILE EXISTS, IT WILL BE OVERWRITTEN!" & vbCrLf & vbCrLf & "Please make sure that there is no filename conflict in the destination folder," & vbCrLf & "Encoder will overwrite existing files." _
    & vbCrLf & vbCrLf & "Do you want to continue?"

    If MessageBox.Show(theMsg, "WARNING!", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) = DialogResult.Yes Then
        'LET'S DISABLE CONTROLS WHILE CONVERT IS WORKING AND ENABLE PROGRESSBAR
        prgrssConvert.Visible = True
        DisableControls()
        prgrssConvert.value = 0 'I assumed this was a progressbar
        prgrssConvert.maximum = lstSourceFiles.Items.Count * chkToFileType.CheckedItems.Count

        For i As Integer = 0 To lstSourceFiles.Items.Count - 1

            If chkToFileType.CheckedItems.Count <> 0 Then
                Dim x As Integer
                Dim forVegas As String

                For x = 0 To chkToFileType.CheckedItems.Count - 1

                    theFormat = chkToFileType.CheckedItems(x).ToString

                    'GET FILENAMES ON FILES LISTBOX
                    theFilename = lstSourceFiles.Items(i).ToString
                    theNewFilename = System.IO.Path.GetFileNameWithoutExtension(theFilename)

                    If chkSameOutputFolder.CheckedItems.Count > 0 Then
                        theDestPath = Path.GetDirectoryName(theFilename) & "\"
                    End If

                    If (theVCodec = "libx265") Then
                        theCRF = "28"
                        thePreset = "medium"
                    End If
                    If (chkLossLess.CheckedItems.Count > 0) And (theVCodec = "libx265") Then
                        theLosslessOpt = "-x265-params lossless=1 "
                    End If


                    If theFormat = "mp3" Then
                        '-i "%%a" -qa 0 - map a "%%~na.mp3"
                        theOptions = " -i " & Chr(34) & theFilename & Chr(34) & " -y -q:a 0 -map a " & Chr(34) & theDestPath & theNewFilename & "." & theFormat & Chr(34)
                    Else
                        'PREPARE NEW FILENAME OF CONVERTED FILE
                        theNewFilename = theNewFilename & "-" & theNewFileTag & "-" & theHeight & "p"

                        theOptions = " -i " & Chr(34) & theFilename & Chr(34) & " -y -vcodec " & theVCodec
                        theOptions = theOptions & " -vf " & theInterlaced & "scale=" & Chr(34) & "trunc(oh*a/2)*2:" & theHeight & Chr(34)

                        If cmbUseCodec.Text = "x264 vegas" Then
                            forVegas = " -strict experimental -tune fastdecode -pix_fmt yuv420p -b:a 192k -ar 48000"
                            theOptions = theOptions & " -preset " & thePreset & " -crf " & theCRF & " -acodec " & theACodec & forVegas
                            theOptions = theOptions & " -threads 4 " & theLosslessOpt & Chr(34) & theDestPath & theNewFilename & "." & theFormat & Chr(34)
                        Else
                            theOptions = theOptions & " -b 1750k -preset " & thePreset & " -crf " & theCRF & " -acodec " & theACodec
                            theOptions = theOptions & " -ac 2 -ab 160k -threads 4 " & theLosslessOpt & Chr(34) & theDestPath & theNewFilename & "." & theFormat & Chr(34)
                        End If
                    End If
                    theOptions = theOptions & " -loglevel error -stats"


                    'LET'S GET READY TO CONVERT
                    ConvertProcessInfo.FileName = theApp
                    ConvertProcessInfo.Arguments = theOptions

                    'LET'S TRY TO CAPTURE STATUS
                    ConvertProcessInfo.RedirectStandardError = True
                    ConvertProcessInfo.RedirectStandardOutput = True
                    ConvertProcessInfo.UseShellExecute = False
                    ConvertProcessInfo.CreateNoWindow = True

                    'LET'S PROVIDE SOME MEANINGFUL INFO
                    procFFMPEG.StartInfo = ConvertProcessInfo
                    lstStatus.Items(i) = "Encoding: " & theFormat
                    txtProcessInfo.Text = "Encoding file: " & theNewFilename & "." & theFormat


                    'LET'S CONVERT
                    procFFMPEG.Start()
                    Do
                        ffStatus = procFFMPEG.StandardError         'Send standard error to ffStatus
                        strFFout = Await(ffStatus.ReadLineAsync())               'Read every line of output and send to strFFout
                        Debug.Print(strFFout)
                        txtProcessInfo.Text = strFFout
                    Loop Until procFFMPEG.HasExited = True



                    'UPDATE STATUS AFTER EVERY FILE
                    prgrssConvert.value += 1
                Next
                lstStatus.Items(i) = "DONE"
            End If
        Next
        prgrssConvert.Visible = False

        'WHEN ALL FILES DONE, UPDATE STATUS
        txtProcessInfo.Text = "Encoding completed. Waiting for new task"
        EnableControls()
    End If

End Sub

答案 1 :(得分:-1)

这是未经测试的,但您可以试试这个:

                Do
                    Await Task.Delay(TimeSpan.FromSeconds(0.1))
                    ffStatus = procFFMPEG.StandardError         'Send standard error to ffStatus
                    strFFout = ffStatus.ReadLine                'Read every line of output and send to strFFout
                    Debug.Print(strFFout)
                    txtProcessInfo.Text = strFFout

                Loop Until Await Task.Run(Function() procFFMPEG.HasExited)

这是一个简单的代码来测试它的工作原理:

Dim process As New Process()

process.StartInfo = New ProcessStartInfo("C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe")
process.Start()

Do
    Await Task.Delay(TimeSpan.FromSeconds(0.1))
    Console.WriteLine("!")
Loop Until Await Task.Run(Function() process.HasExited)

在PowerShell控制台关闭之前,它会生成!行。