在Windows下通过JAVA程序调用ffmpeg实现视频水印

在Windows下通过JAVA程序调用ffmpeg实现视频水印,第1张

在Windows下通过JAVA程序调用ffmpeg实现视频水印

@是

windows下通过java调用ffmpeg实现视频水印功能

最近接到领导的任务:要求实现视频加水印,原本考虑使用javacv实现每一帧抓取在进行帧运算等 *** 作,后来尝试了,太麻烦果断采用java的Process类去驱动ffmpeg程序。于是先打算在windows本机环境下做一个demo,然后再想法改成生产环境能够使用。但是遇到了一大堆坑。下面是本人做的总结。希望能对新手同志们有所帮助。

1.安装ffmpeg并且在网上找到有关调用代码

ffmpeg在windows下安装较简单,直接在网上下载压缩包后解压到指定路径即可。
这里我解压到了D:Program Filesffmpeg-n4.4-latest-win64-gpl-shared-4.4

主干程序
class PrintStream extends Thread
{
    java.io.InputStream __is = null;
    public PrintStream(java.io.InputStream is)
    {
        __is = is;
    }

    public void run()
    {
        try
        {
            while(this != null)
            {
                int _ch = __is.read();
                if(_ch != -1)
                    System.out.print((char)_ch);
                else break;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
public class test2 {
    public final static String ffmpeg_path="D:/Program Files/ffmpeg-n4.4-latest-win64-gpl-shared-4.4/bin/ffmpeg.exe ";
    public final static String input="E:/视频/pp.mp4";
    public final static String output= "E:\视频\grr.mp4";
    public final static String logo = "E\:/视频/12.png";
    public static void main(String[] args) {
        String command = ffmpeg_path+"-i "+input+" -vf "movie="+
                logo+"[watermark];[in][watermark] " +
                "overlay=10:10 [out]" -codec:a copy "+output;
        try {
            Runtime run = Runtime.getRuntime();
            System.out.println(command);
            java.lang.Process process = run.exec(command);
            new PrintStream(process.getErrorStream()).start();
            new PrintStream(process.getInputStream()).start();
            process.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这是参考:

https://www.cnblogs.com/findingsea/archive/2013/03/14/2959634.html

这位博主在遇到坑的时候都写了,还比较全面。不过我直接调用他的代码还是无法实现视频加水印的问题。

遇到的常见问题:

写路径的时候采用:

写法在写ffmpeg路径、输入的原视频路径、输出的加了水印的视频路径,这三个地方正常写没有问题,因为他是识别java调用的方法去驱动的程序的位置。但是在写logo(即要加的水印的位置)的时候不能按照原来的写路径。因为在在ffmpeg命令中它是在双引号里的,ffmpeg的movie filter读取规则是按照linux来的,不支持对盘符(C:、D:、E:)这些的读取。可参考:

https://blog.csdn.net/a373794359/article/details/97496242

如果按这样会报错:
所以吧logo路径改成:

public final static String logo = "E\:/视频/12.png";
然后还有一种最常见的错误就是路径写错

比如空格少了造成连读等因素。这个可以自己排查。还有就是文件读取权限等,这种情况比较少见,反正我是没遇到过。当然第一种情况也会造成“系统找不到指定的文件”这样的报错。

程序做一下封装就成了下面的样子

参考了:https://www.cnblogs.com/xisita0706/p/12580226.html

public class ProcessExec {

    private Process process;
    public static class StringUtils{
        public static boolean isNotEmpty(String s){
            if (s==null||s.length()==0)
                return false;
            return true;
        }
    }
    public void execute(Map dto)
    {
        StringBuffer waterlogo = new StringBuffer();
        waterlogo.append("-i ");
        if(null!=dto.get("input_path")&&StringUtils.isNotEmpty(dto.get("input_path"))){
            waterlogo.append(dto.get("input_path"));
        }
        waterlogo.append(" -vf "movie=");
        if (null!=dto.get("logo")&&StringUtils.isNotEmpty(dto.get("logo"))){
            waterlogo.append(dto.get("logo"));
        }
        waterlogo.append(",scale= 60: 30");
        waterlogo.append("[watermark];[in][watermark] overlay=main_w-overlay_w-10:main_h-overlay_h-10 [out]" -codec:a copy ");
        if (null!=dto.get("video_converted_path")&&StringUtils.isNotEmpty(dto.get("video_converted_path"))){
            waterlogo.append(dto.get("video_converted_path"));
        }
        Runtime run = Runtime.getRuntime();
        String ffmegPath = null;
        if (StringUtils.isNotEmpty(dto.get("ffmpeg_path"))){
            ffmegPath = dto.get("ffmpeg_path");
        }
// 执行命
        try {
            System.out.println(ffmegPath+waterlogo);
            java.lang.Process process = run.exec(ffmegPath+waterlogo);
//            Process videoProcess = new ProcessBuilder(ffmegPath+waterlogo).redirectErrorStream(true).start();
            new PrintStream(process.getErrorStream()).start();
            new PrintStream(process.getInputStream()).start();
            process.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class PrintStream extends Thread
{
    java.io.InputStream __is = null;
    public PrintStream(java.io.InputStream is)
    {
        __is = is;
    }

    public void run()
    {
        try
        {
            while(this != null)
            {
                int _ch = __is.read();
                if(_ch != -1)
                    System.out.print((char)_ch);
                else break;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
public class test {

    public static void main(String[] args) {
        ProcessExec ps = new ProcessExec();
        HashMap dto=new HashMap();
        dto.put("ffmpeg_path","D:/Program Files/ffmpeg-n4.4-latest-win64-gpl-shared-4.4/bin/ffmpeg.exe ");//必填:此处是ffmpeg.exe所在位置,也就FFmpeg文件夹bin目录下的ffmpeg.exe
//        dto.put("ffmpeg_path","E:\ffmpeg.exe ");
        dto.put("input_path", "E:/pp.mp4");//必填;此处是你要处理的视频位置
        dto.put("video_converted_path", "E:\grr.mp4");//必填;此处是完成添加水印后输入视频的位置并重新命名该视频
        dto.put("logo", "E\\:/12.png");//必填;此处是你要添加的水印位置,注意此处图片位置一定要加上转译符,否则识别不了盘符
        ps.execute(dto);
    }

}

这样就能正常跑起来了,不过要注意的是:我这里直接输出的路径是E:/grr.mp4,输出文件的路径下不能有重复的grr.mp4文件.因为我这里没有做覆盖命令,所以要确保你的目录下没有grr.mp4.不然控制台让你输入y/N。你又输入不了了。

看到控制台打印这个就知道成功了!

另外如果使用ProcessBuilder类的话,一定要用字符串数组的形式传递命令的参数,因为系统调用的时候第一个字符串默认会被认为是ffmpeg的路径。
可参考下:

https://www.jianshu.com/p/0cadd56aa9b7?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5706901.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存