用Java的Process执行命令行,ffmpeg抽帧到一千多帧图片卡住,不报错。

项目场景:

最近需要写一个抽帧、推流的工具类,抽帧写好测试的时候也没问题,等到真正用的时候就发现各种问题。


问题描述

用Java执行ffmpeg抽帧命令,测试的时候没有问题,后来发现抽帧图片多了就会卡住。

刚开始觉得可能是网速的问题,测试了一下也没问题阿,抽帧图片多了才发现不知道怎么回事不抽了,最关键的是进程都还没掉。


原因分析:

刚开始觉得可能是这个命令的问题,就直接拿命令在Linux执行发现没这个问题,在Java执行才会有这个问题,然后想着直接用shell脚本试试,也是没有卡住的情况,既然这样,就想着拿Java执行shell脚本再执行命令行,结果还是出现了一样的情况,这是最想不通的一点,这都不是一个进程了,shell脚本后台运行,按理来说就算Java调用shell脚本的进程直接杀掉也还会执行,但是还是会到了一千多张就卡住了。后来就尝试用Javacv 呗,刚开始尝试的还不如直接调用process,只能抽九百多张,这个因为没情况缓冲区,加了

java 复制代码
grabber.setVideoOption("fflags", "nobuffer");

以后可以抽到两千多张,还是到不了想要的效果。

解决方案:

想了想会不会process也是这样的情况,当时process只清空了输入流和错误流,没有对输出流进行处理。添加如下代码

java 复制代码
  ProcessBuilder processBuilder = new ProcessBuilder("cmd",path);
  processBuilder.redirectErrorStream(true);
  try {
  Process process = null;
  process = processBuilder.start();
              // 读取标准输出和错误
            InputStream inputStream = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null) {
                log.info(line); // 处理标准输出和错误
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

这样才给问题解决了,如果需要给前端返回进程号,可以使用下面的代码(jdk1.8),jdk版本高的可以直process.getPid();异步执行process.waitFor(); 提前返回进程号。

java 复制代码
 pidFiled = process.getClass().getDeclaredField("pid");
 pidFiled.setAccessible(true);
 String pid = String.valueOf(pidFiled.getInt(process));

根据进程号结束抽帧的代码:

java 复制代码
/**
 * @param pid 进程号
 * @return 0表示正常
 */
public Integer stopByPid(String pid) {
    if (!StringUtils.hasText(pid)) {
        throw new BadRequestException("Pid cannot be empty");
    }
    String command = "kill -9 " + pid;
    log.info(command);
    Integer exitCode = 0;
    ProcessBuilder processBuilder = new ProcessBuilder();
    processBuilder.command("bash", "-c", command);
    try {
        Process process = processBuilder.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            log.error(line);
        }
        exitCode = process.waitFor();
        log.info("Exited with error code : " + exitCode);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return exitCode;
}
相关推荐
suaizai_几秒前
ComputerUse:让AI真正操控桌面系统
java·前端·javascript
小小张说故事7 分钟前
Python 装饰器到底是个啥?从 @ 符号到手写一个,5 个例子讲透
后端·python
CodeSheep7 分钟前
朋友面试谈薪报价2w,HR非得压到1.9,还反问他:你就差这1000块钱?后来背调时问了他前同事十几个问题,对方最后直接挂了
前端·后端·程序员
fundoit11 分钟前
资源服务器如何对 JWT 进行验签
java·运维·服务器·spring boot·php·oauth2
hljqwb12 分钟前
java服务异常日志只打印异常类型,没有堆栈定位分析(十)
java·开发语言
ym hyd 11116 分钟前
生鲜超市库存管理信息系统源码 Java+SpringBoot+Vue3 前后分离
java·开发语言·vue.js·spring boot·毕设
徐小黑ACG18 分钟前
Golang 基础02 控制语句
开发语言·后端·golang
Rain的Java大神之路20 分钟前
别再瞎装 RabbitMQ 了!从 0 到 1 部署到 Spring Boot 全链路实战,生产级坑全填平
java·后端·面试
liyunlong-java23 分钟前
敏感词过滤完整指南(DFA 字典树)
java·开发语言·spring
专业程序开发源24 分钟前
SSM笔记本在线销售系统32649-计算机课程设计、毕业设计
java·spring boot·后端·python·django·php·课程设计