栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 实现分段截取视频 生成gif图 使用ffmpeg操作

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 实现分段截取视频 生成gif图 使用ffmpeg操作

Java 实现分段截取视频 生成gif图 使用ffmpeg操作
  • 前言
    • 核心代码
    • 调用的抽象方法,包含逻辑处理
    • 通过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("文件夹删除成功!");
        }
如果有更好的方式,请务必在评论区下留下你的想法,望多指教!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/348951.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号