最近在用B站移动端帮助老婆大人找一些视频,并缓存到本地。结果老婆大人要求把视频拷出来,想保存下来。方便以后直接观看。
结果打开B站移动端APP的保存的视频地方,打算把视频拷出来,看一下视频能否正常播放。结果悲剧了。发现其文件格式如下。安卓移动端的路径如下:
进入安卓根目录,再进安卓Android文件夹下面的data文件夹,在里面找到tv.danmaku.bili的文件夹,再进入就能找到你所下载视频的文件夹了。
补充一下,下面的图是通过handshaker的软件,方面电脑直接查看或管理安卓文件。非常方便。个人非常推荐。
进入文件夹84810483下面,看到的文件价格如下,这是我下载的文件截图。addio.m4s这个文件的视频是音频文件,而video.m4s文件这是对应的视频文件。下面先来一波操作。先手动把文件修改一下。比如把addio.m4s变化成addio.mp3,那么对应的把video.m4s变成video.mp4。然后用播放器打开mp3文件。可以的正常播放。
我们再来打开mp4文件。哈哈,😁,悲剧了。没有声音。怎么办??????
然而作为程序员,怎么能不知道怎么办呢?这不是造火箭啊!!!!
打算偷个懒,去找个视频转换的软件来处理,把音频文件和视频文件合并,这样就大功告成了。然而理想很美好,现实很骨感啊!
这个时候我们的伟大的ffmpeg登场,如果读者不知道ffmpeg是什么,可以自行去百度。
下面就不废话了。直接给出答案。
简约的答案:前提示你的电脑上已经安装配置好ffmpeg。(如果没有安装,请接着看下面的ffmpeg安装。),然后用下面的命令。
ffmpeg -i audio.mp3 -i video.mp4 -vcodec copy -acodec copy output.mp4
执行上面的命令后会输出out的文件。然后用播放器打开,正常是图像和声音同步,完美。
当然,上面的已经解决了相对的少量的转换,如果像下面的这么多的文件,难道手动一个一个改文件名,然后用命令一个一个执行转换。那不是疯了。下面就有请答案2上场。答案2上场前先教大家安装ffmpeg。我的是Mac操作系统,只能暂时以此来说明,对应的window环境如何安装大家也可以百度一下。
Mac环境安装ffmpeg
1. lame 下载解压缩 https://pan.baidu.com/s/1cyrvJ3yMfQPO7eGHpcRtJw
密码:4q0w 进入目录后依次执行,为了避免权限问题直接加sudo
1.1 ./configure
1.2 sudo make
1.3 sudo make install
2. 下载解压缩
ffmpeg连接 https://pan.baidu.com/share/init?surl=zXad879R669zJLZ5gf6aGw
密码:f94b
进入目录后依次执行
2.1 ./configure --enable-libmp3lame
2.2 sudo make
2.3 sudo make install
安装好之后关掉终端,重新打开输入 ffmpeg -version 成功后的信息如下。
而如果不能识别ffmpeg命令。则是有可能是环境没有配置,我安装的时候就是出现了这个情况。
环境的配置如下:使用命令打开.bash_profile文件,添加路径。
sudo vim .bash_profile
添加:export PATH=/usr/local/bin:$PATH
保存,再用命令: source .bash_profile使配置修改生效。
接着下面回到答案2。如果有很多文件,我们使用代码来进行批量重名。因为涉及比较多的操作步骤。步骤如下:
步骤1:批量修改文件个属性。即修改文件的格式。
调用以下方法前
调用重名方法后:
从调用结果上面来看。结果是有效的。文件全部重新命名并且改了格式
方法如下:扫描文件和修改文件名字
public static void scanFileAndReviseName(String dir,ExecutorService executor) {
File file = new File(dir);
if (file.isDirectory()) {//判断File对象对应的目录是否存在
File[] ss = file.listFiles();//获得目录下所有的文件名
for (File s : ss) {//循环遍历,依次输出
if (s.isFile()) {
if (s.getName().equals("audio.m4s")) {
rename(s, "audio.mp3");
}
if (s.getName().equals("video.m4s")) {
rename(s, "video.mp4");
}
} else {
scanFileAndReviseName(s.getAbsolutePath(),executor);
}
}
}
}
public static boolean rename(final File file, final String newName) {
// file is null then return false
if (file == null) return false;
// file doesn't exist then return false
if (!file.exists()) return false;
// the new name is space then return false
// the new name equals old name then return true
if (newName.equals(file.getName())) return true;
File newFile = new File(file.getParent() + File.separator + newName);
// the new name of file exists then return false
return !newFile.exists()
&& file.renameTo(newFile);
}
步骤2. 按照最外面的文件名称,再次重命名文件,如对应的295,296,分别要改成295.mp3,295.mp4,296.mp3,296.mp4, 这是为了方便后面的皮批量合成视频。
public static void useParentName(String dir) {
File file = new File(dir);
if (file.isDirectory()) {
//判断File对象对应的目录是否存在
File[] ss = file.listFiles();//获得目录下所有的文件
for (File s : ss) {
//循环遍历,依次输出
if (s.isFile()) {
String name = getParentFileName(s.getAbsolutePath());//抽取父类的文件名
String audio = name+ ".mp3";
String video = name+ ".mp4";
if (s.getName().equals("audio.mp3")) {
System.out.println(s.getAbsoluteFile() + " && 文件名字:" + s.getName());
rename(s, audio);
}
if (s.getName().equals("video.mp4")) {
System.out.println(s.getAbsoluteFile() + " && 文件名字:" + s.getName());
rename(s, video);
}
} else {
useParentName(s.getAbsolutePath());
}
}
}
}
public static String getParentFileName(@NotNull String path){
String name = "";
String[] sArray=path.split("/") ;
if (sArray.length>5){
name = sArray[5]; //根据日志文件的格式视情况来获取
}
return name;
}
运行后的效果图如下:可以看到里面的文件夹名字和外边的集数对应上了。
步骤3.我们需要把文件移到和249平行的目录下面。这里就涉及到在Java里面调用命令。经过我自己验证后,是可以在java里面这样执行命令的。效果图如下
该方法如下:
public static void moveFile(String source,String dest) {
Process process = null;
String command = "mv " + " " + source+ " " + dest;
System.out.println(" ***** cmd "+ command);
List<String> processList = new ArrayList<String>();
try {
process = Runtime.getRuntime().exec(command);
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = input.readLine()) != null) {
processList.add(line);
}
input.close();
} catch (IOException e) {
e.printStackTrace();
}
for (String line : processList) {
System.out.println(line);
}
}
步骤4. 调用ffmpeg命令来执行合成文件,因为合成文件是个耗时操作,因为需要建立一个线程,放到线程里面去执行。执行后的效果如下
使用了如下的方法,代码如下
ExecutorService executor = Executors.newFixedThreadPool(30);
MixFile("/Users/lulanqin/Desktop/84810483/",executor);///Users/lulanqin/Desktop/84810483 是自己放文件的地方
//执行混合音视频的方法
public static void MixFile(String dir,ExecutorService executor) {
File file = new File(dir);
if (file.isDirectory()) {
//判断File对象对应的目录是否存在
File[] ss = file.listFiles();//获得目录下所有的文件
for (File s : ss) {
//循环遍历,依次输出
if (s.isFile()) {
if (s.getName().contains("mp3")) {
String temp = s.getAbsolutePath();
int index = temp.lastIndexOf(".m");
if (index>0){
String sbu = temp.substring(0,index);
String sound1 = sbu+".mp3";
String video1 = sbu+".mp4";
String out = sbu+"_1.mp4";
executor.submit(new MyRunnable(sound1,video1,out));
}
}
}
}
}
}
//执行的线程
public static class MyRunnable implements Runnable{
String sound1,video1,out;
public MyRunnable( String mp3, String mp4, String outPut) {
this.sound1 = mp3;
this.video1 = mp4;
this.out = outPut;
}
@Override
public void run() {
transFormMp4Video(sound1,video1,out);
}
}
//最核心的方法,启动命令来合成视频并输出视频。
public static void transFormMp4Video(String mp3, String mp4, String outPut) {
StringBuilder stringBuilder = new StringBuilder();
try {
String cmd = "ffmpeg -i " + mp3 + " -i " + mp4 + " -vcodec copy -acodec copy " + outPut + "";
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}