失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > C#:将blibli缓存文件批量转换为MP4文件

C#:将blibli缓存文件批量转换为MP4文件

时间:2021-09-21 07:32:20

相关推荐

C#:将blibli缓存文件批量转换为MP4文件

C#:将blibli缓存文件批量转换为MP4文件

一、概述:我们主要处理哔哩哔哩缓存文件夹每一集中的audio.m4s和video.m4s以及entry.json文件,audio.m4s内容是每一集的音频文件,而vedio.m4s内容是视频的画面,也就是说哔哩哔哩将一个视频分解为音频部分和视频画面两部分,而我们要做的将这两部分合成并转换为MP4格式的文件,那么这个MP4文件到底取什么名字呢?这是就需要entry.json文件了,这里面存放的是视频每一集的基本信息,通过这个文件里面的信息来给出输出文件命名。

二、实现步骤:

1.递归访问指定文件目录找出每一集的audio.4ms文件、video.4ms文件以及entry.json文件

2.获取entry.json中的视频信息(视频集数名字)

3.调用进程ffmpeg(程序)将audio.4ms文件、video.4ms文件合成MP4文件

具体步骤:

1.递归找出所有需要文件的路径:

var cap=new List<string>(){};//定义的保存所有文件路径的容器

var cap1=new List<string>(){};

cap=GetAllFilesFromPath(inpath,true);//保存所有的audio.4ms文件和video.4ms文件路径

cap1=GetAllFilesFromPath(inpath,"*entry.json",true);//保存所有entry.json文件路径

具体代码如下:

public static bool ExistsDirectory(string direName){return System.IO.Directory.Exists(direName);}// 递归获取某一目录下的符合条件的所有文件 public static List<string> _GetAllFilesFromPath(string path, string filter, bool DiGui = true)//这里DiGui为true代表使用递归调用{List<string> files = new List<string>();if (!ExistsDirectory(path))//如果该文件目录存在return files;if (DiGui){string[] dirs = Directory.GetDirectories(path);//得到子目录foreach (var str in dirs)files.AddRange(GetAllFilesFromPath(str, filter, DiGui));}string[] tempfiles = Directory.GetFiles(path, filter);files.AddRange(tempfiles);return files;}public static List<string> GetAllFilesFromPath(string path, string filters, bool DiGui = true){List<string> files = new List<string>();if (!string.IsNullOrWhiteSpace(filters)){foreach (var item in filters.Split(new Char[] { ',', '|' }, StringSplitOptions.RemoveEmptyEntries)){var _files = _GetAllFilesFromPath(path, item, DiGui);foreach (var _file in _files){files.Add(_file);}}return files;}elsereturn GetAllFilesFromPath(path, DiGui);}// 递归获取某一目录下的mp4所有文件public static List<string> GetAllFilesFromPath(string path, bool DiGui = true){return GetAllFilesFromPath(path, "*.m4s", DiGui);}

2.通过访问每一集的entry.json文件,获得输出文件名

a.OutFile=outpath+@"\"+GetFileJson(cap1[i]);//这里的a.outFile就是输出路径和文件名,GetFileJson(cap1[i])就是获取每个entry文件中的part部分后面的字符串名,至于我为啥要写字符串处理函数GetFileJson(cap1[i])呢?那是因为我的SharpDevelop 5.1软件无法引入处理.json的文件,所以就自己写了一个。

至于.json文件里面到底有些啥呢?我们打开一个来看看

{"media_type":2,"has_dash_audio":true,"is_completed":true,"total_bytes":6436658,"downloaded_bytes":6436658,"title":"ITZY新曲Mafia In the morning舞蹈版MV公开","type_tag":"16","cover":"http:\/\/\/bfs\/archive\/8a5f741fd079af38481b177877ec4f0350d80651.jpg","video_quality":16,"prefered_video_quality":16,"guessed_total_bytes":0,"total_time_milli":182101,"danmaku_count":85,"time_update_stamp":1620308481186,"time_create_stamp":1620308477092,"can_play_in_advance":true,"interrupt_transform_temp_file":false,"quality_pithy_description":"360P","quality_superscript":"","cache_version_code":6235200,"preferred_audio_quality":0,"audio_quality":0,"avid":417942654,"spid":0,"seasion_id":0,"bvid":"BV1SV41177mc","owner_id":16720403,"page_data":{"cid":334369010,"page":1,"from":"vupload","part":"MV","link":"","vid":"","has_alias":false,"tid":193,"width":3840,"height":2160,"rotate":0,"download_title":"视频已缓存完成","download_subtitle":"ITZY新曲Mafia In the morning舞蹈版MV公开 MV"}}

