Die Möglichkeiten Videos zu erstellen, gehört mittlerweile zum Standard bei vielen Kameras, Handys, PDAs, Iphones und co oder auch von diversen Anwendungen wie z.B. 3D-Animationen oder direkte Desktopaufnahmen (Fraps). Die erstellten Videos werden allerdings meistens von den Geräte kaum bis gar nicht komprimiert und bei Anwendungen ist meistens Glücksache.
Mit einem einheitlich Codec zur Komprimierung sieht es ebenfalls bescheiden ein, so stellt sich die Wiedergabe der unterschiedlichsten Videotypen im Unternehmensnetzwerk mit hunderte Arbeitsplätzen doch ziemlich problematisch dar. Stellt man VLC (VideoLAN) als Wiedergabe auf allen PCs bereit, so ist mit ziemlich Sicherheit zu sagen, dass „fast“ alles Wiedergeben werden kann.
Was allerdings schnell zu Problemen führt, sind „unbelehrbare Mitarbeiter“, die jedes noch so große Video zentral im Netzwerk ablegen. So sieht man doch recht häufig Videoaufnahmen, welche hunderte MB bzw. sogar in mehrere GB gehen mit Videoauflösung die man wirklich nicht braucht.
Eine Einweisung der Mitarbeiter bzgl. Videos ist in den meisten Fällen mehr als sinnlos. Da man schön einiges „Wissen“ bzw. Erfahrung benötigt um beurteilen zu können welche Videoauflösung, Bitrate, Codec nötig ist.
Nun habe ich zu Administrationszwecken ein relativ kleines VB.NET Programm entwickelt, mit dem ich regelmäßig neu erstellte Videos im Netzwerk mittels mencoder komprimieren lassen.
Da ich nicht für jedes Video die genannten Entscheidungen treffen kann, um mögliche Videoanpassungen durchzuführen, lasse ich diesen Vorgang automatisiert durchführen.
Wird ein Video in die Anwendung eingefügt z.B. per Drag&Drop, so wird aus der aktuellen Videoauflösung ein prozentualer Wert ermittelt um den das Video verkleinert wird. Voreinstellt ist zusätzliche ein H264 Profil mit konstanter Bitrate. So kann jeder noch so „unbelehrbare Mitarbeiter“ mit einem einfachen klick ein Video in eine akzeptable Auflösung, Dateigröße und Videoformat bringen.
Die Anwendung
Sie basiert auf mencoder / mplayer und stellt eigentlich nur eine einfache Oberfläche bereit, die die nötigen Kommandozeilen generiert. Per Drag&Drop oder über eine Dialogbox, können mehrere Videos zum konvertieren ausgewählt werden.
Profile
Der mencoder unterstützt Konvert-Profile, welche in der Datei ../meconder.conf eingetragen werden. Ich habe für mich einige Profile angelegt, die man auch im Alltag nutzen kann. z.B. WMV, MPEG oder auch E-Mailprofile, damit auch jeder Kunde außerhalb ohne Zusatzsoftware die zugesandten Video abspielen kann.
Kalkulation der Auflösung
Um einen Wert zu bestimmen, ob ein Video verkleinert werden muss. nutze ich die Pixelanzahl der Quellauflösung und Zielauflösung. Durch einfaches multiplizieren von Breite x Höhe wird sichergestellt, dass alle Videoproportionen 16:9, 19:10, 4:3, ... in eine relativ gleiche Videoauflösung konvertiert werden.
Installation
Die Anwendung besteht lediglich aus einer einfachen EXE welche das .NET Framework benötigt und muss innerhalb des mplayer / mencoder Ordner liegen.
Source Code
Video Informationen mit dem mplayer eines beliebigen Videos auslesen
mplayer -vo null -ao null -frames 0 -identify videofile.avi
[...] ID_VIDEO_FORMAT=XVID ID_VIDEO_BITRATE=815712 ID_VIDEO_WIDTH=640 ID_VIDEO_HEIGHT=256 [...]
Umwandeln eines Video mit mencoder über ein Profil aus der mplayer.conf und reduzierung der Auflösung um 50%
mencoder videosource.avi -vf scale -zoom -xy 0.5 -profile profilname -o videodestination.avi
Konvertieren ohne Sound (muss bei manchen MOV Dateien gemacht werden)
mencoder … -nosound
/trunk/AutoVideoConverter/Form1.vb
Imports System.IO Imports System.Text.RegularExpressions Public Class Form1 #Region "Declarations" Dim BaseDir As String = System.Environment.CurrentDirectory Dim MEncoderEncodingStr As String = """%in%"" %scale% -profile %profil% -o ""%out%""" Dim MPlayerVideoInfoStr As String = "-vo null -ao null -frames 0 -identify ""%in%""" Structure sVideoSize Dim Width As Integer Dim Height As Integer End Structure #End Region #Region "Form Functions" Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim NeededFiles() As String = {BaseDir & "\mplayer\mencoder.conf", BaseDir & "\mencoder.exe", BaseDir & "\mplayer.exe"} For Each NeededFile As String In NeededFiles If Not File.Exists(NeededFile) Then MsgBox(NeededFile & " not found", MsgBoxStyle.Critical) : End Next ReadMEncoderProfiles() chksound.Checked = My.Settings.SoundDisabled cmbprofil.SelectedIndex = cmbprofil.Items.IndexOf(My.Settings.DefaultProfil) cmbzoom.SelectedIndex = cmbzoom.Items.IndexOf(My.Settings.DefaultPercent) txtautosize.Text = My.Settings.MaxPixel If cmbprofil.SelectedIndex < 0 And cmbprofil.Items.Count > 1 Then cmbprofil.SelectedIndex = 0 If cmbzoom.SelectedIndex < 0 And cmbzoom.Items.Count > 1 Then cmbzoom.SelectedIndex = 0 End Sub Private Sub butOpenFiles_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butOpenFiles.Click If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then For Each FileName As String In OpenFileDialog1.FileNames StartEncoding(FileName, cmbzoom.Text, chksound.Checked) Next End If End Sub Private Sub chksound_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chksound.CheckedChanged, ckDebug.CheckedChanged My.Settings.SoundDisabled = chksound.Checked End Sub Private Sub cmbprofil_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbprofil.SelectedIndexChanged My.Settings.DefaultProfil = cmbprofil.Text End Sub Private Sub cmbzoom_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbzoom.SelectedIndexChanged My.Settings.DefaultPercent = cmbzoom.Text End Sub Private Sub tbFiles_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles tbFiles.DragDrop Dim s As Array = CType(e.Data.GetData(DataFormats.FileDrop), Array) For Each FileName As String In s StartEncoding(FileName, cmbzoom.Text, chksound.Checked) Next End Sub Private Sub txtautosize_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtautosize.KeyPress If Not Char.IsNumber(e.KeyChar) And Not Char.IsControl(e.KeyChar) Then e.Handled = True End Sub Private Sub tbFiles_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles tbFiles.DragEnter If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then e.Effect = DragDropEffects.Copy End If End Sub Private Sub txtautosize_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtautosize.TextChanged My.Settings.MaxPixel = Convert.ToInt32(txtautosize.Text) End Sub Private Sub tbInfo_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles tbInfo.Enter txtInfo.Text = My.Application.Info.AssemblyName & " Version:" & vbCrLf txtInfo.Text &= My.Application.Info.Version.ToString & vbCrLf txtInfo.Text &= vbCrLf & "mencoder/mplayer Version:" & vbCrLf txtInfo.Text &= ConsoleGetStd("\mencoder.exe") End Sub #End Region #Region "Functions" ''' <summary> ''' Generate mencoder command and execute it to convert the video ''' </summary> ''' <param name="VideoFilePath">Path to the source video file</param> ''' <param name="ScaleProcent">optional: reduce video resolution by x percent</param> ''' <param name="DisableSound">optional: remove sound on destination video?</param> ''' <remarks></remarks> Sub StartEncoding(ByVal VideoFilePath As String, Optional ByVal ScaleProcent As String = "auto", Optional ByVal DisableSound As Boolean = False) Dim Cmd As String = MEncoderEncodingStr Cmd = Cmd.Replace("%profil%", cmbprofil.Items(cmbprofil.SelectedIndex).ToString) If ScaleProcent = "auto" Then Dim VideoSize As sVideoSize = MPlayerGetVideosize(VideoFilePath, BaseDir & "\") ScaleProcent = VideoResizeProcent(VideoSize, txtautosize.Text) If Not ScaleProcent > 0 Then ScaleProcent = 50 End If Cmd = Cmd.Replace("%scale%", "-vf scale -zoom -xy " & Convert.ToInt32(ScaleProcent) / 100) 'Generate output filepath Dim DestinationFile As String = "" Dim SelectedProfil As String = cmbprofil.Items(cmbprofil.SelectedIndex).ToString 'Generate a file extension depending on selected profil If SelectedProfil.Contains("xvid") = True Then DestinationFile = VideoFilePath.Substring(0, VideoFilePath.LastIndexOf(".")) & "_neu.avi" If SelectedProfil.Contains("x264") = True Then DestinationFile = VideoFilePath.Substring(0, VideoFilePath.LastIndexOf(".")) & "_neu.mp4" If SelectedProfil.Contains("mpeg") = True Then DestinationFile = VideoFilePath.Substring(0, VideoFilePath.LastIndexOf(".")) & "_neu.mpg" If SelectedProfil.Contains("flv") Or SelectedProfil.Contains("flash") = True Then DestinationFile = VideoFilePath.Substring(0, VideoFilePath.LastIndexOf(".")) & "_neu.flv" If SelectedProfil.Contains("f4v") = True Then DestinationFile = VideoFilePath.Substring(0, VideoFilePath.LastIndexOf(".")) & "_neu.f4v" If SelectedProfil.Contains("wmv") = True Then DestinationFile = VideoFilePath.Substring(0, VideoFilePath.LastIndexOf(".")) & "_neu.wmv" 'error if profilname extension is unknown If DestinationFile = "" Then MsgBox("DestinationFile error") Exit Sub End If Cmd = Cmd.Replace("%in%", VideoFilePath) Cmd = Cmd.Replace("%out%", DestinationFile) 'disable sound or not If DisableSound = True Then Cmd = Cmd & " -nosound" If ckDebug.Checked = True Then MsgBox(Cmd) Dim AppMencoder As New System.Diagnostics.Process() With AppMencoder .StartInfo.FileName = BaseDir & "\mencoder.exe" .StartInfo.Arguments = Cmd If ckDebug.Checked = False Then .Start() Else .StartInfo.RedirectStandardInput = True .StartInfo.RedirectStandardOutput = True .StartInfo.RedirectStandardError = True .StartInfo.UseShellExecute = False .StartInfo.CreateNoWindow = True .Start() .WaitForExit() Dim StdOut As System.IO.StreamReader = .StandardOutput Dim source As String = StdOut.ReadToEnd MsgBox(source) End If End With 'old save dialog 'If txtfold.Text.Length > 0 Then ' If Not cmbprofil.Items(cmbprofil.SelectedIndex).ToString.IndexOf("mpeg") Then Cmd = Cmd.Replace("%out%", txtfold.Text & ".mpg") ' If Not cmbprofil.Items(cmbprofil.SelectedIndex).ToString.IndexOf("xvid") Then Cmd = Cmd.Replace("%out%", txtfold.Text & ".avi") 'Else ' Cmd = Cmd.Replace("%out%", VideoFilePath) 'End If End Sub ''' <summary> ''' ''' </summary> ''' <param name="FileName"></param> ''' <param name="cmd"></param> ''' <returns></returns> Function ConsoleGetStd(ByVal FileName As String, Optional ByVal cmd As String = "") Dim AppMencoder As New System.Diagnostics.Process() With AppMencoder .StartInfo.FileName = BaseDir & "\mencoder.exe" .StartInfo.Arguments = cmd .StartInfo.RedirectStandardInput = True .StartInfo.RedirectStandardOutput = True .StartInfo.RedirectStandardError = True .StartInfo.UseShellExecute = False .StartInfo.CreateNoWindow = True .Start() .WaitForExit() Dim StdOut As System.IO.StreamReader = .StandardOutput Dim source As String = StdOut.ReadToEnd Return source End With End Function ''' <summary> ''' Calculate a procent value on which the video must be reduce to match ''' then max pixelsize ''' </summary> ''' <param name="VideoSize">sVideoSize Object</param> ''' <param name="MaxPixel">maximal Pixel size. use Width x Height to calc the wanted video resolution</param> ''' <returns>returns procent value on which the video resolution must be reduce; returns 100 if no resize is necessary</returns> Function VideoResizeProcent(ByVal VideoSize As sVideoSize, Optional ByVal MaxPixel As Integer = 300000) As Integer If VideoSize.Width > 0 And VideoSize.Width > 0 Then Dim Pixels As Integer = VideoSize.Width * VideoSize.Height If Pixels > MaxPixel Then 'calculate procent value to resize and round values to 95,90,85,... Return Math.Round((MaxPixel / Pixels * 100) / 5) * 5 Else 'the source video is smaller than the wanted size Return 100 End If End If Return 0 End Function ''' <summary> ''' Parse available convert profiles out of mencoder.conf ''' </summary> Sub ReadMEncoderProfiles() Dim objReader As New StreamReader("mplayer\mencoder.conf") Dim source As String = objReader.ReadToEnd() objReader.Close() Dim mc As MatchCollection mc = Regex.Matches(source, "\[(.*?)\]") For i As Integer = 0 To mc.Count - 1 cmbprofil.Items.Add(mc(i).Groups(1).Value) Next End Sub ''' <summary> ''' Get the width and height of a video with the help of mplayer.exe ''' </summary> ''' <param name="VideoFile">Fullpath to videofile</param> ''' <param name="MPlayerDir">optional the path of mplayer.exe</param> ''' <returns>sVideoSize Object</returns> Function MPlayerGetVideosize(ByVal VideoFile As String, Optional ByVal MPlayerDir As String = "") As sVideoSize Dim MPlayerApp As New System.Diagnostics.Process() With MPlayerApp .StartInfo.FileName = MPlayerDir & "mplayer.exe" .StartInfo.Arguments = MPlayerVideoInfoStr.Replace("%in%", VideoFile) .StartInfo.RedirectStandardInput = True .StartInfo.RedirectStandardOutput = True .StartInfo.RedirectStandardError = True .StartInfo.UseShellExecute = False .StartInfo.CreateNoWindow = True .Start() .WaitForExit() End With Dim StdOut As System.IO.StreamReader = MPlayerApp.StandardOutput Dim source As String = StdOut.ReadToEnd Dim b As New sVideoSize b.Width = Regex.Match(source, "ID_VIDEO_WIDTH=(.*?)\n").Groups(1).ToString() b.Height = Regex.Match(source, "ID_VIDEO_HEIGHT=(.*?)\n").Groups(1).ToString() Return b 'to extract all video info 'Dim mc As MatchCollection 'mc = Regex.Matches(source, "ID_(.*?)=(.*?)\n") 'For i As Integer = 0 To mc.Count - 1 ' MsgBox(mc(i).Groups(2).Value) 'Next End Function #End Region End Class


