隨着高速(20M)寬帶、HTPC、大容量硬盤(3T)的普及,下載高清片並利用大屏幕觀看也成為普通的事情。
隨着下載影片的增多,管理就有了問題,有時在茫茫文件夾下找尋一個影片也是一件費時費力的事。
於是萌生了自己編寫電影管理器的想法,並逐步逐步在實現。利用博客記錄編寫的過程,也是和網友之間的交流。期望在交流的過程中,網友能提出一些中肯的意見,使自己少走些彎路。
我在拿到一個高清視頻文件時。我希望能有辦法獲知以下的信息
文件名:視頻文件的文件名,這個比較簡單,利用FileInfo類就能獲得
文件大小:視頻文件的大小,這個也比較簡單,利用FileInfo類能獲得
視頻分辨率:視頻文件的分辨率,例如:寬1980像素,高1040像素。
視頻時長:視頻文件的時長,例如:長1小時32分
音頻數:視頻文件中的音頻數,有不少的高清視頻文件中包含不止一個音頻。有的包含英文、中文2個音頻;有的包含英文、中文、粵語3個音頻
音頻的語言類型:具體到每個音頻的語言。例如:音頻1是英文,音頻2是中文等
以上信息中的后面四個(視頻分辨率、視頻時長、音頻數、音頻的語言類型),用視頻播放器都能獲得。但是如何在自己的程序中獲得這些信息呢?
我們可以利用MediaInfo來獲取這些信息(視頻分辨率、視頻時長、音頻數、音頻的語言類型)
先看看MediaInfo的介紹,MediaInfo官網。在官網上有相關的介紹,並給出了調用的代碼(很完備。C++,C#,Visual Basic等都有)
高清視頻文件的相關信息都保存在文件的頭部區域,記錄的信息有很多(除卻上面的四種外,還包括碼率、編碼類型等等)。而MediaInfo就是利用讀取頭部區域的信息來獲得相關的信息。官網的更新很快,筆者下載的是2013年7月6日發布的最新版。
下面就介紹如何利用MediaInfo來獲得高清視頻文件的相關信息。
1、下載相應的DLL
在http://sourceforge.net/projects/mediainfo/files/development_snapshots/上點擊Download MediaInfo_GUI_0.7.64_Windows.exe (4.5 MB),下載最新的版本。安裝后在安裝的目錄中找到MediaInfo.dll和MediaInfo_i386.dll這兩個DLL文件。
2、新建項目
在VS2010中新建項目,把相關的DLL復制到可執行程序的目錄(在項目文件夾下的bin\Debug\,或者復制到系統目錄中)
注:MediaInfo.dll貌似是64位的;MediaInfo_i386.dll貌似是32位的;在后面的調試中,MediaInfo.dll始終會報錯,反而MediaInfo_i386.dll改成MediaInfo.dll后復制到目錄中調試一遍成功。
3、把官網中的提供的調用代碼添加到項目中來
由於DLL僅僅提供了函數。而目前的編碼基本上都是面向對象,所以在官網上針對很多的語言都提供了相應的代碼,把函數調用包裝成類,方便調用者使用。Visual Basic的調用代碼在http://sourceforge.net/p/mediainfo/code/5846/tree/MediaInfoLib/trunk/Project/MSVB2010/上,其他語言在相關的網頁上也能找到,這里就不贅述了。
要注意的是,在如上所做時,還得在VS2010中進行設置
在打開的項目屬性中,點開“調試”,勾上“啟用非托管代碼調試”,才能正常調試。
如果沒有勾上,運行時則會出現下面的對話框
可能是缺少Lib文件的緣故,不過我沒在官網上找到Lib文件的下載
另,不需要在項目中對MediaInfo.dll引用。引用會出錯,如下所示:
官網上的Visual Basic 2010調用代碼如下:
Imports System.Runtime.InteropServices
Public Enum StreamKind As UInteger
General
Visual
Audio
Text
Chapters
Image
Menu
Max
End Enum
Public Enum InfoKind As UInteger
Name
Text
Measure
Options
NameText
MeasureText
Info
HowTo
Max
End Enum
Public Enum InfoOptions As UInteger
ShowInInform
Reserved
ShowInSupported
TypeOfValue
Max
End Enum
Public Class MediaInfo
Private Declare Unicode Function MediaInfo_New Lib "MediaInfo.DLL" () As IntPtr
Private Declare Unicode Sub MediaInfo_Delete Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr)
Private Declare Unicode Function MediaInfo_Open Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr, ByVal FileName As String) As UIntPtr
Private Declare Unicode Sub MediaInfo_Close Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr)
Private Declare Unicode Function MediaInfo_Inform Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr, ByVal Reserved As UIntPtr) As IntPtr
Private Declare Unicode Function MediaInfo_GetI Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr, ByVal StreamKind As UIntPtr, ByVal StreamNumber As UIntPtr, ByVal Parameter As UIntPtr, ByVal KindOfInfo As UIntPtr) As IntPtr
Private Declare Unicode Function MediaInfo_Get Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr, ByVal StreamKind As UIntPtr, ByVal StreamNumber As UIntPtr, ByVal Parameter As String, ByVal KindOfInfo As UIntPtr, ByVal KindOfSearch As UIntPtr) As IntPtr
Private Declare Unicode Function MediaInfo_Option Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr, ByVal Option_ As String, ByVal Value As String) As IntPtr
Private Declare Unicode Function MediaInfo_State_Get Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr) As UIntPtr
Private Declare Unicode Function MediaInfo_Count_Get Lib "MediaInfo.DLL" ( ByVal Handle As IntPtr, ByVal StreamKind As UIntPtr, ByVal StreamNumber As IntPtr) As UIntPtr
Dim Handle As IntPtr
Sub New()
Handle = MediaInfo_New()
End Sub
Protected Overrides Sub Finalize()
MediaInfo_Delete(Handle)
End Sub
Function Open( ByVal FileName As String) As System. UIntPtr
Return MediaInfo_Open(Handle, FileName)
End Function
Sub Close()
MediaInfo_Close(Handle)
End Sub
Function Inform() As String
Return Marshal.PtrToStringUni(MediaInfo_Inform(Handle, CType(0, UIntPtr)))
End Function
Function Get_( ByVal StreamKind As StreamKind, ByVal StreamNumber As Integer, ByVal Parameter As Integer, Optional ByVal KindOfInfo As InfoKind = InfoKind.Text) As String
Return Marshal.PtrToStringUni(MediaInfo_GetI(Handle, CType(StreamKind, UIntPtr), CType(StreamNumber, UIntPtr), CType(Parameter, UIntPtr), CType(KindOfInfo, UIntPtr)))
End Function
Function Get_( ByVal StreamKind As StreamKind, ByVal StreamNumber As Integer, ByVal Parameter As String, Optional ByVal KindOfInfo As InfoKind = InfoKind.Text, Optional ByVal KindOfSearch As InfoKind = InfoKind.Name) As String
Return Marshal.PtrToStringUni(MediaInfo_Get(Handle, CType(StreamKind, UIntPtr), CType(StreamNumber, UIntPtr), Parameter, CType(KindOfInfo, UIntPtr), CType(KindOfSearch, UIntPtr)))
End Function
Function Option_( ByVal Option__ As String, Optional ByVal Value As String = "") As String
Return Marshal.PtrToStringUni(MediaInfo_Option(Handle, Option__, Value))
End Function
Function State_Get() As Integer
Return CInt(MediaInfo_State_Get(Handle))
End Function
Function Count_Get( ByVal StreamKind As StreamKind, Optional ByVal StreamNumber As UInteger = UInteger.MaxValue) As Integer
If StreamNumber = UInteger.MaxValue Then
Return CInt(MediaInfo_Count_Get(Handle, CType(StreamKind, UIntPtr), CType(-1, IntPtr)))
Else
Return CInt(MediaInfo_Count_Get(Handle, CType(StreamKind, UIntPtr), CType(StreamNumber, IntPtr)))
End If
End Function
End Class
4、再次包裝,方便調用
由於上面的代碼是提供了一個類供調用者使用,因此,我決定再包裝一下,使其看起來簡單一些(我只需要分辨率、時長、音頻數、音頻語言這四個信息)。
我包裝的代碼如下:
Public Class clsMediaInfo
Private _M As MediaInfo
Public Sub New()
_M = New MediaInfo
End Sub
Public Function GetInfo(FileName As String) As String
_M.Open(FileName)
_M.Option_( "Complete")
Return _M.Inform
End Function
Public Function Width() As String
Return _M.Get_( StreamKind.Visual, 0, "Width")
End Function
Public Function Height() As String
Return _M.Get_( StreamKind.Visual, 0, "Height")
End Function
Public Function Duration() As String
Return _M.Get_( StreamKind.General, 0, "Duration/String3")
End Function
Public Function AudioCount() As Integer
Return Convert.ToInt32(_M.Get_( StreamKind.General, 0, "AudioCount"))
End Function
Public Function AudioLanguage(Index As Integer) As String
If Index < 0 OrElse Index > AudioCount() - 1 Then Index = 0
Return _M.Get_( StreamKind.Audio, Index, "Language/String")
End Function
Public Function AudioLanguage() As String()
Dim I As Integer, C As Integer = AudioCount()
Dim L(C - 1) As String
For I = 0 To C - 1
L(I) = _M.Get_( StreamKind.Audio, I, "Language/String")
Next
Return L
End Function
End Class
解釋一下:
首先在類的內部定義一個MediaInfo類的實例,具體的功能都是通過該實例來完成。
在查看信息前,需調用GetInfo(FileName As String)函數,該函數的目的是獲得相關的信息,一共三句話
_M.Open(FileName)
_M.Option_("Complete")
Return _M.Inform
第1句,打開FileName指定的文件;第2句,獲取相關信息,並通知類,已經獲取完畢(可能在DLL中會有釋放資源等操作);第3句,返回視頻文件的相關信息。
第3句話返回的是所有的信息,長長的一串。
如果僅僅是想獲得某一個信息,則需要調用下面的語句
_M.Get_(StreamKind.Visual, 0, "Width")
一共三個參數。
第1個參數,獲取信息的類別。一般取StreamKind.General(通用信息)、StreamKind.Visual(視頻信息)、StreamKind.Audio(音頻信息)
第2個參數,獲取信息的流編號。一般取0(第1個流,視頻一般就1個流,音頻有可能多於1個流),音頻的話,取相應的流編號(0開始,到流數減1)
第3個參數,獲取信息的名字。根據該參數返回對應的信息。
那么,對應的調用就是
視頻寬度:_M.Get_(StreamKind.Visual, 0, "Width")
視頻高度:_M.Get_(StreamKind.Visual, 0, "Height")
視頻時長:_M.Get_(StreamKind.General, 0, "Duration/String3")。這個有多種選擇,該調用返回 01:34:48.683 這種格式;如果是:_M.Get_(StreamKind.General, 0, "Duration"),則返回 5688683 ,還需要自己轉換。
音頻個數:_M.Get_(StreamKind.General, 0, "AudioCount")
音頻語言:_M.Get_(StreamKind.Audio, I, "Language/String")。也是多種選擇,該調用返回 English 這種格式;如果是:_M.Get_(StreamKind.Audio, I, "Language"),則返回 en 這種格式。
如果想獲取其他的信息,直接給出相應的參數就行了。例如想獲得視頻的最大碼率,給出參數BitRate_Maximum就行了。如下調用
_M.Get_(StreamKind.Visual, 0, "BitRate_Maximum")
那么,如何能知道有哪些參數呢?參看
這兩篇文章對參數介紹的很詳細,只是文章寫得早,提供的DLL版本比較低罷了
下面是獲取 G:\Despicable.Me.2010.BluRay.1080p.DTS.2Audio.x264-CHD.mkv 這個高清視頻文件信息的調用代碼:
Dim S As New clsMediaInfo
S.GetInfo("G:\Despicable.Me.2010.BluRay.1080p.DTS.2Audio.x264-CHD.mkv")
Dim S1 As String = ""
S1 &= S.Width & " " & S.Height & vbNewLine
S1 &= S.Duration & vbNewLine
S1 &= S.AudioCount & vbNewLine
S1 &= S.AudioLanguage(0) & "," & S.AudioLanguage(1)
RichTextBox1.Text = S1
返回的信息如下:
1920 1040
01:34:48.683
2
English,Chinese
說明視頻分辨率為1920*1040;時長:1小時34分48秒;2個音頻;分別是英文和中文;
這個代碼在做高清視頻文件的信息庫的時候特別有用。可以根據高清視頻文件自動獲取相關信息,毋須再手動填充信息。