而我主要将part后面部分截取了下来也就是MV,即将MV作为文件的一个输出名。

代码如下:

//获取文件名字public static string GetFileJson(string filepath){string json = string.Empty;string c="";using (FileStream fs = new FileStream(filepath, FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite)){using (StreamReader sr = new StreamReader(fs, Encoding.GetEncoding("UTF-8"))){json = sr.ReadLine().ToString();int j=0;for(int i=0;i<json.Length;i++){if(json[i]=='"')if(json[i+1]=='p')if(json[i+2]=='a')if(json[i+3]=='r')if(json[i+4]=='t'){j=i;j=j+8;break;}}while(json[j]!='"'){c=c+json[j];j++;}c=c+".mp4";}}return c;}

3.调用ffmpeg文件合成.mp4文件

a.ConvertVideo();//调用ffmpeg文件

代码如下:

public class CFfmpeg{public static string ffmpegtool = @"D:\ffmpeg\bin\ffmpeg.exe";//ffmpeg.exe文件下载路径public static string outFile = @"D:\ffmpeg\bin\972637678\c_328764377\16\output2.mp4";//默认输出路径public static string sourceFile = @"D:\ffmpeg\input\417942654\c_334370165\16\audio.m4s";//默认音频路径public static string sourceFile1 = @"D:\ffmpeg\input\417942654\c_334370165\16\video.m4s";//默认视频画面路径public string SourceFile{set{sourceFile=value;}get{return sourceFile;}}public string SourceFile1{set{sourceFile1=value;}get{return sourceFile1;}}public string OutFile{set{outFile=value;}get{return outFile;}}public void ConvertVideo(){Process p = new Process();//建立外部调用线程p.StartInfo.FileName = ffmpegtool;//要调用外部程序的绝对路径//传入FFMPEG的参数string strArg = " -i " + sourceFile +" -i "+sourceFile1 + " -codec copy "+outFile ;p.StartInfo.Arguments = strArg;p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中p.StartInfo.CreateNoWindow = false;//不创建进程窗口p.ErrorDataReceived += new DataReceivedEventHandler(Output);//这里是FFMPEG输出流的时候产生的事件,这里是把流的处理过程转移到下面的方法中p.Start();//启动线程p.BeginErrorReadLine();//开始异步读取p.WaitForExit();//阻塞等待进程结束p.Close();//关闭进程p.Dispose();//释放资源}private void Output(object sendProcess, DataReceivedEventArgs output){if (!String.IsNullOrEmpty(output.Data)){Console.WriteLine(output.Data); }}}

三、完整代码

/** Created by SharpDevelop.* User: 12875* Date: /4/23* Time: 14:24* * To change this template use Tools | Options | Coding | Edit Standard Headers.*//*1.如何调用外部命令。(解决)* 2.如何解析集数(entry.json)文件中。* 3.连续的递归查找要转换的每一集。* * * */using System;using System.Linq;using System.Diagnostics;using System.IO;using System.Text;using System.Collections.Generic;//\ffmpeg.exe -i video.m4s -i audio.m4s -codec copy Output.mp4namespace c0423{class Program{//获取文件名字public static string GetFileJson(string filepath){string json = string.Empty;string c="";using (FileStream fs = new FileStream(filepath, FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite)){using (StreamReader sr = new StreamReader(fs, Encoding.GetEncoding("UTF-8"))){json = sr.ReadLine().ToString();int j=0;for(int i=0;i<json.Length;i++){if(json[i]=='"')if(json[i+1]=='p')if(json[i+2]=='a')if(json[i+3]=='r')if(json[i+4]=='t'){j=i;j=j+8;break;}}while(json[j]!='"'){c=c+json[j];j++;}c=c+".mp4";}}return c;}public static bool ExistsDirectory(string direName){return System.IO.Directory.Exists(direName);}// 递归获取某一目录下的符合条件的所有文件 public static List<string> _GetAllFilesFromPath(string path, string filter, bool DiGui = true)//这里DiGui为true代表使用递归调用{List<string> files = new List<string>();if (!ExistsDirectory(path))//如果该文件目录存在return files;if (DiGui){string[] dirs = Directory.GetDirectories(path);//得到子目录foreach (var str in dirs)files.AddRange(GetAllFilesFromPath(str, filter, DiGui));}string[] tempfiles = Directory.GetFiles(path, filter);files.AddRange(tempfiles);return files;}public static List<string> GetAllFilesFromPath(string path, string filters, bool DiGui = true){List<string> files = new List<string>();if (!string.IsNullOrWhiteSpace(filters)){foreach (var item in filters.Split(new Char[] { ',', '|' }, StringSplitOptions.RemoveEmptyEntries)){var _files = _GetAllFilesFromPath(path, item, DiGui);foreach (var _file in _files){files.Add(_file);}}return files;}elsereturn GetAllFilesFromPath(path, DiGui);}// 递归获取某一目录下的mp4所有文件public static List<string> GetAllFilesFromPath(string path, bool DiGui = true){return GetAllFilesFromPath(path, "*.m4s", DiGui);}//合成音频文件public class CFfmpeg{public static string ffmpegtool = @"D:\ffmpeg\bin\ffmpeg.exe";//ffmpeg.exe文件下载路径public static string outFile = @"D:\ffmpeg\bin\972637678\c_328764377\16\output2.mp4";//默认输出路径public static string sourceFile = @"D:\ffmpeg\input\417942654\c_334370165\16\audio.m4s";//默认音频路径public static string sourceFile1 = @"D:\ffmpeg\input\417942654\c_334370165\16\video.m4s";//默认视频画面路径public string SourceFile{set{sourceFile=value;}get{return sourceFile;}}public string SourceFile1{set{sourceFile1=value;}get{return sourceFile1;}}public string OutFile{set{outFile=value;}get{return outFile;}}public void ConvertVideo(){Process p = new Process();//建立外部调用线程p.StartInfo.FileName = ffmpegtool;//要调用外部程序的绝对路径//传入FFMPEG的参数string strArg = " -i " + sourceFile +" -i "+sourceFile1 + " -codec copy "+outFile ;p.StartInfo.Arguments = strArg;p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中p.StartInfo.CreateNoWindow = false;//不创建进程窗口p.ErrorDataReceived += new DataReceivedEventHandler(Output);//这里是FFMPEG输出流的时候产生的事件,这里是把流的处理过程转移到下面的方法中p.Start();//启动线程p.BeginErrorReadLine();//开始异步读取p.WaitForExit();//阻塞等待进程结束p.Close();//关闭进程p.Dispose();//释放资源}private void Output(object sendProcess, DataReceivedEventArgs output){if (!String.IsNullOrEmpty(output.Data)){Console.WriteLine(output.Data); }}}public static void Main(string[] args){Console.WriteLine("Hello World!");string inpath=@"D:\ffmpeg\input";//要递归访问的文件目录默认路径string outpath=@"D:\ffmpeg\output";//生成文件输出目录默认路径var cap=new List<string>(){};var cap1=new List<string>(){};if(args.Length==0){inpath=@"D:\ffmpeg\input";outpath=@"D:\ffmpeg\output";}else if(args.Length==2){inpath=args[0];outpath=args[1];}cap=GetAllFilesFromPath(inpath,true);//保存路径cap1=GetAllFilesFromPath(inpath,"*entry.json",true);//保存的是文件名CFfmpeg a=new CFfmpeg();for(int j=0;j<cap1.Count;j++){Console.WriteLine(GetFileJson(cap1[j]));}for(int i=0;i<cap1.Count;i++){a.SourceFile1=cap[2*i];a.SourceFile=cap[2*i+1];Console.WriteLine(cap[2*i]);Console.WriteLine(cap[2*i+1]);a.OutFile=outpath+@"\"+GetFileJson(cap1[i]);a.ConvertVideo();}Console.Write("Press any key to continue . . . ");Console.ReadKey(true);}}}

四、效果显示

如果觉得《C#:将blibli缓存文件批量转换为MP4文件》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。