更新 看起来罪魁祸首是状态报告
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进程完成时保持进度条选框运行。
知道为什么异步不能处理我的代码吗?
谢谢
答案 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控制台关闭之前,它会生成!
行。