起因是這樣的
一天,本人在B站客戶端緩存了一個視頻,用于學習參考等學術交流,但是視頻和音頻卻是分開且通過Win Hex查看發現文件頭含有9個“30”,想到一個個手動刪字節不如讓程序取代,便有了本文章
這一篇文章發布之前,其實早在5個月以前就完成了代碼
代碼流程
不同語言可以參考流程來做(本教程介紹Console版本的單文件處理)
1、獲取ffmpeg的路徑
如題,我們首先需要ffmpeg,可以去網上隨便什么地方下一個編譯好的ffmpeg放在程序文件夾下,然后獲取ffmpeg的路徑
Dim ff As String = Path.GetDirectoryName(Process.GetCurrentProcess.MainModule.FileName) & "\ffmpeg.exe"
2、獲取 想要處理的 文件
Console.WriteLine("輸入要轉換的文件路徑:")
Dim arg As String
arg = Console.ReadLineIf IO.File.Exists(arg) = False ThenConsole.WriteLine("文件不存在!")Continue Do
End IfDim f As New FileStream(arg, FileMode.Open)
3、定義音頻和視頻判定字節
(這里說明一下,絕大部分B站客戶端下載的視頻是mpg格式的視頻,文件內部二進制數據會包含Video或Sound等字符來標記是視頻還是音頻,但是少部分格式不清楚,因此本程序保留了未知格式,可以降低錯判率)
Dim vid As Byte() = {&H56, &H69, &H64, &H65, &H6F}
Dim sod As Byte() = {&H53, &H6F, &H75, &H6E, &H64}Dim flag As Boolean = False
f.Position = 0For i = 0 To f.Length - 1Dim buf = f.ReadByteDim array1(3) As ByteIf buf = &H53 Thenf.Read(array1, 0, 4)If CompareByte(sod, sod(0), array1) ThenConsole.WriteLine("此文件是音頻,輸入""/""以重新輸入")flag = TrueExit ForEnd IfElseIf buf = &H56 Then 'If buf(0) = &H56 Thenf.Read(array1, 0, 4)If CompareByte(vid, vid(0), array1) ThenConsole.WriteLine("此文件是視頻,輸入""/""以重新輸入")flag = TrueExit ForEnd IfEnd If
NextIf flag = False ThenConsole.WriteLine("輸入的格式可能不準確,除非你知道你自己在做什么!輸入""/""以重新輸入")
End If
匹配字節
Function CompareByte(OriginalByte As Byte(), firstByte As Byte, LastBytes As Byte())If firstByte = OriginalByte(0) ThenFor i = 0 To LastBytes.Count - 1If LastBytes(i) <> OriginalByte(i + 1) ThenReturn FalseEnd IfNextReturn TrueElseReturn FalseEnd If
End Function
這里解釋下為何要使用這一種方法來匹配文件類型……
因為如果你直接讀取所有的音頻文件到內存再轉成Array,且不說上限有多少,代碼會比這個復雜,而且占用大量系統資源,小一點的音頻還好,如果是4K視頻,內存都要炸翻天。
所以我們使用字節流的方式,f.ReadByte一次,字節讀取位置就+1,但凡匹配到0x56,0x53的就開始匹配后面4位是否一致,如果一致了,就按對應格式告訴用戶這個是視頻還是音頻。
4、讓用戶輸入轉換后的名稱
f.Position = 0
Console.WriteLine("輸入轉換后文件名稱,新文件保存于原文件同一個目錄下,請加上后綴!例如as.mp4")Dim newfname As String
newfname = Console.ReadLine
If newfname = "/" ThenContinue Do
End If
Dim newpath As String = Path.GetDirectoryName(arg) & "\" & newfname
Dim w As New FileStream(newpath, FileMode.Create)Dim count As Integer = f.Length
5、詢問用戶刪多少個字節
一般客戶端為9個,UWP(不支持版本)是3個而且音視頻合體
Console.WriteLine("輸入刪除視頻前多少個byte,建議查看WinHex")
Dim start As Integer = CInt(Console.ReadLine())For i = 0 To start - 1f.ReadByte()
NextFor i = 0 To count - start - 1w.WriteByte(f.ReadByte)
Next
w.Close()
f.Close()Process.Start(ff, "-i " & newfname & " " & newpath)Console.WriteLine("轉換成功!")
錯誤處理就不做了,獲取ffmpeg的數據流太麻煩了
敬告
注意,此方法僅用于學習和參考,請勿用于非法用途!!!