zoukankan      html  css  js  c++  java
  • JAVA调用FFMpeg进行转码等操作

    直接上代码:

    public abstract class FFmpegUtils {
    
        FFmpegUtils ffmpegUtils;
        
        int timeLengthSec = 1;
        
        String timeLength = "";
        
        Pattern pattern = Pattern.compile("Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s");
        String frameRegexDuration = "size=([\s\S]*) time=(.*?) bitrate=([\s\S]*) speed=(.*?)x";
        String videoframeRegexDuration = "frame=([\s,\d]*) fps=(.*?) q=(.*?) size=([\s\S]*) time=(.*?) bitrate=([\s\S]*) speed=(.*?)x";
        Pattern framePattern = Pattern.compile(frameRegexDuration);
    
        public static void main(String[] args){
            String target = "";
    /*        try {
                target = extractAsyn("D:\ffmpeg4.2\bin\ffmpeg.exe", 
                        "-y   -f   image2   -ss   1   -t   0.001   -s   640x480", 
                        "E:\迅雷下载\电影\test.avi", 
                        "E:\迅雷下载\电影\test.avi.jpg");
                System.out.println(target);
            } catch (Throwable e) {
                System.err.println(e.getMessage());
            }
            */
            try {
                
                 new FFmpegUtils() {
                    @Override
                    public void dealLine(String line) {
                        System.out.println(line);
                        if(timeLength == null || timeLength.equals("")) {
                            Matcher m = pattern.matcher(line.trim());
                            if (m.find()) {
                                timeLength = m.group(1);
                                if(timeLength!=null){
                                    timeLengthSec = FFVideoUtil.getTimelen(timeLength);
                                }
                                System.out.println(timeLength+"||"+timeLengthSec);
                            }
                        }
    
                        //获取视频信息
                        Matcher matcher = framePattern.matcher(line);
                        if(matcher.find()){
                            try {
                                String execTimeStr = matcher.group(2);
                                int execTimeInt = FFVideoUtil.getTimelen(execTimeStr);
                                double devnum = FFBigDecimalUtil.div(execTimeInt,timeLengthSec,5);
                                double progressDouble = FFBigDecimalUtil.mul(devnum,100);
                                System.out.println("execTimeInt:"+execTimeInt+"&,devnum:"+devnum+"&,progressDouble:"+progressDouble);
                            } catch (IllegalAccessException e) {
                                System.err.println("获取输出流异常:"+e.getMessage());
                            }
                        }
                    }
                    
                    @Override
                    public void dealStream(Process process) {
                         if (process == null) {
                                return;
                            }
                            // 处理InputStream的线程
                            new Thread() {
                                @Override
                                public void run() {
                                    BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
                                    String line = null;
                                    try {
                                        while ((line = in.readLine()) != null) {
                                            //logger.info("output: " + line);
                                            dealLine(line);
                                        }
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    } finally {
                                        try {
                                            in.close();
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            }.start();
                            // 处理ErrorStream的线程
                            new Thread() {
                                @Override
                                public void run() {
                                    BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                                    String line = null;
                                    try {
                                        while ((line = err.readLine()) != null) {
                                            dealLine(line);
                                        }
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    } finally {
                                        try {
                                            err.close();
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            }.start();
                    }
                }.processVideoSync("D:\ffmpeg4.2\bin\ffmpeg.exe", 
                        " -f|mp3", 
                        "E:\迅雷下载\电影\test.avi", 
                        "E:\迅雷下载\电影\test.avi.mp3");
                System.out.println(target);
            } catch (Throwable e) {
                System.err.println(e.getMessage());
            }
            
        }
        
        //异步 适合抽帧等快速的操作
        public static String extractAsyn(
                String ffmpegPath,String cmdParam,
                String sourceFile,String targetFile) 
                        throws Throwable {
                
                Runtime runtime = Runtime.getRuntime();
                Process proce = null;
                // 视频截图命令,封面图。 8是代表第8秒的时候截图
                String cmd = "";
                String cut = ffmpegPath +" -i "+ sourceFile +"  "+ cmdParam +"  "+ targetFile;
                String cutCmd = cmd + cut;
                proce = runtime.exec(cutCmd);
                proce.getOutputStream();
                System.out.println("抽帧命令是:"+cut);
                return targetFile;
        }
        
        
        public static boolean checkfile(String path) {
            File file = new File(path);
            if (!file.isFile()) {
                return false;
            }
            return true;
        }
    
        //异步处理
        public boolean processVideoSync(String ffmpegPath,String cmdParam,
                String sourceFile,String targetFile) {
    
            // 文件命名
            List<String> commond = new ArrayList<String>();
            commond.add(ffmpegPath);
            commond.add("-i");
            commond.add(sourceFile);
            commond.addAll(Arrays.asList(cmdParam.trim().split("\|")));
            commond.add(targetFile);
            
            if(new File(targetFile).exists()) {
                new File(targetFile).delete();
            }
            
            String cmds = ""; 
            for (String cmd : commond) {
                cmds = cmds + " " + cmd;
            }
            System.out.println("执行命令参数为:" + cmds);
            try {
                // 调用线程命令进行转码
                Process videoProcess = new ProcessBuilder(commond).redirectErrorStream(true).start();
                //new PrintStream(videoProcess.getInputStream()).start();          
                //videoProcess.waitFor();
                /*new InputStreamReader(videoProcess.getErrorStream());
                BufferedReader stdout = new BufferedReader(new InputStreamReader(videoProcess.getInputStream()));
                String line;
                while ((line = stdout.readLine()) != null) {
                     dealLine(line);
                }*/
                dealStream(videoProcess);
                videoProcess.waitFor();
                
                
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        //处理输出流
        public abstract void dealLine(String line);
        public abstract void dealStream(Process process );
    }
    FFmpegUtils.java
    @Component
    public class ProgressService extends FFmpegUtils{
    
        public static Logger logger = LoggerFactory.getLogger(ProgressService.class);
        
         /**
         * 进度正则查询
         */
        private String frameRegexDuration = "frame=([\s,\d]*) fps=(.*?) q=(.*?) size=([\s\S]*) time=(.*?) bitrate=([\s\S]*) speed=(.*?)x";
    
        /**
         * 正则模式
         */
        private Pattern framePattern = Pattern.compile(frameRegexDuration);
        
        /**
         * 秒数
         */
        private Integer timeLengthSec;
    
        /**
         * 时长
         */
        private String timeLength;
    
        /**
         * 开始时间
         */
        private String startTime;
    
        /**
         * 比特率
         */
        private String bitrate;
    
        /**
         *  时长 正则
         */
        private String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s";
    
        /**
         * 正则模式
         */
        private Pattern pattern = Pattern.compile(regexDuration);
        
        public String getStartTime() {
            return startTime;
        }
    
        public void setStartTime(String startTime) {
            this.startTime = startTime;
        }
    
        public String getBitrate() {
            return bitrate;
        }
    
        public void setBitrate(String bitrate) {
            this.bitrate = bitrate;
        }
    
    
    
        private TranscodeTask task;
        
        public TranscodeTask getTask() {
            return task;
        }
    
        public void setTask(TranscodeTask task) {
            this.task = task;
        }
    
        @Autowired
        private TaskReposity _taskRep;
        
    
        @Override
        public void dealLine(String line) {
            logger.debug("{}输出信息:{}",task.getName(),line);
            //获取视频长度信息
            if(timeLength == null || "".equals(timeLength)) {
                Matcher m = pattern.matcher(line.trim());
                if (m.find()) {
                    timeLength = m.group(1);
                    if(timeLength!=null){
                        timeLengthSec = FFVideoUtil.getTimelen(timeLength);
                    }
                    startTime = m.group(2);
                    bitrate = m.group(3);
                    logger.debug("timeLength:{}, startTime:{},bitrate:{}",timeLength,startTime,bitrate);
                }
            }
            
             //获取视频信息
            Matcher matcher = framePattern.matcher(line);
            if(matcher.find()){
                try {
                    String execTimeStr = matcher.group(5);
                    int execTimeInt = FFVideoUtil.getTimelen(execTimeStr);
                    double devnum = FFBigDecimalUtil.div(execTimeInt,timeLengthSec,5);
                    double progressDouble = FFBigDecimalUtil.mul(devnum,100);
                    logger.debug("execTimeInt:{},devnum:{},progressDouble:{}",execTimeInt,devnum,progressDouble);
                    task.setProgress((float)progressDouble);
                    _taskRep.saveAndFlush(this.task);
                } catch (IllegalAccessException e) {
                    logger.error("获取输出流异常:{}",e.getMessage());
                }
            }
        }
        
        /**
         * 处理process输出流和错误流,防止进程阻塞
         * 在process.waitFor();前调用
         * @param process
         */
        @Override
        public void dealStream(Process process) {
            if (process == null) {
                return;
            }
            // 处理InputStream的线程
            new Thread() {
                @Override
                public void run() {
                    BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
                    String line = null;
                    try {
                        while ((line = in.readLine()) != null) {
                            //logger.info("output: " + line);
                            dealLine(line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
            // 处理ErrorStream的线程
            new Thread() {
                @Override
                public void run() {
                    BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                    String line = null;
                    try {
                        while ((line = err.readLine()) != null) {
                            logger.info("err: " + line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            err.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
        
    }
    @Component
    public class FileService {
    
        public static Logger logger = LoggerFactory.getLogger(FileService.class);
    
        // 下载小文件
        public File downloadFile(String formUrl, String fileName) throws Throwable {
            File desc = null;
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpGet httpget = new HttpGet(formUrl);
            httpget.setConfig(RequestConfig.custom() //
                    .setConnectionRequestTimeout(5000) //
                    .setConnectTimeout(5000) //
                    .setSocketTimeout(5000) //
                    .build());
            logger.debug("正在从{}下载文件到{}",formUrl,fileName);
            try (CloseableHttpResponse response = httpclient.execute(httpget)) {
                org.apache.http.HttpEntity entity = response.getEntity();
                desc = new File(fileName);
                try (InputStream is = entity.getContent(); //
                        OutputStream os = new FileOutputStream(desc)) {
                    StreamUtils.copy(is, os);
                    logger.debug("成功从{}下载文件到{}",formUrl,fileName);
                }
            }
            return desc;
        }
    
        public void downloadLittleFileToPath(String url, String target) {
            Instant now = Instant.now();
            RestTemplate template = new RestTemplate();
            ClientHttpRequestFactory clientFactory = new HttpComponentsClientHttpRequestFactory();
            template.setRequestFactory(clientFactory);
            HttpHeaders header = new HttpHeaders();
            List<MediaType> list = new ArrayList<MediaType>();
            // 指定下载文件类型
            list.add(MediaType.APPLICATION_OCTET_STREAM);
            header.setAccept(list);
            HttpEntity<byte[]> request = new HttpEntity<byte[]>(header);
            ResponseEntity<byte[]> rsp = template.exchange(url, HttpMethod.GET, request, byte[].class);
            logger.info("[下载文件] [状态码] code:{}", rsp.getStatusCode());
            try {
                if(Paths.get(target).toFile().exists()) {
                    Paths.get(target).toFile().delete();
                }
                Files.write(Paths.get(target), Objects.requireNonNull(rsp.getBody(), "未获取到下载文件"));
            } catch (IOException e) {
                logger.error("[下载文件] 写入失败:", e);
            }
            logger.info("[下载文件] 完成,耗时:{}", ChronoUnit.MILLIS.between(now, Instant.now()));
        }
    
         public void downloadBigFileToPath(String url, String target) {
                Instant now = Instant.now();
                try {
                    RestTemplate template = new RestTemplate();
                    ClientHttpRequestFactory clientFactory = new HttpComponentsClientHttpRequestFactory();
                    template.setRequestFactory(clientFactory);
                  //定义请求头的接收类型
                  RequestCallback requestCallback = request -> request.getHeaders()
                          .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
                  // getForObject会将所有返回直接放到内存中,使用流来替代这个操作
                  ResponseExtractor<Void> responseExtractor = response -> {
                    // Here I write the response to a file but do what you like
                    if(Files.exists(Paths.get(target), LinkOption.NOFOLLOW_LINKS)) {
                        Files.delete(Paths.get(target));
                    }
                    Files.copy(response.getBody(), Paths.get(target));
                    return null;
                  };
                  template.execute(url, HttpMethod.GET, requestCallback, responseExtractor);
                } catch (Throwable e) {
                    logger.error("[下载文件] 写入失败:", e);
                }
                logger.info("[下载文件] 完成,耗时:{}", ChronoUnit.MILLIS.between(now, Instant.now()));
              }
        
    }
    FileService

    有个问题需要注意:

    转码目标文件必须不存在才行,如果存在 先删除,不然就卡死。

  • 相关阅读:
    剩下的树
    守形数
    小白鼠排队(map容器插入数据的四种方法)
    字母统计
    与7无关的数
    ZOJ
    基于js的CURD插件
    API验证插件
    Django之权限管理插件
    Django之信号和序列化
  • 原文地址:https://www.cnblogs.com/liangblog/p/11399213.html
Copyright © 2011-2022 走看看