mirror of
https://github.com/staxrip/staxrip.git
synced 2026-10-27 20:54:42 +08:00
1704 lines
54 KiB
VB.net
1704 lines
54 KiB
VB.net
|
|
Imports System.Text.RegularExpressions
|
|
Imports System.Text
|
|
|
|
Imports StaxRip.UI
|
|
|
|
<Serializable()>
|
|
Public MustInherit Class AudioProfile
|
|
Inherits Profile
|
|
|
|
Property Language As New Language
|
|
Property Delay As Integer
|
|
Property Depth As Integer = 24
|
|
Property StreamName As String = ""
|
|
Property Gain As Single
|
|
Property Streams As List(Of AudioStream) = New List(Of AudioStream)
|
|
Property [Default] As Boolean
|
|
Property Forced As Boolean
|
|
Property Commentary As Boolean
|
|
Property ExtractDTSCore As Boolean
|
|
Property Decoder As AudioDecoderMode
|
|
Property DecodingMode As AudioDecodingMode
|
|
|
|
Overridable Property Channels As Integer = 6
|
|
Overridable Property OutputFileType As String = "unknown"
|
|
Overridable Property Bitrate As Double
|
|
Overridable Property SupportedInput As String()
|
|
|
|
Overridable Property CommandLines As String
|
|
|
|
Sub New(name As String)
|
|
MyBase.New(name)
|
|
End Sub
|
|
|
|
Sub New(name As String,
|
|
bitrate As Integer,
|
|
input As String(),
|
|
fileType As String,
|
|
channels As Integer)
|
|
|
|
MyBase.New(name)
|
|
|
|
Me.Channels = channels
|
|
Me.Bitrate = bitrate
|
|
SupportedInput = input
|
|
OutputFileType = fileType
|
|
End Sub
|
|
|
|
ReadOnly Property AudioCodec As AudioCodec
|
|
Get
|
|
If TypeOf Me Is GUIAudioProfile Then
|
|
Return DirectCast(Me, GUIAudioProfile).Params.Codec
|
|
End If
|
|
|
|
For Each i As AudioCodec In System.Enum.GetValues(GetType(AudioCodec))
|
|
If i.ToString.ToLowerInvariant = OutputFileType Then
|
|
Return i
|
|
End If
|
|
Next
|
|
|
|
Return AudioCodec.None
|
|
End Get
|
|
End Property
|
|
|
|
Private FileValue As String = ""
|
|
|
|
Property File As String
|
|
Get
|
|
Return FileValue
|
|
End Get
|
|
Set(value As String)
|
|
If FileValue <> value Then
|
|
FileValue = value
|
|
Stream = Nothing
|
|
OnFileChanged()
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
Private StreamValue As AudioStream
|
|
|
|
Property Stream As AudioStream
|
|
Get
|
|
Return StreamValue
|
|
End Get
|
|
Set(value As AudioStream)
|
|
If Not value Is StreamValue Then
|
|
StreamValue = value
|
|
|
|
If Not Stream Is Nothing Then
|
|
If Not p.Script.GetFilter("Source").Script.Contains("DirectShowSource") Then
|
|
Delay = Stream.Delay
|
|
End If
|
|
|
|
Language = Stream.Language
|
|
Forced = Stream.Forced
|
|
Me.Default = Stream.Default
|
|
Commentary = Stream.Commentary
|
|
|
|
If StreamName = "" AndAlso Stream.Title <> "" Then
|
|
StreamName = Stream.Title
|
|
End If
|
|
End If
|
|
|
|
OnStreamChanged()
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
Property DisplayName As String
|
|
Get
|
|
Dim ret As String
|
|
|
|
If Stream Is Nothing Then
|
|
Dim streams = MediaInfo.GetAudioStreams(File)
|
|
|
|
If streams.Count > 0 Then
|
|
Dim firstStream = streams(0)
|
|
|
|
If firstStream.Bitrate = 0 AndAlso firstStream.Bitrate2 = 0 Then
|
|
firstStream.Bitrate = CInt(Calc.GetBitrateFromFile(File, p.SourceSeconds))
|
|
End If
|
|
|
|
ret = GetAudioText(firstStream, File)
|
|
Else
|
|
ret = File.FileName
|
|
End If
|
|
Else
|
|
ret = Stream.Name + " (" + File.Ext + ")"
|
|
End If
|
|
|
|
Return ret
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Private SourceSamplingRateValue As Integer
|
|
|
|
ReadOnly Property SourceSamplingRate As Integer
|
|
Get
|
|
If SourceSamplingRateValue = 0 Then
|
|
If Stream Is Nothing Then
|
|
If File <> "" AndAlso IO.File.Exists(File) Then
|
|
SourceSamplingRateValue = MediaInfo.GetAudio(File, "SamplingRate").ToInt
|
|
End If
|
|
Else
|
|
SourceSamplingRateValue = Stream.SamplingRate
|
|
End If
|
|
End If
|
|
|
|
If SourceSamplingRateValue = 0 Then
|
|
SourceSamplingRateValue = 48000
|
|
End If
|
|
|
|
Return SourceSamplingRateValue
|
|
End Get
|
|
End Property
|
|
|
|
ReadOnly Property HasStream As Boolean
|
|
Get
|
|
Return Stream IsNot Nothing
|
|
End Get
|
|
End Property
|
|
|
|
Overridable Sub Migrate()
|
|
If Depth = 0 Then
|
|
Depth = 24
|
|
End If
|
|
End Sub
|
|
|
|
ReadOnly Property ConvertExt As String
|
|
Get
|
|
Dim ret As String
|
|
|
|
Select Case DecodingMode
|
|
Case AudioDecodingMode.WAVE
|
|
ret = "wav"
|
|
Case AudioDecodingMode.W64
|
|
ret = "w64"
|
|
Case Else
|
|
ret = "flac"
|
|
End Select
|
|
|
|
If Not SupportedInput.Contains(ret) Then
|
|
ret = "flac"
|
|
End If
|
|
|
|
If Not SupportedInput.Contains(ret) Then
|
|
ret = "w64"
|
|
End If
|
|
|
|
If Not SupportedInput.Contains(ret) Then
|
|
ret = "wav"
|
|
End If
|
|
|
|
Return ret
|
|
End Get
|
|
End Property
|
|
|
|
Overridable Sub OnFileChanged()
|
|
End Sub
|
|
|
|
Overridable Sub OnStreamChanged()
|
|
End Sub
|
|
|
|
Function ContainsCommand(value As String) As Boolean
|
|
Return CommandLines.ContainsEx(value)
|
|
End Function
|
|
|
|
Function IsUsedAndContainsCommand(value As String) As Boolean
|
|
Return File <> "" AndAlso CommandLines.ContainsEx(value)
|
|
End Function
|
|
|
|
Function GetDuration() As TimeSpan
|
|
If IO.File.Exists(File) Then
|
|
If Stream Is Nothing Then
|
|
Return TimeSpan.FromMilliseconds(MediaInfo.GetAudio(File, "Duration").ToDouble)
|
|
Else
|
|
Using mi As New MediaInfo(File)
|
|
Return TimeSpan.FromMilliseconds(mi.GetAudio(Stream.Index, "Duration").ToDouble)
|
|
End Using
|
|
End If
|
|
End If
|
|
End Function
|
|
|
|
Function GetAudioText(stream As AudioStream, path As String) As String
|
|
For Each i In Language.Languages
|
|
If path.Contains(i.CultureInfo.EnglishName) Then
|
|
stream.Language = i
|
|
Exit For
|
|
End If
|
|
Next
|
|
|
|
Dim matchDelay = Regex.Match(path, " (-?\d+)ms")
|
|
|
|
If matchDelay.Success Then
|
|
stream.Delay = matchDelay.Groups(1).Value.ToInt
|
|
End If
|
|
|
|
Dim matchID = Regex.Match(path, " ID(\d+)")
|
|
Dim name As String
|
|
name = stream.Name.Substring(3)
|
|
|
|
If File.Base = p.SourceFile.Base Then
|
|
Return name + " (" + File.Ext + ")"
|
|
Else
|
|
Return name + " (" + File.FileName + ")"
|
|
End If
|
|
End Function
|
|
|
|
Sub SetStreamOrLanguage()
|
|
If File = "" Then
|
|
Exit Sub
|
|
End If
|
|
|
|
If File <> p.LastOriginalSourceFile Then
|
|
For Each i In Language.Languages
|
|
If File.Contains(i.CultureInfo.EnglishName) Then
|
|
Language = i
|
|
Exit Sub
|
|
End If
|
|
Next
|
|
Else
|
|
For Each i In Streams
|
|
If FileTypes.AudioHQ.Contains(i.Ext) AndAlso i.Language.Equals(Language) Then
|
|
Stream = i
|
|
Exit For
|
|
End If
|
|
Next
|
|
|
|
If Stream Is Nothing Then
|
|
For Each i In Streams
|
|
If Not FileTypes.AudioHQ.Contains(i.Ext) AndAlso i.Language.Equals(Language) Then
|
|
Stream = i
|
|
Exit For
|
|
End If
|
|
Next
|
|
End If
|
|
|
|
If Stream Is Nothing AndAlso Streams.Count > 0 Then
|
|
Stream = Streams(0)
|
|
End If
|
|
End If
|
|
End Sub
|
|
|
|
Function IsInputSupported() As Boolean
|
|
Return SupportedInput.NothingOrEmpty OrElse SupportedInput.Contains(File.Ext)
|
|
End Function
|
|
|
|
Function IsMuxProfile() As Boolean
|
|
Return TypeOf Me Is MuxAudioProfile
|
|
End Function
|
|
|
|
Overridable Sub Encode()
|
|
End Sub
|
|
|
|
Overridable Sub EditProject()
|
|
End Sub
|
|
|
|
Overridable Function HandlesDelay() As Boolean
|
|
End Function
|
|
|
|
Function GetTrackIndex() As Integer
|
|
If Me Is p.Audio0 Then Return 0
|
|
If Me Is p.Audio1 Then Return 1
|
|
|
|
For x = 0 To p.AudioTracks.Count - 1
|
|
If Me Is p.AudioTracks(x) Then
|
|
Return x + 2
|
|
End If
|
|
Next
|
|
End Function
|
|
|
|
Function GetTrackID() As String
|
|
Return "_" & (CRC32.GetChecksum(p.TargetFile) + GetTrackIndex())
|
|
End Function
|
|
|
|
Function GetOutputFile() As String
|
|
Dim base As String
|
|
|
|
If HasStream Then
|
|
base = Audio.GetBaseNameForStream(File, Stream)
|
|
ElseIf p.TempDir.EndsWithEx("_temp\") AndAlso File.Base.StartsWithEx(p.SourceFile.Base) Then
|
|
base = File.Base.Substring(p.SourceFile.Base.Length).Trim
|
|
Else
|
|
base = File.Base
|
|
End If
|
|
|
|
If base = "" Then
|
|
base = "temp"
|
|
End If
|
|
|
|
If Not base.Contains(GetTrackID) Then
|
|
base += GetTrackID()
|
|
End If
|
|
|
|
If Delay <> 0 Then
|
|
If HandlesDelay() Then
|
|
If base.Contains("ms") Then
|
|
Dim re As New Regex(" (-?\d+)ms")
|
|
|
|
If re.IsMatch(base) Then
|
|
base = re.Replace(base, "")
|
|
End If
|
|
End If
|
|
Else
|
|
If Not base.Contains("ms") Then
|
|
base += " " & Delay & "ms"
|
|
End If
|
|
End If
|
|
End If
|
|
|
|
Dim outfile = p.TempDir + base + "." + OutputFileType.ToLowerInvariant
|
|
|
|
If File = outfile Then
|
|
outfile = outfile.Base + "_new." + OutputFileType.ToLowerInvariant
|
|
End If
|
|
|
|
Return outfile
|
|
End Function
|
|
|
|
Shared Function GetProfiles() As IEnumerable(Of AudioProfile)
|
|
If p.AudioTracks.Count = 0 Then
|
|
Return {p.Audio0, p.Audio1}
|
|
Else
|
|
Dim ret As New List(Of AudioProfile)
|
|
ret.Add(p.Audio0)
|
|
ret.Add(p.Audio1)
|
|
ret.AddRange(p.AudioTracks)
|
|
Return ret
|
|
End If
|
|
End Function
|
|
|
|
Function ExpandMacros(value As String) As String
|
|
Return ExpandMacros(value, True)
|
|
End Function
|
|
|
|
Function ExpandMacros(value As String, silent As Boolean) As String
|
|
If value = "" Then Return ""
|
|
If value.Contains("%input%") Then value = value.Replace("%input%", File.Escape)
|
|
If value.Contains("%output%") Then value = value.Replace("%output%", GetOutputFile.Escape)
|
|
If value.Contains("%bitrate%") Then value = value.Replace("%bitrate%", Bitrate.ToString)
|
|
If value.Contains("%channels%") Then value = value.Replace("%channels%", Channels.ToString)
|
|
If value.Contains("%language_native%") Then value = value.Replace("%language_native%", Language.CultureInfo.NativeName)
|
|
If value.Contains("%language_english%") Then value = value.Replace("%language_english%", Language.Name)
|
|
If value.Contains("%delay%") Then value = value.Replace("%delay%", Delay.ToString)
|
|
If value.Contains("%streamid0%") AndAlso Stream IsNot Nothing Then value = value.Replace("%streamid0%", (Stream?.ID - 1)?.ToString)
|
|
If value.Contains("%streamid1%") Then value = value.Replace("%streamid1%", Stream?.ID.ToString)
|
|
|
|
Return Macro.Expand(value)
|
|
End Function
|
|
|
|
Shared Function GetDefaults() As List(Of AudioProfile)
|
|
Dim ret As New List(Of AudioProfile)
|
|
|
|
ret.Add(New GUIAudioProfile(AudioCodec.AAC, 50))
|
|
ret.Add(New GUIAudioProfile(AudioCodec.Opus, 1) With {.Bitrate = 250})
|
|
ret.Add(New GUIAudioProfile(AudioCodec.FLAC, 0.3))
|
|
ret.Add(New GUIAudioProfile(AudioCodec.Vorbis, 1))
|
|
ret.Add(New GUIAudioProfile(AudioCodec.MP3, 4))
|
|
ret.Add(New GUIAudioProfile(AudioCodec.AC3, 1.0) With {.Channels = 6, .Bitrate = 640})
|
|
ret.Add(New GUIAudioProfile(AudioCodec.EAC3, 1.0) With {.Channels = 6, .Bitrate = 640})
|
|
ret.Add(New BatchAudioProfile(640, {}, "ac3", 6, """%app:ffmpeg%"" -i %input% -b:a %bitrate%k -y -hide_banner %output%"))
|
|
ret.Add(New MuxAudioProfile())
|
|
ret.Add(New NullAudioProfile())
|
|
|
|
Return ret
|
|
End Function
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class BatchAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Sub New(bitrate As Integer,
|
|
input As String(),
|
|
fileType As String,
|
|
channels As Integer,
|
|
commandLines As String)
|
|
|
|
MyBase.New("Command Line", bitrate, input, fileType, channels)
|
|
Me.CommandLines = commandLines
|
|
CanEditValue = True
|
|
End Sub
|
|
|
|
Overrides Function Edit() As DialogResult
|
|
Using form As New CommandLineAudioEncoderForm(Me)
|
|
form.mbLanguage.Enabled = False
|
|
form.lLanguage.Enabled = False
|
|
form.tbDelay.Enabled = False
|
|
form.lDelay.Enabled = False
|
|
Return form.ShowDialog()
|
|
End Using
|
|
End Function
|
|
|
|
Function GetCode() As String
|
|
Return ExpandMacros(CommandLines).Trim
|
|
End Function
|
|
|
|
Overrides Sub Encode()
|
|
If File <> "" Then
|
|
Dim bitrateBefore = p.VideoBitrate
|
|
Dim targetPath = GetOutputFile()
|
|
|
|
For Each line In Macro.Expand(GetCode).SplitLinesNoEmpty
|
|
Using proc As New Proc
|
|
proc.Header = "Audio Encoding: " + Name
|
|
proc.SkipStrings = Proc.GetSkipStrings(CommandLines)
|
|
proc.File = "cmd.exe"
|
|
proc.Arguments = "/S /C """ + line + """"
|
|
|
|
Try
|
|
proc.Start()
|
|
Catch ex As AbortException
|
|
Throw ex
|
|
Catch ex As Exception
|
|
g.ShowException(ex)
|
|
Throw New AbortException
|
|
End Try
|
|
End Using
|
|
Next
|
|
|
|
If g.FileExists(targetPath) Then
|
|
If Not p.BitrateIsFixed Then
|
|
Dim bitrateFromFile = Calc.GetBitrateFromFile(targetPath, p.TargetSeconds)
|
|
p.VideoBitrate = p.VideoBitrate + CInt(Calc.GetAudioBitrateFromAudioProfile(Me)) - CInt(bitrateFromFile)
|
|
Bitrate = bitrateFromFile
|
|
|
|
If Not p.VideoEncoder.QualityMode Then
|
|
Log.WriteLine("Video Bitrate Adjustment: " + bitrateBefore.ToString() + " -> " & p.VideoBitrate & BR2)
|
|
End If
|
|
End If
|
|
|
|
File = targetPath
|
|
Log.WriteLine(MediaInfo.GetSummary(File))
|
|
Else
|
|
Log.Write("Error", "no output found")
|
|
|
|
If Not File.Ext = "wav" Then
|
|
Audio.Convert(Me)
|
|
|
|
If File.Ext = "wav" Then
|
|
Encode()
|
|
End If
|
|
End If
|
|
End If
|
|
End If
|
|
End Sub
|
|
|
|
Overrides Sub EditProject()
|
|
Using f As New CommandLineAudioEncoderForm(Me)
|
|
f.ShowDialog()
|
|
End Using
|
|
End Sub
|
|
|
|
Overrides Function HandlesDelay() As Boolean
|
|
Return CommandLines.Contains("%delay%")
|
|
End Function
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class NullAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Sub New()
|
|
MyBase.New("No Audio", 0, {}, "ignore", 0)
|
|
End Sub
|
|
|
|
Overrides Function HandlesDelay() As Boolean
|
|
End Function
|
|
|
|
Overrides Sub EditProject()
|
|
Using form As New SimpleSettingsForm("Null Audio Profile Options")
|
|
form.ScaleClientSize(20, 10)
|
|
Dim ui = form.SimpleUI
|
|
ui.Store = Me
|
|
|
|
Dim n = ui.AddNum()
|
|
n.Text = "Reserved Bitrate:"
|
|
n.Config = {0, Integer.MaxValue, 8}
|
|
n.Property = NameOf(Bitrate)
|
|
|
|
If form.ShowDialog() = DialogResult.OK Then
|
|
ui.Save()
|
|
End If
|
|
End Using
|
|
End Sub
|
|
|
|
Public Overrides Property OutputFileType As String
|
|
Get
|
|
Return "ignore"
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Public Overrides Sub Encode()
|
|
End Sub
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class MuxAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Sub New()
|
|
MyBase.New("Copy/Mux", 0, Nothing, "ignore", 2)
|
|
CanEditValue = True
|
|
End Sub
|
|
|
|
Private ChannelsValue As Integer = 0
|
|
|
|
Public Overrides Property Channels As Integer
|
|
Get
|
|
If Not Stream Is Nothing Then
|
|
If Stream.Channels > Stream.Channels2 Then
|
|
Return Stream.Channels
|
|
Else
|
|
Return Stream.Channels2
|
|
End If
|
|
ElseIf IO.File.Exists(File) Then
|
|
|
|
If ChannelsValue = 0 Then
|
|
ChannelsValue = MediaInfo.GetChannels(File)
|
|
End If
|
|
|
|
Return ChannelsValue
|
|
Else
|
|
Return 6
|
|
End If
|
|
End Get
|
|
Set(value As Integer)
|
|
End Set
|
|
End Property
|
|
|
|
Public Overrides Property OutputFileType As String
|
|
Get
|
|
If Stream Is Nothing Then
|
|
Return File.Ext
|
|
Else
|
|
Return Stream.Ext
|
|
End If
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Overrides Property SupportedInput As String()
|
|
Get
|
|
Return {}
|
|
End Get
|
|
Set(value As String())
|
|
End Set
|
|
End Property
|
|
|
|
Overrides Function Edit() As DialogResult
|
|
Return Edit(False)
|
|
End Function
|
|
|
|
Overrides Sub EditProject()
|
|
Edit(True)
|
|
End Sub
|
|
|
|
Overrides Sub Encode()
|
|
End Sub
|
|
|
|
Overrides Sub OnFileChanged()
|
|
MyBase.OnFileChanged()
|
|
SetBitrate()
|
|
End Sub
|
|
|
|
Overrides Sub OnStreamChanged()
|
|
MyBase.OnStreamChanged()
|
|
SetBitrate()
|
|
End Sub
|
|
|
|
Sub SetBitrate()
|
|
If Stream Is Nothing Then
|
|
Dim temp = CInt(MediaInfo.GetAudio(File, "BitRate").ToInt / 1000)
|
|
|
|
If temp > 0 Then
|
|
Bitrate = temp
|
|
Else
|
|
Bitrate = Calc.GetBitrateFromFile(File, p.SourceSeconds)
|
|
End If
|
|
Else
|
|
Bitrate = Stream.Bitrate + Stream.Bitrate2
|
|
End If
|
|
End Sub
|
|
|
|
Private Overloads Function Edit(showProjectSettings As Boolean) As DialogResult
|
|
Using form As New SimpleSettingsForm("Audio Mux Options",
|
|
"The Audio Mux options allow to add an audio file without reencoding.")
|
|
|
|
form.ScaleClientSize(30, 15)
|
|
|
|
Dim ui = form.SimpleUI
|
|
Dim page = ui.CreateFlowPage("main page")
|
|
page.SuspendLayout()
|
|
|
|
Dim tbb = ui.AddTextButton(page)
|
|
tbb.Label.Text = "Track Name:"
|
|
tbb.Label.Help = "Track name used by the muxer. The track name may contain macros."
|
|
tbb.Edit.Expand = True
|
|
tbb.Edit.Text = StreamName
|
|
tbb.Edit.SaveAction = Sub(value) StreamName = value
|
|
tbb.Button.Text = "Macro Editor..."
|
|
tbb.Button.ClickAction = AddressOf tbb.Edit.EditMacro
|
|
|
|
Dim nb = ui.AddNum(page)
|
|
nb.Label.Text = "Delay:"
|
|
nb.Label.Help = "Delay used by the muxer."
|
|
nb.NumEdit.Config = {Integer.MinValue, Integer.MaxValue, 1}
|
|
nb.NumEdit.Value = Delay
|
|
nb.NumEdit.SaveAction = Sub(value) Delay = CInt(value)
|
|
|
|
Dim mbi = ui.AddMenu(Of Language)(page)
|
|
mbi.Label.Text = "Language:"
|
|
mbi.Label.Help = "Language of the audio track."
|
|
mbi.Button.Value = Language
|
|
mbi.Button.SaveAction = Sub(value) Language = value
|
|
|
|
For Each i In Language.Languages
|
|
If i.IsCommon Then
|
|
mbi.Button.Add(i.ToString, i)
|
|
Else
|
|
mbi.Button.Add("More | " + i.ToString.Substring(0, 1).ToUpperInvariant + " | " + i.ToString, i)
|
|
End If
|
|
Next
|
|
|
|
Dim cb = ui.AddBool(page)
|
|
cb.Text = "Default"
|
|
cb.Help = "Flaged as default."
|
|
cb.Checked = [Default]
|
|
cb.SaveAction = Sub(value) [Default] = value
|
|
|
|
If TypeOf p.VideoEncoder.Muxer Is MkvMuxer Then
|
|
cb = ui.AddBool(page)
|
|
cb.Text = "Forced"
|
|
cb.Help = "Flaged as forced in MKV."
|
|
cb.Checked = Forced
|
|
cb.SaveAction = Sub(value) Forced = value
|
|
|
|
cb = ui.AddBool(page)
|
|
cb.Text = "Commentary"
|
|
cb.Help = "Flaged as commentary in MKV."
|
|
cb.Checked = Commentary
|
|
cb.SaveAction = Sub(value) Commentary = value
|
|
End If
|
|
|
|
cb = ui.AddBool(page)
|
|
cb.Text = "Extract DTS Core"
|
|
cb.Help = "Only include DTS core using mkvmerge."
|
|
cb.Checked = ExtractDTSCore
|
|
cb.SaveAction = Sub(value) ExtractDTSCore = value
|
|
|
|
page.ResumeLayout()
|
|
|
|
Dim ret = form.ShowDialog()
|
|
|
|
If ret = DialogResult.OK Then
|
|
ui.Save()
|
|
End If
|
|
|
|
Return ret
|
|
End Using
|
|
End Function
|
|
End Class
|
|
|
|
<Serializable()>
|
|
Public Class GUIAudioProfile
|
|
Inherits AudioProfile
|
|
|
|
Property Params As New Parameters
|
|
|
|
Sub New(codec As AudioCodec, quality As Single)
|
|
MyBase.New(Nothing)
|
|
|
|
Params.Codec = codec
|
|
Params.Quality = quality
|
|
|
|
Select Case codec
|
|
Case AudioCodec.DTS, AudioCodec.AC3, AudioCodec.EAC3
|
|
Params.RateMode = AudioRateMode.CBR
|
|
Case Else
|
|
Params.RateMode = AudioRateMode.VBR
|
|
End Select
|
|
|
|
Bitrate = GetBitrate()
|
|
End Sub
|
|
|
|
Private ChannelsValue As Integer
|
|
|
|
Public Overrides Property Channels As Integer
|
|
Get
|
|
Select Case Params.ChannelsMode
|
|
Case ChannelsMode.Original
|
|
If Not Stream Is Nothing Then
|
|
If Stream.Channels > Stream.Channels2 Then
|
|
Return Stream.Channels
|
|
Else
|
|
Return Stream.Channels2
|
|
End If
|
|
ElseIf IO.File.Exists(File) Then
|
|
If ChannelsValue = 0 Then
|
|
ChannelsValue = MediaInfo.GetChannels(File)
|
|
End If
|
|
|
|
Return ChannelsValue
|
|
Else
|
|
Return 6
|
|
End If
|
|
Case ChannelsMode._1
|
|
Return 1
|
|
Case ChannelsMode._2
|
|
Return 2
|
|
Case ChannelsMode._6
|
|
Return 6
|
|
Case ChannelsMode._7
|
|
Return 7
|
|
Case ChannelsMode._8
|
|
Return 8
|
|
Case Else
|
|
Throw New NotImplementedException
|
|
End Select
|
|
End Get
|
|
Set(value As Integer)
|
|
End Set
|
|
End Property
|
|
|
|
ReadOnly Property TargetSamplingRate As Integer
|
|
Get
|
|
If Params.SamplingRate <> 0 Then
|
|
Return Params.SamplingRate
|
|
Else
|
|
Return SourceSamplingRate
|
|
End If
|
|
End Get
|
|
End Property
|
|
|
|
Public Overrides Sub Migrate()
|
|
MyBase.Migrate()
|
|
Params.Migrate()
|
|
End Sub
|
|
|
|
Public Function GetBitrate() As Integer
|
|
If Params.RateMode = AudioRateMode.VBR Then
|
|
Select Case Params.Codec
|
|
Case AudioCodec.AAC
|
|
Select Case Params.Encoder
|
|
Case GuiAudioEncoder.qaac, GuiAudioEncoder.Automatic
|
|
Return Calc.GetYFromTwoPointForm(0, CInt(50 / 8 * Channels), 127, CInt(1000 / 8 * Channels), Params.Quality)
|
|
Case GuiAudioEncoder.eac3to
|
|
Return Calc.GetYFromTwoPointForm(0.01, CInt(50 / 8 * Channels), 1, CInt(1000 / 8 * Channels), Params.Quality)
|
|
Case Else
|
|
Return Calc.GetYFromTwoPointForm(1, CInt(50 / 8 * Channels), 5, CInt(900 / 8 * Channels), Params.Quality)
|
|
End Select
|
|
Case AudioCodec.MP3
|
|
Return Calc.GetYFromTwoPointForm(9, 65, 0, 245, Params.Quality)
|
|
Case AudioCodec.Vorbis
|
|
If Channels >= 6 Then
|
|
Return Calc.GetYFromTwoPointForm(0, 120, 10, 1440, Params.Quality)
|
|
Else
|
|
Return Calc.GetYFromTwoPointForm(0, 64, 10, 500, Params.Quality)
|
|
End If
|
|
Case AudioCodec.Opus
|
|
Return CInt(Bitrate)
|
|
End Select
|
|
End If
|
|
|
|
Select Case Params.Codec
|
|
Case AudioCodec.FLAC
|
|
Return CInt(((TargetSamplingRate * Depth * Channels) / 1000) * 0.55)
|
|
Case AudioCodec.W64, AudioCodec.WAV
|
|
Return CInt((TargetSamplingRate * Depth * Channels) / 1000)
|
|
End Select
|
|
|
|
Return CInt(Bitrate)
|
|
End Function
|
|
|
|
Public Overrides Sub Encode()
|
|
If File <> "" Then
|
|
Dim bitrateBefore = p.VideoBitrate
|
|
Dim targetPath = GetOutputFile()
|
|
Dim cl = GetCommandLine(True)
|
|
|
|
Using proc As New Proc
|
|
proc.Header = "Audio Encoding " & (GetTrackIndex() + 1)
|
|
|
|
If cl.Contains("|") Then
|
|
proc.File = "cmd.exe"
|
|
proc.Arguments = "/S /C """ + cl + """"
|
|
Else
|
|
proc.CommandLine = cl
|
|
End If
|
|
|
|
If cl.Contains("qaac64") Then
|
|
proc.Package = Package.qaac
|
|
proc.SkipStrings = {", ETA ", "x)", "Optimizing..."}
|
|
proc.AddToPath(Package.AppleApplicationSupport.Directory)
|
|
ElseIf cl.Contains("fdkaac") Then
|
|
proc.Package = Package.fdkaac
|
|
proc.SkipStrings = {"%]", "x)"}
|
|
ElseIf cl.Contains("eac3to") Then
|
|
proc.Package = Package.eac3to
|
|
proc.SkipStrings = {"process: ", "analyze: "}
|
|
proc.TrimChars = {"-"c, " "c}
|
|
proc.AddToPath(Package.NeroAAC.Directory)
|
|
ElseIf cl.Contains("ffmpeg") Then
|
|
If cl.Contains("libfdk_aac") Then
|
|
proc.Package = Package.ffmpeg_non_free
|
|
Else
|
|
proc.Package = Package.ffmpeg
|
|
End If
|
|
|
|
proc.SkipStrings = {"frame=", "size="}
|
|
proc.Encoding = Encoding.UTF8
|
|
proc.Duration = GetDuration()
|
|
End If
|
|
|
|
proc.Start()
|
|
End Using
|
|
|
|
If g.FileExists(targetPath) Then
|
|
If Not p.BitrateIsFixed Then
|
|
Dim bitrateFromFile = Calc.GetBitrateFromFile(targetPath, p.TargetSeconds)
|
|
p.VideoBitrate = p.VideoBitrate + CInt(Calc.GetAudioBitrateFromAudioProfile(Me)) - CInt(bitrateFromFile)
|
|
Bitrate = bitrateFromFile
|
|
|
|
If Not p.VideoEncoder.QualityMode Then
|
|
Log.WriteLine("Video Bitrate Adjustment: " + bitrateBefore.ToString() + " -> " & p.VideoBitrate & BR2)
|
|
End If
|
|
End If
|
|
|
|
File = targetPath
|
|
Log.WriteLine(MediaInfo.GetSummary(File))
|
|
Else
|
|
Throw New ErrorAbortException("Error audio encoding", "The output file is missing")
|
|
End If
|
|
End If
|
|
End Sub
|
|
|
|
Sub NormalizeFF()
|
|
If Not Params.Normalize OrElse ExtractCore OrElse
|
|
Not {ffmpegNormalizeMode.loudnorm, ffmpegNormalizeMode.volumedetect}.Contains(Params.ffmpegNormalizeMode) Then
|
|
|
|
Exit Sub
|
|
End If
|
|
|
|
Dim args = "-i " + File.Escape
|
|
|
|
If Not Stream Is Nothing AndAlso Streams.Count > 1 Then
|
|
args += " -map 0:a:" & Stream.Index
|
|
End If
|
|
|
|
args += " -sn -vn -hide_banner"
|
|
|
|
If Params.ffmpegNormalizeMode = ffmpegNormalizeMode.volumedetect Then
|
|
args += " -af volumedetect"
|
|
ElseIf Params.ffmpegNormalizeMode = ffmpegNormalizeMode.loudnorm Then
|
|
args += " -af loudnorm=I=" & Params.ffmpegLoudnormIntegrated.ToInvariantString +
|
|
":TP=" & Params.ffmpegLoudnormTruePeak.ToInvariantString + ":LRA=" &
|
|
Params.ffmpegLoudnormLRA.ToInvariantString + ":print_format=summary"
|
|
End If
|
|
|
|
args += " -f null NUL"
|
|
|
|
Using proc As New Proc
|
|
proc.Header = "Find Gain " & (GetTrackIndex() + 1)
|
|
proc.SkipStrings = {"frame=", "size="}
|
|
proc.Encoding = Encoding.UTF8
|
|
proc.Package = Package.ffmpeg
|
|
proc.Arguments = args
|
|
proc.Start()
|
|
|
|
Dim match = Regex.Match(proc.Log.ToString, "max_volume: -(\d+\.\d+) dB")
|
|
If match.Success Then Gain += match.Groups(1).Value.ToSingle()
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input Integrated:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormIntegratedMeasured = match.Groups(1).Value.ToDouble
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input True Peak:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormTruePeakMeasured = match.Groups(1).Value.ToDouble
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input LRA:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormLraMeasured = match.Groups(1).Value.ToDouble
|
|
|
|
match = Regex.Match(proc.Log.ToString, "Input Threshold:\s*([-\.0-9]+)")
|
|
If match.Success Then Params.ffmpegLoudnormThresholdMeasured = match.Groups(1).Value.ToDouble
|
|
End Using
|
|
End Sub
|
|
|
|
Overrides Function Edit() As DialogResult
|
|
Using form As New AudioForm()
|
|
form.LoadProfile(Me)
|
|
form.mbLanguage.Enabled = False
|
|
form.numDelay.Enabled = False
|
|
form.numGain.Enabled = False
|
|
Return form.ShowDialog()
|
|
End Using
|
|
End Function
|
|
|
|
Overrides Sub EditProject()
|
|
Using form As New AudioForm()
|
|
form.LoadProfile(Me)
|
|
form.ShowDialog()
|
|
End Using
|
|
End Sub
|
|
|
|
Public Overrides Property OutputFileType As String
|
|
Get
|
|
Select Case Params.Codec
|
|
Case AudioCodec.AAC
|
|
Return "m4a"
|
|
Case AudioCodec.Vorbis
|
|
Return "ogg"
|
|
Case Else
|
|
Return Params.Codec.ToString.ToLowerInvariant
|
|
End Select
|
|
End Get
|
|
Set(value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Function GetEac3toCommandLine(includePaths As Boolean) As String
|
|
Dim id = ""
|
|
Dim sb As New StringBuilder()
|
|
|
|
If File.Ext.EqualsAny("ts", "m2ts", "mkv") AndAlso Not Stream Is Nothing Then
|
|
id = (Stream.StreamOrder + 1) & ": "
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.eac3to.Path.Escape + " " + id + File.LongPathPrefix.Escape +
|
|
" " + GetOutputFile.LongPathPrefix.Escape)
|
|
Else
|
|
sb.Append("eac3to")
|
|
End If
|
|
|
|
If Not (Params.Codec = AudioCodec.DTS AndAlso ExtractDTSCore) Then
|
|
Select Case Params.Codec
|
|
Case AudioCodec.AAC
|
|
sb.Append(" -quality=" & Params.Quality.ToInvariantString)
|
|
Case AudioCodec.AC3
|
|
sb.Append(" -" & Bitrate)
|
|
Case AudioCodec.DTS
|
|
sb.Append(" -" & Bitrate)
|
|
End Select
|
|
|
|
If Params.Normalize Then
|
|
sb.Append(" -normalize")
|
|
End If
|
|
|
|
If Depth = 16 Then
|
|
sb.Append(" -down16")
|
|
End If
|
|
|
|
If Params.SamplingRate <> 0 Then
|
|
sb.Append(" -resampleTo" & Params.SamplingRate)
|
|
End If
|
|
|
|
If Params.FrameRateMode = AudioFrameRateMode.Speedup Then
|
|
sb.Append(" -speedup")
|
|
End If
|
|
|
|
If Params.FrameRateMode = AudioFrameRateMode.Slowdown Then
|
|
sb.Append(" -slowdown")
|
|
End If
|
|
|
|
If Delay <> 0 Then
|
|
sb.Append(" " + If(Delay > 0, "+", "") & Delay & "ms")
|
|
End If
|
|
|
|
If Gain < 0 Then
|
|
sb.Append(" " & CInt(Gain) & "dB")
|
|
End If
|
|
|
|
If Gain > 0 Then
|
|
sb.Append(" +" & CInt(Gain) & "dB")
|
|
End If
|
|
|
|
Select Case Channels
|
|
Case 6
|
|
If Params.ChannelsMode <> ChannelsMode.Original Then
|
|
sb.Append(" -down6")
|
|
End If
|
|
Case 2
|
|
If Params.eac3toStereoDownmixMode = 0 Then
|
|
If Params.ChannelsMode <> ChannelsMode.Original Then
|
|
sb.Append(" -downStereo")
|
|
End If
|
|
Else
|
|
sb.Append(" -downDpl")
|
|
End If
|
|
End Select
|
|
|
|
If Params.CustomSwitches <> "" Then
|
|
sb.Append(" " + Params.CustomSwitches)
|
|
End If
|
|
ElseIf ExtractDTSCore Then
|
|
sb.Append(" -core")
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(" -progressnumbers")
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetfdkaacCommandLine(includePaths As Boolean) As String
|
|
Dim sb As New StringBuilder
|
|
includePaths = includePaths And File <> ""
|
|
|
|
If DecodingMode = AudioDecodingMode.Pipe Then
|
|
sb.Append(GetPipeCommandLine(includePaths))
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.fdkaac.Path.Escape)
|
|
Else
|
|
sb.Clear()
|
|
sb.Append("fdkaac")
|
|
End If
|
|
|
|
If Params.fdkaacProfile <> 2 Then
|
|
sb.Append(" --profile " & Params.fdkaacProfile)
|
|
End If
|
|
|
|
If Params.SimpleRateMode = SimpleAudioRateMode.CBR Then
|
|
sb.Append(" --bitrate " & CInt(Bitrate))
|
|
Else
|
|
sb.Append(" --bitrate-mode " & Params.Quality)
|
|
End If
|
|
|
|
If Params.fdkaacGaplessMode <> 0 Then sb.Append(" --gapless-mode " & Params.fdkaacGaplessMode)
|
|
If Params.fdkaacBandwidth <> 0 Then sb.Append(" --bandwidth " & Params.fdkaacBandwidth)
|
|
If Not Params.fdkaacAfterburner Then sb.Append(" --afterburner 0")
|
|
If Params.fdkaacAdtsCrcCheck Then sb.Append(" --adts-crc-check")
|
|
If Params.fdkaacMoovBeforeMdat Then sb.Append(" --moov-before-mdat")
|
|
If Params.fdkaacIncludeSbrDelay Then sb.Append(" --include-sbr-delay")
|
|
If Params.fdkaacHeaderPeriod Then sb.Append(" --header-period")
|
|
If Params.fdkaacLowDelaySBR <> 0 Then sb.Append(" --lowdelay-sbr " & Params.fdkaacLowDelaySBR)
|
|
If Params.fdkaacSbrRatio <> 0 Then sb.Append(" --sbr-ratio " & Params.fdkaacSbrRatio)
|
|
If Params.fdkaacTransportFormat <> 0 Then sb.Append(" --transport-format " & Params.fdkaacTransportFormat)
|
|
If Params.CustomSwitches <> "" Then sb.Append(" " + Params.CustomSwitches)
|
|
|
|
Dim input = If(DecodingMode = AudioDecodingMode.Pipe, "-", File.LongPathPrefix.Escape)
|
|
|
|
If includePaths Then
|
|
sb.Append(" --ignorelength -o " + GetOutputFile.LongPathPrefix.Escape + " " + input)
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetQaacCommandLine(includePaths As Boolean) As String
|
|
Dim usePipe = DecodingMode = AudioDecodingMode.Pipe OrElse (Params.ChannelsMode <> ChannelsMode.Original AndAlso SupportedInput.Contains(File.Ext))
|
|
Dim sb As New StringBuilder
|
|
includePaths = includePaths And File <> ""
|
|
|
|
If usePipe Then
|
|
sb.Append(GetPipeCommandLine(includePaths))
|
|
End If
|
|
|
|
If includePaths Then
|
|
sb.Append(Package.qaac.Path.Escape)
|
|
Else
|
|
sb.Clear()
|
|
sb.Append("qaac")
|
|
End If
|
|
|
|
Select Case Params.qaacRateMode
|
|
Case 0
|
|
sb.Append(" --tvbr " & CInt(Params.Quality))
|
|
Case 1
|
|
sb.Append(" --cvbr " & CInt(Bitrate))
|
|
Case 2
|
|
sb.Append(" --abr " & CInt(Bitrate))
|
|
Case 3
|
|
sb.Append(" --cbr " & CInt(Bitrate))
|
|
End Select
|
|
|
|
If Params.qaacHE AndAlso {1, 2, 3}.Contains(Params.qaacRateMode) Then
|
|
sb.Append(" --he")
|
|
End If
|
|
|
|
If Delay <> 0 Then
|
|
sb.Append(" --delay " + (Delay / 1000).ToInvariantString)
|
|
End If
|
|
|
|
If Params.Normalize Then
|
|
sb.Append(" --normalize")
|
|
End If
|
|
|
|
If Params.qaacQuality <> 2 Then
|
|
sb.Append(" --quality " & Params.qaacQuality)
|
|
End If
|
|
|
|
If Params.SamplingRate <> 0 Then
|
|
sb.Append(" --rate " & Params.SamplingRate)
|
|
End If
|
|
|
|
If Params.qaacLowpass <> 0 Then
|
|
sb.Append(" --lowpass " & Params.qaacLowpass)
|
|
End If
|
|
|
|
If Params.qaacNoDither Then
|
|
sb.Append(" --no-dither")
|
|
End If
|
|
|
|
If Gain <> 0 Then
|
|
sb.Append(" --gain " & Gain.ToInvariantString)
|
|
End If
|
|
|
|
If Params.CustomSwitches <> "" Then
|
|
sb.Append(" " + Params.CustomSwitches)
|
|
End If
|
|
|
|
Dim input = If(usePipe, "-", File.Escape)
|
|
|
|
If includePaths Then
|
|
sb.Append(" " + input + " -o " + GetOutputFile.Escape)
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetPipeCommandLine(includePaths As Boolean) As String
|
|
Dim sb As New StringBuilder
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(Package.ffmpeg.Path.Escape + " -i " + File.Escape)
|
|
Else
|
|
sb.Append("ffmpeg")
|
|
End If
|
|
|
|
If Not Stream Is Nothing AndAlso Streams.Count > 1 Then
|
|
sb.Append(" -map 0:a:" & Stream.Index)
|
|
End If
|
|
|
|
If Params.ChannelsMode <> ChannelsMode.Original Then
|
|
sb.Append(" -ac " & Channels)
|
|
End If
|
|
|
|
If Params.Normalize Then
|
|
If Params.ffmpegNormalizeMode = ffmpegNormalizeMode.dynaudnorm Then
|
|
sb.Append(" " + Audio.GetDynAudNormArgs(Params))
|
|
ElseIf Params.ffmpegNormalizeMode = ffmpegNormalizeMode.loudnorm Then
|
|
sb.Append(" " + Audio.GetLoudNormArgs(Params))
|
|
End If
|
|
End If
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(" -loglevel fatal -hide_banner -f wav - | ")
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function GetffmpegCommandLine(includePaths As Boolean) As String
|
|
Dim sb As New StringBuilder
|
|
Dim pack = If(Params.Codec = AudioCodec.AAC AndAlso Params.ffmpegLibFdkAAC,
|
|
Package.ffmpeg_non_free, Package.ffmpeg)
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(pack.Path.Escape)
|
|
|
|
If Params.ProbeSize <> 5 Then
|
|
sb.Append($" -probesize {Params.ProbeSize}M")
|
|
End If
|
|
|
|
If Params.AnalyzeDuration <> 5 Then
|
|
sb.Append($" -analyzeduration {Params.AnalyzeDuration}M")
|
|
End If
|
|
|
|
If File.Ext.EqualsAny("avs", "vpy") Then
|
|
sb.Append(" -vn")
|
|
End If
|
|
|
|
sb.Append(" -i " + File.Escape)
|
|
Else
|
|
sb.Append("ffmpeg")
|
|
End If
|
|
|
|
If Not Stream Is Nothing Then
|
|
sb.Append(" -map 0:a:" & Stream.Index)
|
|
End If
|
|
|
|
Select Case Params.Codec
|
|
Case AudioCodec.MP3
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a libmp3lame")
|
|
End If
|
|
|
|
Select Case Params.RateMode
|
|
Case AudioRateMode.ABR
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k -abr 1")
|
|
Case AudioRateMode.CBR
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Case AudioRateMode.VBR
|
|
sb.Append(" -q:a " & CInt(Params.Quality))
|
|
End Select
|
|
Case AudioCodec.AC3
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a ac3")
|
|
End If
|
|
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Case AudioCodec.EAC3
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a eac3")
|
|
End If
|
|
|
|
sb.Append(" -b:a " & If(Bitrate > 960, CInt(Bitrate) + 0.1, CInt(Bitrate)).ToInvariantString() & "k")
|
|
Case AudioCodec.DTS
|
|
If ExtractDTSCore Then
|
|
sb.Append(" -bsf:a dca_core -c:a copy")
|
|
Else
|
|
sb.Append(" -strict -2 -b:a " & CInt(Bitrate) & "k")
|
|
End If
|
|
Case AudioCodec.Vorbis
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a libvorbis")
|
|
End If
|
|
|
|
If Params.RateMode = AudioRateMode.VBR Then
|
|
sb.Append(" -q:a " & CInt(Params.Quality))
|
|
Else
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
End If
|
|
Case AudioCodec.Opus
|
|
If Not Params.CustomSwitches.Contains("-c:a ") Then
|
|
sb.Append(" -c:a libopus")
|
|
End If
|
|
|
|
Select Case Params.ffmpegOpusRateMode
|
|
Case OpusRateMode.CBR
|
|
sb.Append(" -vbr off")
|
|
Case OpusRateMode.CVBR
|
|
sb.Append(" -vbr constrained")
|
|
End Select
|
|
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
|
|
Select Case Params.ffmpegOpusApp
|
|
Case OpusApp.voip
|
|
sb.Append(" -application voip")
|
|
Case OpusApp.lowdelay
|
|
sb.Append(" -application lowdelay")
|
|
End Select
|
|
|
|
If Params.ffmpegOpusFrame <> 20 Then
|
|
sb.Append(" -frame_duration " & Params.ffmpegOpusFrame.ToInvariantString)
|
|
End If
|
|
|
|
If Params.ffmpegOpusMap <> -1 Then
|
|
sb.Append(" -mapping_family " & CInt(Params.ffmpegOpusMap))
|
|
End If
|
|
|
|
If Params.ffmpegOpusCompress <> 10 Then
|
|
sb.Append(" -compression_level " & CInt(Params.ffmpegOpusCompress))
|
|
End If
|
|
|
|
If Params.ffmpegOpusPacket <> 0 Then
|
|
sb.Append(" -packet_loss " & CInt(Params.ffmpegOpusPacket))
|
|
End If
|
|
Case AudioCodec.AAC
|
|
If Params.ffmpegLibFdkAAC Then
|
|
sb.Append(" -c:a libfdk_aac")
|
|
|
|
If Params.RateMode = SimpleAudioRateMode.CBR Then
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Else
|
|
sb.Append(" -vbr " & CInt(Params.Quality))
|
|
End If
|
|
Else
|
|
sb.Append(" -c:a aac")
|
|
|
|
If Params.RateMode = SimpleAudioRateMode.CBR Then
|
|
sb.Append(" -b:a " & CInt(Bitrate) & "k")
|
|
Else
|
|
sb.Append(" -q:a " & CInt(Params.Quality))
|
|
End If
|
|
End If
|
|
Case AudioCodec.W64, AudioCodec.WAV
|
|
If Depth = 24 Then
|
|
sb.Append(" -c:a pcm_s24le")
|
|
Else
|
|
sb.Append(" -c:a pcm_s16le")
|
|
End If
|
|
End Select
|
|
|
|
If Gain <> 0 Then
|
|
sb.Append(" -af volume=" + Gain.ToInvariantString + "dB")
|
|
End If
|
|
|
|
If Params.Normalize Then
|
|
If Params.ffmpegNormalizeMode = ffmpegNormalizeMode.loudnorm Then
|
|
sb.Append(" " + Audio.GetLoudNormArgs(Params))
|
|
ElseIf Params.ffmpegNormalizeMode = ffmpegNormalizeMode.dynaudnorm Then
|
|
sb.Append(" " + Audio.GetDynAudNormArgs(Params))
|
|
End If
|
|
End If
|
|
|
|
If Params.ChannelsMode <> ChannelsMode.Original OrElse Params.Codec = AudioCodec.Opus Then
|
|
sb.Append(" -ac " & Channels)
|
|
End If
|
|
|
|
If Params.SamplingRate <> 0 Then
|
|
sb.Append(" -ar " & Params.SamplingRate)
|
|
End If
|
|
|
|
If Params.CustomSwitches <> "" Then
|
|
sb.Append(" " + Params.CustomSwitches)
|
|
End If
|
|
|
|
If includePaths AndAlso File <> "" Then
|
|
sb.Append(" -y -hide_banner")
|
|
sb.Append(" " + GetOutputFile.Escape)
|
|
End If
|
|
|
|
Return sb.ToString
|
|
End Function
|
|
|
|
Function SupportsNormalize() As Boolean
|
|
Return GetEncoder() = GuiAudioEncoder.eac3to OrElse GetEncoder() = GuiAudioEncoder.qaac
|
|
End Function
|
|
|
|
Public Overrides ReadOnly Property DefaultName As String
|
|
Get
|
|
If Params Is Nothing Then
|
|
Exit Property
|
|
End If
|
|
|
|
Dim ch = ""
|
|
|
|
Select Case Params.ChannelsMode
|
|
Case ChannelsMode._8
|
|
ch += " 7.1"
|
|
Case ChannelsMode._7
|
|
ch += " 6.1"
|
|
Case ChannelsMode._6
|
|
ch += " 5.1"
|
|
Case ChannelsMode._2
|
|
ch += " 2.0"
|
|
Case ChannelsMode._1
|
|
ch += " Mono"
|
|
End Select
|
|
|
|
Dim circa = If(Params.RateMode = AudioRateMode.VBR OrElse Params.Codec = AudioCodec.FLAC, "~", "")
|
|
Dim bitrate = If(Params.RateMode = AudioRateMode.VBR, GetBitrate(), Me.Bitrate)
|
|
|
|
If ExtractCore Then
|
|
Return "Extract DTS Core"
|
|
Else
|
|
Return Params.Codec.ToString + ch & " " & circa & bitrate & " Kbps"
|
|
End If
|
|
End Get
|
|
End Property
|
|
|
|
ReadOnly Property ExtractCore As Boolean
|
|
Get
|
|
Dim enc = GetEncoder()
|
|
|
|
If Params.Codec = AudioCodec.DTS AndAlso ExtractDTSCore AndAlso
|
|
(enc = GuiAudioEncoder.eac3to OrElse enc = GuiAudioEncoder.ffmpeg) Then
|
|
|
|
Return True
|
|
End If
|
|
End Get
|
|
End Property
|
|
|
|
Overrides Property CommandLines() As String
|
|
Get
|
|
Return GetCommandLine(True)
|
|
End Get
|
|
Set(Value As String)
|
|
End Set
|
|
End Property
|
|
|
|
Overrides ReadOnly Property CanEdit() As Boolean
|
|
Get
|
|
Return True
|
|
End Get
|
|
End Property
|
|
|
|
Overrides Function HandlesDelay() As Boolean
|
|
If {GuiAudioEncoder.eac3to, GuiAudioEncoder.qaac}.Contains(GetEncoder()) Then
|
|
Return True
|
|
End If
|
|
End Function
|
|
|
|
Function GetEncoder() As GuiAudioEncoder
|
|
Select Case Params.Encoder
|
|
Case GuiAudioEncoder.eac3to
|
|
If {AudioCodec.AAC, AudioCodec.AC3, AudioCodec.FLAC, AudioCodec.DTS,
|
|
AudioCodec.W64, AudioCodec.WAV}.Contains(Params.Codec) Then
|
|
|
|
Return GuiAudioEncoder.eac3to
|
|
End If
|
|
Case GuiAudioEncoder.qaac
|
|
If Params.Codec = AudioCodec.AAC Then
|
|
Return GuiAudioEncoder.qaac
|
|
End If
|
|
Case GuiAudioEncoder.fdkaac
|
|
If Params.Codec = AudioCodec.AAC Then
|
|
Return GuiAudioEncoder.fdkaac
|
|
End If
|
|
Case GuiAudioEncoder.Automatic
|
|
If Params.Codec = AudioCodec.AAC Then
|
|
Return GuiAudioEncoder.qaac
|
|
End If
|
|
End Select
|
|
|
|
Return GuiAudioEncoder.ffmpeg
|
|
End Function
|
|
|
|
Function GetCommandLine(includePaths As Boolean, Optional useCrcSuffix As Boolean = False) As String
|
|
Select Case GetEncoder()
|
|
Case GuiAudioEncoder.eac3to
|
|
Return GetEac3toCommandLine(includePaths)
|
|
Case GuiAudioEncoder.qaac
|
|
Return GetQaacCommandLine(includePaths)
|
|
Case GuiAudioEncoder.fdkaac
|
|
Return GetfdkaacCommandLine(includePaths)
|
|
Case Else
|
|
Return GetffmpegCommandLine(includePaths)
|
|
End Select
|
|
End Function
|
|
|
|
Overrides Property SupportedInput As String()
|
|
Get
|
|
Select Case GetEncoder()
|
|
Case GuiAudioEncoder.eac3to
|
|
Return FileTypes.eac3toInput
|
|
Case GuiAudioEncoder.qaac
|
|
If DecodingMode <> AudioDecodingMode.Pipe Then
|
|
If p.Ranges.Count > 0 Then
|
|
Return {"wav", "w64"}
|
|
Else
|
|
Return {"wav", "flac", "w64"}
|
|
End If
|
|
End If
|
|
Case GuiAudioEncoder.fdkaac
|
|
If DecodingMode <> AudioDecodingMode.Pipe Then
|
|
Return {"wav"}
|
|
End If
|
|
End Select
|
|
|
|
Return {}
|
|
End Get
|
|
Set(value As String())
|
|
End Set
|
|
End Property
|
|
|
|
<Serializable()>
|
|
Public Class Parameters
|
|
Property AnalyzeDuration As Integer = 5
|
|
Property ChannelsMode As ChannelsMode
|
|
Property Codec As AudioCodec
|
|
Property CustomSwitches As String = ""
|
|
Property eac3toStereoDownmixMode As Integer
|
|
Property Encoder As GuiAudioEncoder
|
|
Property FrameRateMode As AudioFrameRateMode
|
|
Property Normalize As Boolean = True
|
|
Property ProbeSize As Integer = 5
|
|
Property Quality As Single = 0.3
|
|
Property RateMode As AudioRateMode
|
|
Property SamplingRate As Integer
|
|
|
|
Property Migrate1 As Boolean = True
|
|
Property MigrateffNormalizeMode As Boolean = True
|
|
|
|
Property qaacHE As Boolean
|
|
Property qaacLowpass As Integer
|
|
Property qaacNoDither As Boolean
|
|
Property qaacQuality As Integer = 2
|
|
Property qaacRateMode As Integer
|
|
|
|
Property fdkaacProfile As Integer = 2
|
|
Property fdkaacBandwidth As Integer
|
|
Property fdkaacAfterburner As Boolean = True
|
|
Property fdkaacLowDelaySBR As Integer
|
|
Property fdkaacSbrRatio As Integer
|
|
Property fdkaacTransportFormat As Integer
|
|
Property fdkaacGaplessMode As Integer
|
|
Property fdkaacAdtsCrcCheck As Boolean
|
|
Property fdkaacHeaderPeriod As Boolean
|
|
Property fdkaacIncludeSbrDelay As Boolean
|
|
Property fdkaacMoovBeforeMdat As Boolean
|
|
|
|
Property ffNormalizeMode As ffNormalizeMode
|
|
Property ffmpegNormalizeMode As ffmpegNormalizeMode
|
|
|
|
Property ffmpegLibFdkAAC As Boolean
|
|
|
|
Property ffmpegLoudnormIntegrated As Double = -24
|
|
Property ffmpegLoudnormIntegratedMeasured As Double
|
|
Property ffmpegLoudnormLRA As Double = 7
|
|
Property ffmpegLoudnormLraMeasured As Double
|
|
Property ffmpegLoudnormThresholdMeasured As Double
|
|
Property ffmpegLoudnormTruePeak As Double = -2
|
|
Property ffmpegLoudnormTruePeakMeasured As Double
|
|
|
|
Property ffmpegDynaudnormF As Integer = 500
|
|
Property ffmpegDynaudnormG As Integer = 31
|
|
Property ffmpegDynaudnormP As Double = 0.95
|
|
Property ffmpegDynaudnormM As Double = 10
|
|
Property ffmpegDynaudnormR As Double
|
|
Property ffmpegDynaudnormN As Boolean = True
|
|
Property ffmpegDynaudnormC As Boolean
|
|
Property ffmpegDynaudnormB As Boolean
|
|
Property ffmpegDynaudnormS As Double
|
|
|
|
Property ffmpegOpusApp As OpusApp = OpusApp.audio
|
|
Property ffmpegOpusCompress As Integer = 10
|
|
Property ffmpegOpusFrame As Double = 20
|
|
Property ffmpegOpusMap As Integer = -1
|
|
Property ffmpegOpusPacket As Integer
|
|
Property ffmpegOpusRateMode As OpusRateMode = OpusRateMode.VBR
|
|
Property ffmpegOpusMigrate As Integer = 1
|
|
|
|
Property SimpleRateMode As SimpleAudioRateMode
|
|
Get
|
|
If RateMode = AudioRateMode.CBR Then
|
|
Return SimpleAudioRateMode.CBR
|
|
Else
|
|
Return SimpleAudioRateMode.VBR
|
|
End If
|
|
End Get
|
|
Set(value As SimpleAudioRateMode)
|
|
If value = SimpleAudioRateMode.CBR Then
|
|
RateMode = AudioRateMode.CBR
|
|
Else
|
|
RateMode = AudioRateMode.VBR
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
'legacy/obsolete
|
|
Sub Migrate()
|
|
'2019
|
|
If fdkaacProfile = 0 Then
|
|
fdkaacProfile = 2
|
|
SimpleRateMode = SimpleAudioRateMode.VBR
|
|
fdkaacAfterburner = True
|
|
End If
|
|
|
|
'2019
|
|
If Not Migrate1 Then
|
|
Normalize = True
|
|
|
|
ffmpegLoudnormIntegrated = -24
|
|
ffmpegLoudnormLRA = 7
|
|
ffmpegLoudnormTruePeak = -2
|
|
|
|
ffmpegDynaudnormF = 500
|
|
ffmpegDynaudnormG = 31
|
|
ffmpegDynaudnormP = 0.95
|
|
ffmpegDynaudnormM = 10
|
|
ffmpegDynaudnormN = True
|
|
|
|
Migrate1 = True
|
|
End If
|
|
|
|
'2020
|
|
If Not MigrateffNormalizeMode Then
|
|
ffmpegNormalizeMode = CType(ffNormalizeMode, ffmpegNormalizeMode)
|
|
MigrateffNormalizeMode = True
|
|
End If
|
|
|
|
'2020
|
|
If ffmpegOpusMigrate <> 1 Then
|
|
ffmpegOpusMigrate = 1
|
|
ffmpegOpusApp = OpusApp.audio
|
|
ffmpegOpusCompress = 10
|
|
ffmpegOpusFrame = 20
|
|
ffmpegOpusMap = -1
|
|
ffmpegOpusRateMode = OpusRateMode.VBR
|
|
End If
|
|
|
|
'2020
|
|
If ProbeSize = 0 AndAlso AnalyzeDuration = 0 Then
|
|
ProbeSize = 5
|
|
AnalyzeDuration = 5
|
|
End If
|
|
End Sub
|
|
End Class
|
|
End Class
|
|
|
|
Public Enum AudioCodec
|
|
AAC
|
|
AC3
|
|
DTS
|
|
FLAC
|
|
MP3
|
|
Opus
|
|
Vorbis
|
|
W64
|
|
WAV
|
|
EAC3
|
|
None
|
|
End Enum
|
|
|
|
Public Enum AudioRateMode
|
|
CBR
|
|
ABR
|
|
VBR
|
|
End Enum
|
|
|
|
Public Enum OpusRateMode
|
|
CBR
|
|
VBR
|
|
CVBR
|
|
End Enum
|
|
|
|
Public Enum OpusApp
|
|
voip
|
|
audio
|
|
lowdelay
|
|
End Enum
|
|
|
|
Public Enum SimpleAudioRateMode
|
|
CBR
|
|
VBR
|
|
End Enum
|
|
|
|
Public Enum AudioAacProfile
|
|
Automatic
|
|
LC
|
|
SBR
|
|
<DispName("SBR+PS")> SBRPS = 300
|
|
End Enum
|
|
|
|
Public Enum GuiAudioEncoder
|
|
Automatic
|
|
eac3to
|
|
ffmpeg
|
|
qaac
|
|
fdkaac
|
|
End Enum
|
|
|
|
Public Enum AudioFrameRateMode
|
|
Keep
|
|
<DispName("Apply PAL speedup")> Speedup
|
|
<DispName("Reverse PAL speedup")> Slowdown
|
|
End Enum
|
|
|
|
Public Enum AudioDownMixMode
|
|
<DispName("Simple")> Stereo
|
|
<DispName("Dolby Surround")> Surround
|
|
<DispName("Dolby Surround 2")> Surround2
|
|
End Enum
|
|
|
|
Public Enum ChannelsMode
|
|
Original
|
|
<DispName("1 (Mono)")> _1
|
|
<DispName("2 (Stereo)")> _2
|
|
<DispName("5.1")> _6
|
|
<DispName("6.1")> _7
|
|
<DispName("7.1")> _8
|
|
End Enum
|