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;
            }
            else
                return 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:\/\/i0.hdslb.com\/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: 2021/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.mp4
namespace c20210423
{
	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;
            }
            else
                return 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);
		
	}
	}
}

四、效果显示

如何把dll转换成动态库让java调用 dll文件怎么转化为mp4_json

如何把dll转换成动态库让java调用 dll文件怎么转化为mp4_ffmpeg_02