- 前言
- 核心代码
- 调用的抽象方法,包含逻辑处理
- 通过ffmpeg获取视频时长
- 合成gif图
- 删除文件夹
- 最终的调用
- 如果有更好的方式,请务必在评论区下留下你的想法,望多指教!
因为公司需求,需要把一段视频转换成gif图,具体需求是这样的,需要把一段视频按照他视频的长度,(0%,20%,40%,60%,80%,90%)每段截个3秒,然后组合成一个gif,面向谷歌编程没找到轮子,只能自己写了,途中代码也借鉴了一些别人的。希望看到的作者联系一下,给你标注一下。
话不多说上代码
这里是抽出来的核心代码
public static boolean spitVideo(String paletteFile,String timeStart,String filepath,String videoPath,String flag) throws IOException, InterruptedException {
String s="";
if(flag.equals("0")){
//竖
s="212*272";
}else {
//横
s="320*180";
}
//设置进程生成器的操作系统程序,方便理解一点,大体意思就是操作cmd然后执行命令
Process p = new ProcessBuilder()
.command(FFMPEG_PATH,
"-v", "warning",
//-ss 从第几秒开始
"-ss", timeStart,
//-t 共要多少时间
"-t", "3",
//-i 输入文件
"-i", videoPath,
//-r 表示一秒几帧
"-r", "15",
"-s", s,
//-vf 执行缩放 scale 视频宽度 -1表示保持长宽比
"-q:v", "2",
//-y 文件存在时直接覆盖不再询问
"-y", filepath+"/"+paletteFile+"%03d.png", "-vn")
.redirectError(new File("stderr.txt"))
.start();
logger.info("errorFilepath:"+filepath+"/"+paletteFile+"d.png");
boolean isComplete = p.waitFor(10, TimeUnit.SECONDS);
if(!isComplete){
logger.info("生成调色板出错");
throw new InterruptedException("生成调色板出错");
}
return isComplete;
}
调用的抽象方法,包含逻辑处理
算是通过一种取巧的方式,来实现,
因为ffmpeg 不能直接实现 所以取巧了一下
生成不同的文件夹A,B,C,D,E,F, 每个文件夹下面截取部分的视频帧
全部截取完之后 再把这些文件夹里的图片合成一个gif
算是实现了需求,如果有更好的方式,请各位大佬在评论区里指点一二
不同的时间点截取视频帧,面向谷歌 没有找到解决方案。
public static void getGif(int time,String directoryPath,String videoPath,String flag) throws IOException, InterruptedException {
//生成文件夹
File file=new File(directoryPath);
if (!file.isDirectory()){
file.setWritable(true,false);
file.mkdir();
}
String[] name={"A","B","C","D","E","F"};
//操作ffmpeg生成gif图片
Boolean p=false;
String[] t=new String[6];
t[0]=String.valueOf(3);
t[1]= String.valueOf((time*0.2));
t[2]= String.valueOf((time*0.4));
t[3]= String.valueOf((time*0.6));
t[4]= String.valueOf((time*0.8));
t[5]= String.valueOf((time*0.9));
for (int i = 0; i < 6; i++) {
p=spitVideo(name[i],t[i],directoryPath,videoPath,flag);
}
if(p==true){
logger.info("截取视频帧已完成!");
}else {
logger.info("截取视频帧未完成!");
}
}
通过ffmpeg获取视频时长
这段代码 忘记是从哪拿过来的了 原作者联系我,谢谢
public static int getVideoTime(String video_path, String ffmpeg_path) {
List commands = new java.util.ArrayList();
commands.add(ffmpeg_path);
commands.add("-i");
commands.add(video_path);
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commands);
final Process p = builder.start();
//从输入流中读取视频信息
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
//从视频信息中解析时长
String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s";
Pattern pattern = Pattern.compile(regexDuration);
Matcher m = pattern.matcher(sb.toString());
if (m.find()) {
int time = getTimelen(m.group(1));
logger.info(video_path+",视频时长:"+time+", 开始时间:"+m.group(2)+",比特率:"+m.group(3)+"kb/s");
System.out.println(video_path+",视频时长:"+time+", 开始时间:"+m.group(2)+",比特率:"+m.group(3)+"kb/s");
return time;
}
String regexVideo = "Video: (.*?), (.*?,.*?), (.*?)[,\s]";
Pattern pattern1 = Pattern.compile(regexVideo);
Matcher x = pattern1.matcher(sb.toString());
if (x.find()) {
System.out.println("编码格式 ===" + x.group(1));
System.out.println("视频格式 ===" + x.group(2));
System.out.println(" 分辨率 == =" + x.group(3));
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
合成gif图
public synchronized static void jpgToGif(String pic[], String newPic, int playTime) {
try {
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.setRepeat(0);
e.start(newPic);
BufferedImage src[] = new BufferedImage[pic.length];
for (int i = 0; i < src.length; i++) {
e.setDelay(playTime); //设置播放的延迟时间
src[i] = ImageIO.read(new File(pic[i])); // 读入需要播放的jpg文件
e.addframe(src[i]); //添加到帧中
}
e.finish();
} catch (Exception e) {
System.out.println( "jpgToGif Failed:");
e.printStackTrace();
}
}
删除文件夹
public static boolean deletefile(String delpath) throws Exception {
try {
File file = new File(delpath);
// 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true
if (!file.isDirectory()) {
file.delete();
} else if (file.isDirectory()) {
String[] filelist = file.list();
for (int i = 0; i < filelist.length; i++) {
File delfile = new File(delpath + "/" + filelist[i]);
if (!delfile.isDirectory()) {
delfile.delete();
System.out.println(delfile.getAbsolutePath() + "删除文件成功");
} else if (delfile.isDirectory()) {
deletefile(delpath + "/" + filelist[i]);
}
}
System.out.println(file.getAbsolutePath()+"删除成功");
file.delete();
}
} catch (FileNotFoundException e) {
System.out.println("deletefile() Exception:" + e.getMessage());
}
return true;
}
最终的调用
FFMPEG_PATH 为ffmpeg的调用绝对路径
不知道FFMPEG的,可以去谷歌一下。
windows的话直接使用 去下载ffmpeg(如果有小伙伴实在不知道。在评论区说,我会提供下载包),图方便就不配置什么系统变量
//FFMPEG_PATH 为ffmpeg的调用绝对路径 D:ffmpegbinffmpeg
int videolength=getVideoTime(videoPath, FFMPEG_PATH);
getGif(videolength,courseFile+"/"+pngfilePath,videoPath,upload.getFlag());
//读取文件
File pngFile = new File(courseFile+"/"+pngfilePath);
File [] files = pngFile.listFiles();
String[] png=new String[files.length];
for (int z = 0; z < files.length; z++){
png[z]=String.valueOf(files[z]);
}
jpgToGif(png,gifPath,100);
//完成后删除图片文件夹
boolean x=FileUtils.deletefile(courseFile+"/"+pngfilePath);
if(!x){
logger.info("文件夹删除失败!");
}else {
logger.info("文件夹删除成功!");
}
如果有更好的方式,请务必在评论区下留下你的想法,望多指教!


