一、背景

最近项目中遇到需要将.webm视频进行剪辑并合并的需求,系统为ubuntu。开始尝试使用ffmpeg,在java中调用指令剪辑已存在的问题没有问题,但将剪辑后的文件拼接起来的时候ffmpeg会报文件不存在的错误,暂时无法解,所以后来换成了mencoder。

二、指令调用

  首先,定义执行命令方法。

/**
     * 系统执行指定控制台命令
     */
    public static boolean commandExecution(String command) throws Exception {
        logger.info("执行指令 " + command);
        boolean flg = true;
        try {
            Process proc = Runtime.getRuntime().exec(command);

            DriverThreadPool.clearStream(proc.getInputStream());
            DriverThreadPool.clearStream(proc.getErrorStream());

            if (proc.waitFor() != 0) {
                if (proc.exitValue() != 0) {
                    logger.info("指令执行失败" + command);
                    flg = false;
                }
            }
        } catch (Exception e) {
            flg = false;
            throw e;
        }
        return flg;
    }

  其中 Runtime.getRuntime().exec()方法如果要等待系统执行完指令再继续运行需要调用proc.waitFor()方法。

  而waitFor()方法中需要注意一个坑,在exec()执行后,java会为这个系统指令创建三个流:标准输入流、标准输出流和标准错误流,执行指令的过程中系统会不断向输入流和错误流写数据,如果不及时处理这两个流,可能会使得流的缓存区暂满而主线程阻塞。

  尝试过在主线程内直接循环读取流,发现执行mencoder命令后依然会造成阻塞,所以后来使用两个线程单独读取输入流和错误流解决了问题,但这里注意在程序结束的时候需要吧线程池关闭掉,否则这两个线程依然会不断读取。

/**
     * 流处理
     */
    public static void clearStream(InputStream stream) {
        // 处理buffer的线程
        executor.execute(() -> {
            String line = null;
            try (BufferedReader in = new BufferedReader(new InputStreamReader(stream));) {
                while ((line = in.readLine()) != null) {
                    logger.info(line);
                }
            } catch (Exception e) {
                logger.error(line);
            }
        });
    }

三、安装mencoder与webm格式的相关编码库

  在ubuntu执行指令如下:

sudo apt-get update
sudo apt-get install mencoder
sudo apt-get install libavformat-dev // mencoder中lavf的支持库
sudo apt install libvpx-dev // webm格式编码VP80的支出库

  随后java中调用指令如下:

mencoder -ovc copy -oac copy source.webm -o target.webm -of lavf -lavfopts format=webm -lavcopts acodec=vorbis:vcodec=libvpx -ffourcc VP80 -ss 00:10 -endpos 00:20

  -ovc copy -oac COPY表示音频源和视屏源使用源视频格式,-o表示复制目标,-of lavf表示使用lavf库,format=webm -lavcopts acodec=vorbis:vcodec=libvpx表示指定web格式,-ffourcc VP80表示使用VP80编码,-ss 00:10 -endpos 00:20表示截取source.webm的10秒到20秒,然后输出到target.webm。

  进行了几个视频的剪辑后,需要将多个视频进行合并。

mencoder -ovc copy -oac copy source1.webm source2.webm source3.webm -o target.webm -of lavf -lavfopts format=webm -lavcopts acodec=vorbis:vcodec=libvpx -ffourcc VP80

  将多个原视频用空格隔开即可。