起因是这样的
一天,本人在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.ReadLine
If IO.File.Exists(arg) = False Then
Console.WriteLine("文件不存在!")
Continue Do
End If
Dim 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 = 0
For i = 0 To f.Length - 1
Dim buf = f.ReadByte
Dim array1(3) As Byte
If buf = &H53 Then
f.Read(array1, 0, 4)
If CompareByte(sod, sod(0), array1) Then
Console.WriteLine("此文件是音频,输入""/""以重新输入")
flag = True
Exit For
End If
ElseIf buf = &H56 Then 'If buf(0) = &H56 Then
f.Read(array1, 0, 4)
If CompareByte(vid, vid(0), array1) Then
Console.WriteLine("此文件是视频,输入""/""以重新输入")
flag = True
Exit For
End If
End If
Next
If flag = False Then
Console.WriteLine("输入的格式可能不准确,除非你知道你自己在做什么!输入""/""以重新输入")
End If
匹配字节
Function CompareByte(OriginalByte As Byte(), firstByte As Byte, LastBytes As Byte())
If firstByte = OriginalByte(0) Then
For i = 0 To LastBytes.Count - 1
If LastBytes(i) <> OriginalByte(i + 1) Then
Return False
End If
Next
Return True
Else
Return False
End 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 = "/" Then
Continue 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 - 1
f.ReadByte()
Next
For i = 0 To count - start - 1
w.WriteByte(f.ReadByte)
Next
w.Close()
f.Close()
Process.Start(ff, "-i " & newfname & " " & newpath)
Console.WriteLine("转换成功!")
错误处理就不做了,获取ffmpeg的数据流太麻烦了
敬告
注意,此方法仅用于学习和参考,请勿用于非法用途!!!