【发布时间】:2017-11-05 02:39:54
【问题描述】:
更新: 看起来罪魁祸首是状态报告
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 中添加刷新,但它在视觉上并不吸引人,因为它是“机器人”而不是流畅的选取框。
在我看来,异步并没有发挥作用。我希望在等待 ffmpeg 进程完成时保持进度条选取框运行。
知道为什么异步无法处理我的代码吗?
谢谢
【问题讨论】:
-
不要不要使用
Application.DoEvents()。它可能会导致代码出现各种问题,并且很难调试。在循环中使用它只会使问题更加复杂。你需要使用计时器来获得你想要的结果。 -
嗨@Enigmativity,你能详细说明一下计时器吗? Application.DoEvents() 是出于沮丧而使用的 :) 删除它不会改变任何事情。
-
StandardError.ReadLine() 是一个阻塞调用。如果你做对了,这可能需要很长时间,希望这个过程不会产生很多错误消息。这会挂起您的 UI 线程并停止更新进度条。使用 BeginReadLine() 或将此代码移动到工作线程中。并修复另一个错误,您没有阅读 StandardOutput。这可能会导致程序永远挂起。
-
您的问题是您正在尝试获取编码进度,但您需要一个函数来返回异步调用的进度。
-
如果您想要一个没有异步功能的进度条来更新您的进度条,那么请使用进度条在您的文件列表上显示进度以进行编码。
标签: vb.net asynchronous progress-bar