JAVA调用FFMpeg进行转码等操作

2022-02-14 15:39:53 浏览数 (1)

直接上代码:

代码语言:javascript复制
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 );
}
代码语言:javascript复制
@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();
    }
    
}
代码语言:javascript复制
@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()));
          }
    
}

有个问题需要注意:

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

0 人点赞