文章目录
- 前言
- 一、实现思路
- 1.你需要把视频转换成一帧一帧的图片。
- 2.把图片转换成字符串文件。
- 3.按照一定的时间差遍历打印字符串文件。
- 4.另起一个线程进行音乐的同步播放。
- 二、具体步骤
- 1.视频转图片
- 2.图片转字符串文件
- 3.循环遍历字符串文件
- 4.通过异步线程添加音乐播放
- 三、总结
前言
最近华强买瓜在B站大火,于是乎在闲暇之余,通过百度和各种学习,终于将这个视频通过Java形式展现出来了~
具体效果是这样的~
可以参考我发布在B站的视频进行预览~
华强买瓜【程序员复刻版】
一、实现思路
其实实现这个视频转文字输出的功能并不难,就是需要分成好几个环节去实现。
1.你需要把视频转换成一帧一帧的图片。
2.把图片转换成字符串文件。
3.按照一定的时间差遍历打印字符串文件。
4.另起一个线程进行音乐的同步播放。
二、具体步骤
首先准备好华强买瓜的原视频:
链接:https://pan.baidu.com/s/1HRAAzprVArxd692kUsKoPQ
提取码:p88i
1.视频转图片
通过AoaoPhoto Video to Picture Converter 将视频转换为图片。
软件下载地址:
视频转换工具
1)首先选择上面的load(视频导入目录)和下面的output folder(图片导出目录)
2)选择分辨率为1280*720,无效果,每秒十张图片,图片格式为PNG。
3)点击convert(转换)
操作如下图所示:
2.图片转字符串文件
通过Ascgen 2 批量将图片转换为字符串文件。
下载地址:图片转换字符串工具 1)选择批量转换
2)添加要转换的文件夹,以及转化后的文件夹位置,点击开始。
3.循环遍历字符串文件
接下来就到了代码的部分了~
long stime = System.currentTimeMillis();
// File file = new File(Hua.class.getClassLoader().getResource("input").getPath());
File file = new File("E:\\picture\\output\\OutputStrs");
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(files[i])));
String line ="";
String str = null;
while ((str = in.readLine()) != null) {
line += str+"\n";
}
System.out.println(line);
Thread.sleep(5);//打印的间隔时间
line = "";
//打印一张清空屏幕内容
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
in.close();
}
long etime = System.currentTimeMillis();
System.out.println("播放时长:"+(etime-stime)/1000);
4.通过异步线程添加音乐播放
1)音频转换:
音乐可以通过绘声绘影将MP4转换为音频。
转换教程:绘声绘影转换视频为音频 如果懒得转换,直接使用下面资源:
链接:https://pan.baidu.com/s/1cbFR4l9TOb7wJGJxvc5Bpw
提取码:77dd
2)音乐播放的相关代码:
public static void playMusic() throws Exception, IOException{
//1 获取你要播放的音乐文件
// File files = new File(Hua.class.getClassLoader().getResource("music").getPath());
// File file = files.listFiles()[0];
File file = new File("E:\\picture\\华强买瓜.wav");
//2、定义一个AudioInputStream用于接收输入的音频数据
AudioInputStream am;
//3、使用AudioSystem来获取音频的音频输入流(处理(抛出)异常)
am = AudioSystem.getAudioInputStream(file);
//4、使用AudioFormat来获取AudioInputStream的格式
AudioFormat af = am.getFormat();
//5、一个源数据行
SourceDataLine sd ;
//6、获取受数据行支持的音频格式DataLine.info
//DataLine.Info dl = new DataLine.Info(SourceDataLine.class, af);
//7、获取与上面类型相匹配的行 写到源数据行里 二选一
sd = AudioSystem.getSourceDataLine(af);//便捷写法
//sd = (SourceDataLine) AudioSystem.getLine(dl);
//8、打开具有指定格式的行,这样可以使行获得资源并进行操作
sd.open();
//9、允许某个数据行执行数据i/o
sd.start();
//10、写数据
int sumByteRead = 0; //读取的总字节数
byte [] b = new byte[320];//设置字节数组大小
//11、从音频流读取指定的最大数量的数据字节,并将其放入给定的字节数组中。
while (sumByteRead != -1) {//-1代表没有 不等于-1时就无限读取
sumByteRead = am.read(b, 0, b.length);//12、读取哪个数组
if(sumByteRead >= 0 ) {//13、读取了之后将数据写入混频器,开始播放
sd.write(b, 0, b.length);
}
}
//关闭
sd.drain();
sd.close();
}
3)异步线程:
思路其实就是把播放音乐的方法写在线程的run方法中,然后在打印直接就启动线程。
由于我这边直接将内容都写在一起了,并没有很好的规划代码结构。直接将完整源码贴在下面。
public class Hua extends Thread{
public static void main(String[] args) throws Exception {
new Hua().start();
long stime = System.currentTimeMillis();
// File file = new File(Hua.class.getClassLoader().getResource("input").getPath());
File file = new File("E:\\picture\\output\\OutputStrs");
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(files[i])));
String line ="";
String str = null;
while ((str = in.readLine()) != null) {
line += str+"\n";
}
System.out.println(line);
Thread.sleep(5);
line = "";
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
in.close();
}
long etime = System.currentTimeMillis();
System.out.println("播放时长:"+(etime-stime)/1000);
}
@Override
public void run() {
try {
playMusic();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void playMusic() throws Exception, IOException{
//1 获取你要播放的音乐文件
// File files = new File(Hua.class.getClassLoader().getResource("music").getPath());
// File file = files.listFiles()[0];
File file = new File("E:\\picture\\华强买瓜.wav");
//2、定义一个AudioInputStream用于接收输入的音频数据
AudioInputStream am;
//3、使用AudioSystem来获取音频的音频输入流(处理(抛出)异常)
am = AudioSystem.getAudioInputStream(file);
//4、使用AudioFormat来获取AudioInputStream的格式
AudioFormat af = am.getFormat();
//5、一个源数据行
SourceDataLine sd ;
//6、获取受数据行支持的音频格式DataLine.info
//DataLine.Info dl = new DataLine.Info(SourceDataLine.class, af);
//7、获取与上面类型相匹配的行 写到源数据行里 二选一
sd = AudioSystem.getSourceDataLine(af);//便捷写法
//sd = (SourceDataLine) AudioSystem.getLine(dl);
//8、打开具有指定格式的行,这样可以使行获得资源并进行操作
sd.open();
//9、允许某个数据行执行数据i/o
sd.start();
//10、写数据
int sumByteRead = 0; //读取的总字节数
byte [] b = new byte[320];//设置字节数组大小
//11、从音频流读取指定的最大数量的数据字节,并将其放入给定的字节数组中。
while (sumByteRead != -1) {//-1代表没有 不等于-1时就无限读取
sumByteRead = am.read(b, 0, b.length);//12、读取哪个数组
if(sumByteRead >= 0 ) {//13、读取了之后将数据写入混频器,开始播放
sd.write(b, 0, b.length);
}
}
//关闭
sd.drain();
sd.close();
}
}
4)运行及打包:
打包时右键项目选择export
选择jar file
选择jar包存放位置,以及起一个名称。
点击下一步-下一步,选择主函数所在的类。
点击完成,即可导出可执行jar包。
然后打开cmd,在程序所在位置 java -jar jar包名称即可运行~~
当然,你可以微调线程休眠时间(Thread.sleep(5);)来优化音乐播放和打印时的偏差,达到同步~
三、总结
通过这篇文章你可以实现各种基于视频的字符动画打印,发挥你的创意,创造更多好的作品吧~~