mirror of
https://github.com/staxrip/staxrip.git
synced 2026-10-28 21:47:41 +08:00
529 lines
19 KiB
VB.net
529 lines
19 KiB
VB.net
|
|
Imports System.Collections.Concurrent
|
|
Imports System.Runtime.InteropServices
|
|
Imports System.Text.RegularExpressions
|
|
|
|
Public Class MediaInfo
|
|
Implements IDisposable
|
|
|
|
Private ReadOnly Handle As IntPtr
|
|
Private Shared Loaded As Boolean
|
|
|
|
Property Path As String = ""
|
|
|
|
Sub New(path As String)
|
|
If Not Loaded Then
|
|
Native.LoadLibrary(Package.MediaInfo.Path)
|
|
Loaded = True
|
|
End If
|
|
|
|
Handle = MediaInfo_New()
|
|
MediaInfo_Open(Handle, path)
|
|
Me.Path = path
|
|
End Sub
|
|
|
|
Private VideoStreamsValue As List(Of VideoStream)
|
|
|
|
ReadOnly Property VideoStreams() As List(Of VideoStream)
|
|
Get
|
|
If VideoStreamsValue Is Nothing Then
|
|
VideoStreamsValue = New List(Of VideoStream)
|
|
Dim count = MediaInfo_Count_Get(Handle, MediaInfoStreamKind.Video, -1)
|
|
|
|
If count > 0 Then
|
|
For index = 0 To count - 1
|
|
Dim at As New VideoStream With {
|
|
.Index = index
|
|
}
|
|
|
|
Dim streamOrder = GetVideo(index, "StreamOrder")
|
|
If Not streamOrder.IsInt Then streamOrder = (index + 1).ToString
|
|
at.StreamOrder = streamOrder.ToInt
|
|
|
|
at.Format = GetVideo(index, "Format")
|
|
at.ID = GetVideo(index, "ID").ToInt
|
|
|
|
VideoStreamsValue.Add(at)
|
|
Next
|
|
End If
|
|
End If
|
|
|
|
Return VideoStreamsValue
|
|
End Get
|
|
End Property
|
|
|
|
ReadOnly Property AudioStreams() As List(Of AudioStream)
|
|
Get
|
|
Dim ret As New List(Of AudioStream)
|
|
Dim count = MediaInfo_Count_Get(Handle, MediaInfoStreamKind.Audio, -1)
|
|
Dim offset As Integer
|
|
|
|
If count > 0 Then
|
|
For index = 0 To count - 1
|
|
Dim at As New AudioStream With {
|
|
.Index = index
|
|
}
|
|
|
|
Dim streamOrder = GetAudio(index, "StreamOrder")
|
|
|
|
If Not streamOrder.IsInt Then
|
|
streamOrder = (index + 1).ToString
|
|
End If
|
|
|
|
at.StreamOrder = streamOrder.ToInt + offset
|
|
|
|
Dim id = GetAudio(index, "ID")
|
|
|
|
If Not id.IsInt Then
|
|
id = (index + 2).ToString
|
|
End If
|
|
|
|
at.ID = id.ToInt + offset
|
|
|
|
at.Lossy = GetAudio(index, "Compression_Mode") = "Lossy"
|
|
at.SamplingRate = GetAudio(index, "SamplingRate").ToInt
|
|
at.BitDepth = GetAudio(index, "BitDepth").ToInt
|
|
at.Format = GetAudio(index, "Format")
|
|
at.FormatString = GetAudio(index, "Format/String")
|
|
at.FormatProfile = GetAudio(index, "Format_Profile")
|
|
at.Title = GetAudio(index, "Title").Trim
|
|
at.Forced = GetAudio(index, "Forced") = "Yes"
|
|
at.Default = GetAudio(index, "Default") = "Yes"
|
|
at.SBR = GetAudio(index, "Format/String").ContainsEx("SBR")
|
|
|
|
Dim lm = GetAudio(index, "Language_More")
|
|
|
|
If lm <> "" Then
|
|
If at.Title = "" Then
|
|
at.Title = lm
|
|
Else
|
|
at.Title += " - " + lm
|
|
End If
|
|
End If
|
|
|
|
Dim bitrate = GetAudio(index, "BitRate")
|
|
|
|
If bitrate.IsInt Then
|
|
at.Bitrate = CInt(bitrate.ToInt / 1000)
|
|
ElseIf bitrate.Contains("/") Then
|
|
Dim values = bitrate.Split("/"c)
|
|
at.Bitrate = CInt(values(0).ToInt / 1000)
|
|
at.Bitrate2 = CInt(values(1).ToInt / 1000)
|
|
End If
|
|
|
|
If at.Bitrate = 0 Then
|
|
at.Bitrate = GetAudio(index, "FromStats_BitRate").ToInt
|
|
End If
|
|
|
|
at.Delay = GetAudio(index, "Video_Delay").ToInt
|
|
|
|
Dim channels = GetAudio(index, "Channel(s)")
|
|
at.Channels = channels.ToInt
|
|
|
|
If at.Channels = 0 Then
|
|
at.Channels = GetAudio(index, "Channel(s)_Original").ToInt
|
|
End If
|
|
|
|
If at.Channels = 0 Then
|
|
If channels.Contains("/") Then
|
|
Dim values = channels.Split("/"c)
|
|
at.Channels = values(0).ToInt
|
|
at.Channels2 = values(1).ToInt
|
|
End If
|
|
End If
|
|
|
|
at.Language = New Language(GetAudio(index, "Language"))
|
|
|
|
Select Case p.DemuxAudio
|
|
Case DemuxMode.All
|
|
at.Enabled = True
|
|
Case DemuxMode.None
|
|
at.Enabled = False
|
|
Case DemuxMode.Preferred, DemuxMode.Dialog
|
|
Dim autoCode = p.PreferredAudio.ToLowerInvariant.SplitNoEmptyAndWhiteSpace(",", ";", " ")
|
|
at.Enabled = autoCode.ContainsAny("all", at.Language.TwoLetterCode, at.Language.ThreeLetterCode)
|
|
|
|
For Each i In autoCode
|
|
If i.IsInt AndAlso i.ToInt = (index + 1) Then
|
|
at.Enabled = True
|
|
End If
|
|
Next
|
|
End Select
|
|
|
|
ret.Add(at)
|
|
Next
|
|
End If
|
|
|
|
Return ret
|
|
End Get
|
|
End Property
|
|
|
|
ReadOnly Property Subtitles() As List(Of Subtitle)
|
|
Get
|
|
Dim ret As New List(Of Subtitle)
|
|
Dim count = MediaInfo_Count_Get(Handle, MediaInfoStreamKind.Text, -1)
|
|
Dim offset As Integer
|
|
|
|
If count > 0 Then
|
|
For index = 0 To count - 1
|
|
Dim subtitle As New Subtitle(New Language(GetText(index, "Language"))) With {
|
|
.Index = index
|
|
}
|
|
|
|
Dim streamOrder = GetText(index, "StreamOrder")
|
|
|
|
If streamOrder <> "" Then
|
|
subtitle.StreamOrder = If(streamOrder.Contains("-"), streamOrder.Right("-").ToInt + offset, streamOrder.ToInt)
|
|
End If
|
|
|
|
subtitle.Default = GetText(index, "Default") = "Yes"
|
|
subtitle.Forced = GetText(index, "Forced") = "Yes"
|
|
subtitle.Commentary = GetText(index, "Commentary") = "Yes"
|
|
subtitle.Hearingimpaired = GetText(index, "HearingImpaired") = "Yes"
|
|
subtitle.ID = GetText(index, "ID").ToInt
|
|
subtitle.Title = GetText(index, "Title").Trim
|
|
subtitle.CodecString = GetText(index, "Codec/String")
|
|
|
|
If subtitle.CodecString = "" Then
|
|
subtitle.CodecString = GetText(index, "Format")
|
|
End If
|
|
|
|
subtitle.Format = GetText(index, "Format")
|
|
subtitle.Size = GetText(index, "StreamSize").ToInt
|
|
|
|
If p.SubtitleMode = SubtitleMode.Disabled OrElse p.SubtitleMode = SubtitleMode.PreferredNoMux Then
|
|
subtitle.Enabled = False
|
|
Else
|
|
Dim autoCode = p.PreferredSubtitles.ToLowerInvariant.SplitNoEmptyAndWhiteSpace(",", ";", " ")
|
|
|
|
subtitle.Enabled = autoCode.ContainsAny("all", subtitle.Language.TwoLetterCode, subtitle.Language.ThreeLetterCode) OrElse p.SubtitleMode = SubtitleMode.All
|
|
|
|
For Each i In autoCode
|
|
If i.IsInt AndAlso i.ToInt = (index + 1) Then
|
|
subtitle.Enabled = True
|
|
End If
|
|
Next
|
|
End If
|
|
|
|
ret.Add(subtitle)
|
|
Next
|
|
End If
|
|
|
|
Return ret
|
|
End Get
|
|
End Property
|
|
|
|
Shared Function GetAudioStreams(path As String) As List(Of AudioStream)
|
|
Return GetMediaInfo(path).AudioStreams
|
|
End Function
|
|
|
|
Shared Function GetVideoStreams(path As String) As List(Of VideoStream)
|
|
Return GetMediaInfo(path).VideoStreams
|
|
End Function
|
|
|
|
Shared Function GetSubtitles(path As String) As List(Of Subtitle)
|
|
Return GetMediaInfo(path).Subtitles
|
|
End Function
|
|
|
|
Shared Function GetSummary(path As String) As String
|
|
Dim mi = GetMediaInfo(path)
|
|
MediaInfo_Option(mi.Handle, "Complete", "0")
|
|
Dim ret = Marshal.PtrToStringUni(MediaInfo_Inform(mi.Handle, 0))
|
|
If ret.Contains("UniqueID/String") Then ret = Regex.Replace(ret, "UniqueID/String +: .+\n", "")
|
|
If ret.Contains("Unique ID") Then ret = Regex.Replace(ret, "Unique ID +: .+\n", "")
|
|
If ret.Contains("Encoded_Library_Settings") Then ret = Regex.Replace(ret, "Encoded_Library_Settings +: .+\n", "")
|
|
If ret.Contains("Encoding settings") Then ret = Regex.Replace(ret, "Encoding settings +: .+\n", "")
|
|
If ret.Contains("Format settings, ") Then ret = ret.Replace("Format settings, ", "Format, ")
|
|
Return ret.FormatColumn(":").Trim
|
|
End Function
|
|
|
|
Shared Function GetCompleteSummary(path As String) As String
|
|
Dim mi = GetMediaInfo(path)
|
|
MediaInfo_Option(mi.Handle, "Complete", "1")
|
|
Return Marshal.PtrToStringUni(MediaInfo_Inform(mi.Handle, 0))
|
|
End Function
|
|
|
|
Function GetInfo(streamKind As MediaInfoStreamKind, parameter As String) As String
|
|
Return Marshal.PtrToStringUni(MediaInfo_Get(Handle, streamKind, 0, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name))
|
|
End Function
|
|
|
|
Function GetAudio(streamNumber As Integer, parameter As String) As String
|
|
Return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Audio, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name))
|
|
End Function
|
|
|
|
Function GetText(streamNumber As Integer, parameter As String) As String
|
|
Return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Text, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name))
|
|
End Function
|
|
|
|
Function GetInfo(streamKind As MediaInfoStreamKind, streamNumber As Integer, parameter As String) As String
|
|
Return Marshal.PtrToStringUni(MediaInfo_Get(Handle, streamKind, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name))
|
|
End Function
|
|
|
|
Shared Function GetInfo(path As String, streamKind As MediaInfoStreamKind, parameter As String) As String
|
|
Return If(path = "", "", GetMediaInfo(path).GetInfo(streamKind, parameter))
|
|
End Function
|
|
|
|
Shared Function GetInfo(path As String, streamKind As MediaInfoStreamKind, streamNumber As Integer, parameter As String) As String
|
|
Return If(path = "", "", GetMediaInfo(path).GetInfo(streamKind, streamNumber, parameter))
|
|
End Function
|
|
|
|
Shared Function GetMenu(path As String, parameter As String) As String
|
|
Return GetInfo(path, MediaInfoStreamKind.Menu, parameter)
|
|
End Function
|
|
|
|
Shared Function GetAudio(path As String, parameter As String) As String
|
|
Return GetInfo(path, MediaInfoStreamKind.Audio, parameter)
|
|
End Function
|
|
|
|
Shared Function GetAudio(path As String, streamNumber As Integer, parameter As String) As String
|
|
Return GetInfo(path, MediaInfoStreamKind.Audio, streamNumber, parameter)
|
|
End Function
|
|
|
|
Function GetVideo(parameter As String) As String
|
|
Return GetInfo(MediaInfoStreamKind.Video, parameter)
|
|
End Function
|
|
|
|
Function GetVideo(streamNumber As Integer, parameter As String) As String
|
|
Return GetInfo(MediaInfoStreamKind.Video, streamNumber, parameter)
|
|
End Function
|
|
|
|
Shared Function GetVideo(path As String, parameter As String) As String
|
|
Return GetInfo(path, MediaInfoStreamKind.Video, parameter)
|
|
End Function
|
|
|
|
Shared Function GetVideo(path As String, streamNumber As Integer, parameter As String) As String
|
|
Return GetInfo(path, MediaInfoStreamKind.Video, streamNumber, parameter)
|
|
End Function
|
|
|
|
Shared Function GetText(path As String, streamNumber As Integer, parameter As String) As String
|
|
Return GetInfo(path, MediaInfoStreamKind.Text, streamNumber, parameter)
|
|
End Function
|
|
|
|
Function GetGeneral(parameter As String) As String
|
|
Return GetInfo(MediaInfoStreamKind.General, parameter)
|
|
End Function
|
|
|
|
Shared Function GetGeneral(path As String, parameter As String) As String
|
|
Return GetInfo(path, MediaInfoStreamKind.General, parameter)
|
|
End Function
|
|
|
|
Shared Function GetVideoFormat(path As String) As String
|
|
Dim ret = GetInfo(path, MediaInfoStreamKind.Video, "Format")
|
|
|
|
If ret = "MPEG Video" Then
|
|
ret = "MPEG"
|
|
End If
|
|
|
|
Return ret
|
|
End Function
|
|
|
|
Function GetFrameRate(Optional defaultValue As Double = 25) As Double
|
|
Dim ret = GetVideo("FrameRate_Num").ToInt / GetVideo("FrameRate_Den").ToInt
|
|
|
|
If Calc.IsValidFrameRate(ret) Then
|
|
Return ret
|
|
End If
|
|
|
|
ret = GetVideo("FrameRate_Original_Num").ToInt / GetVideo("FrameRate_Original_Den").ToInt
|
|
|
|
If Calc.IsValidFrameRate(ret) Then
|
|
Return ret
|
|
End If
|
|
|
|
ret = GetVideo("FrameRate").ToDouble
|
|
|
|
If Calc.IsValidFrameRate(ret) Then
|
|
Return ret
|
|
End If
|
|
|
|
ret = GetVideo("FrameRate_Original").ToDouble
|
|
|
|
If Calc.IsValidFrameRate(ret) Then
|
|
Return ret
|
|
End If
|
|
|
|
ret = GetVideo("FrameRate_Nominal").ToDouble
|
|
|
|
If Calc.IsValidFrameRate(ret) Then
|
|
Return ret
|
|
End If
|
|
|
|
Return defaultValue
|
|
End Function
|
|
|
|
Shared Function GetFrameRate(path As String, Optional defaultValue As Double = 25) As Double
|
|
Return GetMediaInfo(path).GetFrameRate(defaultValue)
|
|
End Function
|
|
|
|
Function GetChannels() As Integer
|
|
Dim channelsString = GetInfo(MediaInfoStreamKind.Audio, "Channel(s)")
|
|
Dim ret = channelsString.ToInt
|
|
If ret = 0 Then ret = GetInfo(MediaInfoStreamKind.Audio, "Channel(s)_Original").ToInt
|
|
|
|
If ret = 0 Then
|
|
If channelsString.Contains("/") Then
|
|
Dim values = channelsString.Split("/"c)
|
|
Dim value0 = values(0).ToInt
|
|
Dim value1 = values(1).ToInt
|
|
If value0 >= value1 Then ret = value0 Else ret = value1
|
|
End If
|
|
End If
|
|
|
|
If ret = 0 Then ret = 2
|
|
Return ret
|
|
End Function
|
|
|
|
Shared Function GetChannels(path As String) As Integer
|
|
Return GetMediaInfo(path).GetChannels
|
|
End Function
|
|
|
|
Shared Function GetAudioCodecs(path As String) As String
|
|
Dim ret = GetGeneral(path, "Audio_Codec_List")
|
|
|
|
If ret.Contains("MPEG-1 Audio layer 2") Then ret = ret.Replace("MPEG-1 Audio layer 2", "MP2")
|
|
If ret.Contains("MPEG-1 Audio layer 3") Then ret = ret.Replace("MPEG-1 Audio layer 3", "MP3")
|
|
If ret.Contains("MPEG-2 Audio layer 3") Then ret = ret.Replace("MPEG-2 Audio layer 3", "MP3")
|
|
|
|
Return ret
|
|
End Function
|
|
|
|
Function GetVideoCount() As Integer
|
|
Return MediaInfo_Count_Get(Handle, MediaInfoStreamKind.Video, -1)
|
|
End Function
|
|
|
|
Shared Function GetVideoCount(Path As String) As Integer
|
|
Return GetMediaInfo(Path).GetVideoCount
|
|
End Function
|
|
|
|
Function GetAudioCount() As Integer
|
|
Return MediaInfo_Count_Get(Handle, MediaInfoStreamKind.Audio, -1)
|
|
End Function
|
|
|
|
Shared Function GetAudioCount(path As String) As Integer
|
|
Return GetMediaInfo(path).GetAudioCount
|
|
End Function
|
|
|
|
Function GetSubtitleCount() As Integer
|
|
Return MediaInfo_Count_Get(Handle, MediaInfoStreamKind.Text, -1)
|
|
End Function
|
|
|
|
Shared Function GetSubtitleCount(path As String) As Integer
|
|
Return GetMediaInfo(path).GetSubtitleCount
|
|
End Function
|
|
|
|
Shared ReadOnly Cache As ConcurrentDictionary(Of String, MediaInfo) = New ConcurrentDictionary(Of String, MediaInfo)
|
|
|
|
Shared Function GetMediaInfo(path As String) As MediaInfo
|
|
If path = "" Then
|
|
Return Nothing
|
|
End If
|
|
|
|
Dim key = path & File.GetLastWriteTime(path).Ticks
|
|
|
|
If Cache.ContainsKey(key) AndAlso Cache(key) IsNot Nothing Then
|
|
Return Cache(key)
|
|
End If
|
|
|
|
Dim ret = New MediaInfo(path)
|
|
Cache(key) = ret
|
|
Return ret
|
|
End Function
|
|
|
|
Shared Sub ClearCache()
|
|
For Each i In Cache
|
|
i.Value.Dispose()
|
|
Next
|
|
|
|
Cache.Clear()
|
|
End Sub
|
|
|
|
#Region "IDisposable"
|
|
|
|
Private Disposed As Boolean
|
|
|
|
Sub Dispose() Implements IDisposable.Dispose
|
|
If Not Disposed Then
|
|
Disposed = True
|
|
MediaInfo_Close(Handle)
|
|
MediaInfo_Delete(Handle)
|
|
End If
|
|
End Sub
|
|
|
|
Protected Overrides Sub Finalize()
|
|
Dispose()
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
#Region "native"
|
|
|
|
<DllImport("MediaInfo.dll")>
|
|
Private Shared Function MediaInfo_New() As IntPtr
|
|
End Function
|
|
|
|
<DllImport("MediaInfo.dll")>
|
|
Private Shared Sub MediaInfo_Delete(Handle As IntPtr)
|
|
End Sub
|
|
|
|
<DllImport("MediaInfo.dll", CharSet:=CharSet.Unicode)>
|
|
Private Shared Function MediaInfo_Open(Handle As IntPtr, FileName As String) As Integer
|
|
End Function
|
|
|
|
<DllImport("MediaInfo.dll")>
|
|
Private Shared Function MediaInfo_Close(Handle As IntPtr) As Integer
|
|
End Function
|
|
|
|
<DllImport("MediaInfo.dll")>
|
|
Private Shared Function MediaInfo_Inform(Handle As IntPtr,
|
|
Reserved As Integer) As IntPtr
|
|
End Function
|
|
|
|
<DllImport("MediaInfo.dll", CharSet:=CharSet.Unicode)>
|
|
Private Shared Function MediaInfo_Get(Handle As IntPtr,
|
|
StreamKind As MediaInfoStreamKind,
|
|
StreamNumber As Integer, Parameter As String,
|
|
KindOfInfo As MediaInfoInfoKind,
|
|
KindOfSearch As MediaInfoInfoKind) As IntPtr
|
|
End Function
|
|
|
|
<DllImport("MediaInfo.dll", CharSet:=CharSet.Unicode)>
|
|
Private Shared Function MediaInfo_Option(Handle As IntPtr,
|
|
OptionString As String,
|
|
Value As String) As IntPtr
|
|
End Function
|
|
|
|
<DllImport("MediaInfo.dll")>
|
|
Private Shared Function MediaInfo_State_Get(Handle As IntPtr) As Integer
|
|
End Function
|
|
|
|
<DllImport("MediaInfo.dll")>
|
|
Private Shared Function MediaInfo_Count_Get(Handle As IntPtr,
|
|
StreamKind As MediaInfoStreamKind,
|
|
StreamNumber As Integer) As Integer
|
|
End Function
|
|
|
|
#End Region
|
|
|
|
End Class
|
|
|
|
Public Enum MediaInfoStreamKind
|
|
General
|
|
Video
|
|
Audio
|
|
Text
|
|
Other
|
|
Image
|
|
Menu
|
|
Max
|
|
End Enum
|
|
|
|
Public Enum MediaInfoInfoKind
|
|
Name
|
|
Text
|
|
Measure
|
|
Options
|
|
NameText
|
|
MeasureText
|
|
Info
|
|
HowTo
|
|
End Enum |