【问题标题】:Why a batch processing of ffmpeg is freezing the system?为什么ffmpeg的批处理会冻结系统?
【发布时间】:2020-01-06 16:57:11
【问题描述】:

我需要从 50 多个 mp4 源文件中分割出更小的视频块,以获取 5000 多条记录。每条记录可能会从这 50 多个源文件中产生 2 或 3 个较小的块。

确定要提取哪个源文件的逻辑是用Java编写的,然后使用ExecutorServicenewFixedThreadPoolRuntime.getRuntime().exec()上的ffmpeg输入如下:

private static boolean processqueue(ArrayList<String> cmds) {
    final ExecutorService pool;
    int threadsnum = Runtime.getRuntime().availableProcessors()-2;
    pool = Executors.newFixedThreadPool(threadsnum);

    for(final String cmd: cmds){ 
        pool.execute(new Runnable() {
            public void run() {
                System.out.println(cmd);
                try {
                    Runtime.getRuntime().exec(cmd);
                } catch (IOException e) {
                    e.printStackTrace();
                    pool.shutdown();
                }
            }
        });
    }                   
    pool.shutdown();

    // wait for them to finish for up to one minute.
    try {
        if(!pool.awaitTermination(1, TimeUnit.MINUTES)) {
            pool.shutdownNow();
        }

        //Wait a while for tasks to respond to being cancelled
        if(!pool.awaitTermination(1, TimeUnit.MINUTES))
            System.err.println("Pool did not shutdown properly");

    } catch (InterruptedException e) {
        e.printStackTrace();
        pool.shutdownNow();
        //Preserve interrupt status
        Thread.currentThread().interrupt();
        return false;
    }                   

    return true;
}

String cmd 值是基于 splitmerge 要求的其中之一:

拆分:

ffmpeg -y -ss 00:00:00 -t 00:08 -i E:/tmp/fin12.mp4 -acodec copy -vcodec copy E:/tmp/Intermed/0136f.mp4

合并:

ffmpeg -y -i E:/tmp/Inter/0136c0.mp4 -i E:/tmp/Inter/0136c1.mp4 -i E:/tmp/Inter/0136f.mp4 -i E:/tmp/Jingle.mp4 -i E:/tmp/wm1280.png -filter_complex "[0:v][0:a][1:v][1:a][2:v][2:a][3:v][3:a]concat=n=4:v=1:a=1[vv][a];[vv][4:v]overlay=x=0:y=H-overlay_h[v]" -map "[v]" -map "[a]" E:/tmp/final/0136.mp4

第一次尝试时,只处理了 250 条记录。并且,在随后尝试处理余额记录时,它抛出了以下异常;但是,又处理了 300 条记录:

java.io.IOException: Cannot run program "ffmpeg": CreateProcess error=1455, The paging file is too small for this operation to complete
at java.lang.ProcessBuilder.start(Unknown Source)

而且,此代码经常冻结。为什么ExecutorService 不排队处理所有记录并优雅退出?我做错了什么?

注意:我通过传递从命令行执行的相关参数从 Windows 批处理脚本调用 Java 类。

【问题讨论】:

  • 您的 java 代码妨碍了正常调试:“分页文件太小,无法完成此操作”是当您需要的内存超出 windows 所能提供的内存时出现的 windows 错误,要么是因为其他应用程序/进程占用了内存,要么是因为没有任何内存可供分配。那么:在运行这个怪物操作时,您是否尝试过在任务管理器中查看内存使用情况?

标签: java ffmpeg parallel-processing batch-processing executorservice


【解决方案1】:

您正在开始执行,但没有等待它完成,因此您的线程池只会启动与命令一样多的进程。我不确定您的其余 try/catch 正在尝试做什么。我建议您使用 CountdownLatch。这是一个例子:

public static void main(String[] args) {
    List<String> cmds = Lists.newArrayList("sleep 1", "sleep 2", "sleep 3");

    final ExecutorService pool;
    int threadsnum = Runtime.getRuntime().availableProcessors() - 2;
    pool = Executors.newFixedThreadPool(threadsnum);


    CountDownLatch latch = new CountDownLatch(cmds.size());


    for (final String cmd : cmds) {
        pool.submit(() -> {
            try {
                System.out.println("to be executed: " + cmd);
                Runtime.getRuntime().exec(cmd).waitFor();
                latch.countDown();
            }
            catch (IOException e) {
                Thread.currentThread().interrupt();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

    }

    try {
        latch.await(10, TimeUnit.SECONDS);
        if (latch.getCount() > 0) {
            System.out.println("Waited long enough. There are " + latch.getCount() + " threads still running");
        }
    }
    catch (InterruptedException e) {
        e.printStackTrace();
    }
    finally {
        pool.shutdown();
    }
    System.out.println("Completed.");

}

【讨论】:

  • 非常感谢。你救了我的一天! waitFor() 成功了。由于我的环境不支持 Lambda 表达式,我不得不切换回 1.8 之前的提交语法。而且,CountDownLatch 是锦上添花..
  • 我想我承认解决方案太快了。它非常适合split;但是,即使在增加 latch.await 时间之后,mergeffmpeg concat 命令也不会发生任何事情。通常,merge 在我的系统上需要 10-20 秒,具体取决于输入文件的数量及其大小。所以,我尝试了 30 秒到 2 分钟 latch 时间。但是,进程永远不会停止(不得不强制中止),日志显示#of threads running 和“completed”语句。有什么想法吗?
  • 你运行的命令对上面的代码没有影响。闩锁时间是它等待所有作业完成的时间。因此,如果您有 30 个作业,每个作业需要 20 秒才能运行,并且池中有 4 个,则运行 (30*20)/4 需要 2 分钟多一点。在池关闭之前,您将在池中拥有空闲线程。我的猜测是您发送的命令中有一些东西不能正常工作。尝试从进程和/或退出代码中捕获输出流并将其输出到控制台以查看发生了什么。
  • D,显然,命令行参数有一些影响,因为Runtime.getRuntime().exec() 的行为与 Shell 不同。 issues-in-executing-ffmpeg-command-in-java-code-in-linuxwhen-runtime-exec---won-t.html。我必须相应地更正代码,现在一切正常。再次感谢。
猜你喜欢
  • 2017-04-19
  • 2018-11-13
  • 1970-01-01
  • 2015-06-03
  • 1970-01-01
  • 1970-01-01
  • 2022-12-23
  • 2019-07-14
  • 2015-03-08
相关资源
最近更新 更多