为什么ffmpeg的批处理会卡死系统?
Why a batch processing of ffmpeg is freezing the system?
我需要从 50 多个 mp4 源文件中拆分出较小的视频块,以获得 5000 多条记录。每条记录可能会从 50 多个源文件中产生 2 或 3 个较小的块。
确定要拾取哪个源文件的逻辑写在 Java 中,然后在 Runtime.getRuntime().exec()
上使用 ExecutorService
和 [=17= 馈送到 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;
}
字符串 cmd
值是其中之一,基于 split 或 merge 要求:
拆分:
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 class。
您正在开始执行,但没有等待它完成,因此您的线程池只启动与命令一样多的进程。我不确定您 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.");
}
我需要从 50 多个 mp4 源文件中拆分出较小的视频块,以获得 5000 多条记录。每条记录可能会从 50 多个源文件中产生 2 或 3 个较小的块。
确定要拾取哪个源文件的逻辑写在 Java 中,然后在 Runtime.getRuntime().exec()
上使用 ExecutorService
和 [=17= 馈送到 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;
}
字符串 cmd
值是其中之一,基于 split 或 merge 要求:
拆分:
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 class。
您正在开始执行,但没有等待它完成,因此您的线程池只启动与命令一样多的进程。我不确定您 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.");
}