java 调用 ffmpeg 指令获取视频的第 n 帧图片-兼容【linux 和 win】
1.调用
if (StringUtil.equals(HotCacheData.os, "linux")) { msg = processVideo(filePath, n, targetUrl); } else { if (StringUtil.isEmpty(HotCacheData.ffmpegUrl)) { throw new CustomResultException(ResultEn.FILE_LOADUP_ERROR.getCode(), "win系统ffmpeg的执行文件未找到"); } msg = processVideo(HotCacheData.ffmpegUrl, filePath, n, targetUrl); }
2.封装的方法

private static String processVideo(String filePath, int n, String targetUrl) { String msg = ""; StringBuilder commend = new StringBuilder(); commend.append("ffmpeg ") .append(" -i ") .append(filePath) .append(" -ss ") .append(" ").append(n).append(" ") .append(" -f ") .append(" image2 ") .append(targetUrl); Process process = null; try { ProcessBuilder pb = new ProcessBuilder(); //因为process执行命令并不是像窗口中执行shell一样,所以需要添加参数,用于执行脚本 pb.command("sh", "-c", commend.toString()); //processBuilder支持将inputStream与ErrorStream合并为一个Stream,即所有的输出信息都合并到inputStream中,这样做可以减少一个线程 pb.redirectErrorStream(true); process = pb.start(); //由于process机制原因会导致死锁,所以需要在waitfor方法之前,创建线程用于处理inputstream中缓冲区的数据,这也是为什么要合并inputstream和errorstream的原因,在这里可以少创建一个线程 readInputStream(process.getInputStream()); //返回0则表示输出正常 int resultCode = process.waitFor(); } catch (Exception e) { msg = ExcBox.getExcMsg(e); log.info("\n视频解析帧画面异常:"); log.info(msg); } finally { try { if (null != process) { process.getErrorStream().close(); process.getInputStream().close(); process.getOutputStream().close(); } } catch (Exception ignored) { } } return msg; }

private static String processVideo(String ffmpegPath, String filePath, int n, String targetUrl) { String msg = ""; Process process = null; try { ProcessBuilder pb = new ProcessBuilder(); //因为process执行命令并不是像窗口中执行shell一样,所以需要添加参数,用于执行脚本 pb.command(ffmpegPath, "-y", "-i", filePath, "-ss", n + "", "-f", "image2", targetUrl); //processBuilder支持将inputStream与ErrorStream合并为一个Stream,即所有的输出信息都合并到inputStream中,这样做可以减少一个线程 pb.redirectErrorStream(true); process = pb.start(); //由于process机制原因会导致死锁,所以需要在waitfor方法之前,创建线程用于处理inputstream中缓冲区的数据,这也是为什么要合并inputstream和errorstream的原因,在这里可以少创建一个线程 readInputStream(process.getInputStream()); //返回0则表示输出正常 int resultCode = process.waitFor(); } catch (Exception e) { msg = ExcBox.getExcMsg(e); log.info("\n视频解析帧画面异常:"); log.info(msg); } finally { try { if (null != process) { process.getErrorStream().close(); process.getInputStream().close(); process.getOutputStream().close(); } } catch (Exception ignored) { } } return msg; }

//创建线程处理输出流 private static void readInputStream(InputStream in) { executor.execute(new Runnable() { @Override public void run() { InputStreamReader reader = null; try { reader = new InputStreamReader(in); LineNumberReader line = new LineNumberReader(reader); String str = null; while ((str = line.readLine()) != null) { System.out.println(str); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (reader != null) { reader.close(); } } catch (IOException e) { e.printStackTrace(); } } } }); }
本文来自博客园,作者:岑惜,转载请注明原文链接:https://www.cnblogs.com/c2g5201314/p/16943695.html
响应开源精神相互学习,内容良币驱除劣币
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话