最近工作中接触到了视频监控这块东西,最开始使用的是海康摄像头,因为有文档还有技术对接,做起来基本还算顺利,但是后来需求要求支持usb摄像头,最开始百度了一圈,用啥opencv  javacv之类的技术,感觉都挺麻烦的,最终发现了FFMPEG可以很好的解决业务中的问题,在这里记录一下

  1. 查看本机的设备信息(包含摄像头,音频等)

(ps:请先切换到ffmpeg的bin目录下打开cmd命令)

命令:

ffmpeg -list_devices true -f dshow -i dummy

在java 项目中可以通过返回的errorStream进行业务的逻辑划分,注意,,如果是cmd命令执行,可以ffmpeg开头然后敲回车就可以,如果是java 可以带上exe后缀,会自动执行。

private static String ffmpegEXE = "C:/ffmpeg/bin/ffmpeg.exe";public static Boolean haveUsbCamera() {List<String> command = new ArrayList<String>();command.add(ffmpegEXE);command.add("-list_devices");command.add("true");command.add("-f");command.add("dshow");command.add("-i");command.add("dummy");ProcessBuilder p = new ProcessBuilder();p.command(command);Process start = null;try {start = p.start();} catch (IOException e) {log.error("启动进程错误", e);}try(BufferedReader readers = new BufferedReader(new InputStreamReader(start.getErrorStream()))) {String lines = null;while((lines = readers.readLine())!=null) {if (lines.contains("Lanseyaoji Webcam")) {log.info("查询到usb摄像头!");return true;}}}catch (Exception e) {log.error("获取进程信息错误", e);}log.info("未查询到usb摄像头!");return false;}

2 调取摄像头并录屏

获取到设备信息后,拿到设备名称再执行命令进行录屏

命令:

ffmpeg -f dshow -i video="Lanseyaoji Webcam" -f dshow -i audio="麦克风 (Lanseyaoji USB2.0 MIC)" -vcodec libx264 -acodec aac -strict -2 output.mp4

执行命令后会使用指定的录屏和录音设备开始录制视频,输出的位置可以指定绝对路径,如果不是绝对路径会存放在ffmpeg的bin目录下

值得注意的是有时候是编码的速度太慢导致过多的数据保存在缓存内,缓存区满了就会报错,所以需要处理一下(百度来的,我也木有太理解这话啥意思。。。),使用exec.getOutputStream可以获取输出流,然后再执行对应的命令即可

public static Process exec = null;
@SneakyThrowsprivate static void doStartCamera(String fileName) {String cmd = ffmpegEXE + " -f dshow -i video=\"Lanseyaoji Webcam\" -f dshow -i audio=\"麦克风 (Lanseyaoji USB2.0 MIC)\" -vcodec libx264 -acodec aac -strict -2 " + fileName;List<String> command = Arrays.asList(StringUtils.split(cmd, " "));ProcessBuilder p = new ProcessBuilder();p.command(command);try {exec = p.start();} catch (IOException e) {log.info("启动进程失败", e);}try (BufferedReader readers = new BufferedReader(new InputStreamReader(exec.getErrorStream()))){String lines1 = null;while((lines1 = readers.readLine())!=null) {log.info("error lines:"+lines1);// 有时候编码的速度太慢导致过多的图片数据保存在缓存内,缓存区空间太小或满了就会报错// 需要手动确认一下才能继续// 提示信息:xxxtoo full or near too fullxxxif (lines1.contains("[y/N]")) {executeCommand("y\n");}}}catch (Exception e) {log.error("获取进程信息错误", e);}}private static boolean executeCommand(String command) {try {OutputStream outputStream = exec.getOutputStream();outputStream.write(command.getBytes(StandardCharsets.UTF_8));outputStream.flush();} catch (Exception e) {log.error("执行命令{}错误", command, e);return false;}return true;}

这个方法时开始录制,后台会一直打印录制信息,包括时间、大小等信息,等待程序给出停止指令

public static boolean endCamera() {boolean b = executeCommand("q\n");try {// 睡眠几秒,让视频流完全写入到视频文件,否则可能会导致文件不可用Thread.sleep(3000);} catch (Exception e) {}return b;}

至此,一个视频文件就会产生在指定的路径中了

3 添加水印

现在应该已经下载好一个视频了,但是有时候有需求要添加水印,找过几个命令要么就产生的水印半天才走一秒,要么提示命令不正确,参数不正确,在疯狂百度下,终于找到了一个命令

 public static void main(String[] args) {Map<Integer, String> map = new HashMap<>();map.put(0, "000");map.put(2, "222");map.put(4, "444");map.put(8, "888");map.put(75, "");Calendar instance = Calendar.getInstance();instance.set(Calendar.YEAR, 2021);instance.set(Calendar.MONTH, 8);instance.set(Calendar.DAY_OF_MONTH, 23);instance.set(Calendar.HOUR_OF_DAY, 15);instance.set(Calendar.MINUTE, 23);instance.set(Calendar.SECOND, 23);addWatermark("C:/ffmpeg/bin/1.mp4", map, instance.getTime());} /*** 添加水印* @param fileName 原视频文件绝对路径* @param secondsMap 时间轴和水印信息* @param startTime 时间水印起始时间* @return 新视频文件绝对路径*/public static String addWatermark(String fileName, Map<Integer, String> secondsMap, Date startTime) {//ffmpeg -i 1.mp4 -vf// "drawtext=fontfile=simhei.ttf: text='I_CODE\:YT777':x='if(gte(t,3),if(lte(t,8),0,NAN),NAN)':y=35:fontsize=24:fontcolor=white:shadowy=2,// drawtext=fontfile=simhei.ttf: text='I_CODE\:YT888':x='if(gte(t,0),if(lte(t,8),0,NAN),NAN)':y=15:fontsize=24:fontcolor=white:shadowy=2"// output1.mp4// 水印命令StringBuilder command = new StringBuilder(ffmpegEXE + " -i " + fileName + " -vf \"");// 垂直位置int y = 10;// 拼接水印命令ArrayList<Integer> integers = new ArrayList<>(secondsMap.keySet());Collections.sort(integers);// 所有水印都要持续到视频最后Integer lastTime = integers.get(integers.size() - 1);for (int i = 0; i < integers.size() - 1; i++) {String s = secondsMap.get(integers.get(i));if (i < integers.size() - 1) {command.append("drawtext=fontfile=simhei.ttf:text='" + s + "':x='if(gte(t," + integers.get(i) + "),if(lte(t," + lastTime + "),0,NAN),NAN)':y=" + y + ":fontsize=24:fontcolor=white:shadowy=2");}if (i < integers.size() - 2) {command.append(",");}y = y + 20;}// 模拟添加时间水印// 注意第一个要添加逗号Calendar calendar = Calendar.getInstance();calendar.setTime(startTime);long ll = calendar.getTimeInMillis() / 1000;System.out.println(ll);command.append(",drawtext='fontfile=simhei.ttf:fontsize=24:x=w-tw:y=10:fontcolor=white:text=%{pts\\: localtime\\:").append(ll).append("}'");String newFileName = getNewFileName(fileName);command.append("\" ").append(newFileName);ProcessBuilder p = new ProcessBuilder();p.command(command.toString().split(" "));Process start = null;try {start = p.start();} catch (IOException e) {log.error("启动进程错误", e);}try(BufferedReader readers = new BufferedReader(new InputStreamReader(start.getErrorStream()))) {String lines = null;while((lines = readers.readLine())!=null) {log.info("error lines:"+lines);if (lines.contains("[y/N]")) {executeCommand("y\n");}}}catch (Exception e) {log.error("获取进程信息错误", e);}return newFileName;}/*** 重命名文件的时间戳* @param fileName* @return*/private static String getNewFileName(String fileName) {String path = fileName.substring(0, fileName.lastIndexOf("/"));String name = fileName.substring(fileName.lastIndexOf("/"), fileName.lastIndexOf("."));String[] s = name.split("-");return path + s[0] + "-" + System.currentTimeMillis() + ".mp4";}

命令的格式是这样的:

ffmpeg -i 1.mp4 -vf
"drawtext=fontfile=simhei.ttf: text='I_CODE\:YT777':x='if(gte(t,3),if(lte(t,8),0,NAN),NAN)':y=35:fontsize=24:fontcolor=white:shadowy=2,
drawtext=fontfile=simhei.ttf: text='I_CODE\:YT888':x='if(gte(t,0),if(lte(t,8),0,NAN),NAN)':y=15:fontsize=24:fontcolor=white:shadowy=2" output1.mp4

解释一下参数map的格式,是一个时间轴信息,意思是第0秒开始显示000,第二秒开始显示222,以此类推,最后一个key表示这个视频的有多长,单位为秒(这个值需要在自己的业务逻辑中获取到,如果获取不到实际时长,应该也可以设置的非常大来达到同样的效果),这个值主要是在命令中控制水印可以显示多久

startTime是视频的时间水印从什么时候开始,最后需要转化为秒钟即可

添加水印是中间的drawtext命令,一次性添加多个水印使用逗号隔开,由于每个属性使用冒号隔开的,所以添加的文字水印中需要显示冒号的话要用反斜杠转义(\:)

text:文字水印的内容,记得要转义冒号

x:相对于左上角,显示的横坐标,if(gte(t,0),if(lte(t,3),w-tw,NAN),NAN)意思就是大于0秒和小于3秒时显示,大于3秒时消失,根据需求拼接多条水印命令即可

y:相对于左上角,显示的纵坐标

这里的属性代表的含义自己百度一下吧 ,最后执行一下就可以了

java FFMPEG调取usb摄像头,截取视频,添加文字和时间水印相关推荐

  1. 《FFmpeg Basics》中文版-10-为视频添加文字

    正文 视频中包含的文本数据可以显着提高其信息质量. 在视频中添加文字的相关介绍 如何将一些文本添加到视频输出中的两种常用方法是使用前一章中的字幕或叠加技术(overlay). 具有许多可能性的最高级选 ...

  2. Linux下用FFMPEG采集usb摄像头到RTMP

    Linux下用 FFMPEG 采集 usb摄像头视频 和 摄像头内置麦克风音频 到RTMP服务 ffmpeg -f video4linux2 -qscale 10 -r 12 -s 640x480 - ...

  3. ffmpeg查看USB摄像头同时推流

    欢迎访问自建博客原文: http://www.e-lionel.com/index.php/2018/08/07/64/ 最近有个项目,需求是USB摄像头在观看画面的同时做直播,一直以来都是通过ffm ...

  4. 如何使用usb_cam和image_transport_plugins插件进行usb摄像头的视频获取和实时图像传输

    如何使用usb_cam和image_transport_plugins插件进行usb摄像头的视频获取和实时图像传输 前言 一.使用usb_cam驱动进行usb摄像头的图像获取 二.使用image_tr ...

  5. 手把手教你如何通过Java给图片添加文字和图片水印

    本文首发于个人网站 前言 最近工作上有个需求,动态生成一张图片,具体来说就是基于模版图片动态添加文字和图片(文字内容不同,图片数目不同),其中文字大小不全一样,且对位置有所要求. 本文将剖析多个技术方 ...

  6. 如何用AVS Video Editor给视频添加文字?

    一般我们在给视频进行后期处理的时候,会需要给这个视频加入文字或者主题标题.大家都知道,大部分视频剪辑软件都支持这个操作,但就有用户问,这个给AVS Video Editor添加文字该怎么做呢? 首先我 ...

  7. 如何在视频里添加文字?3个方法教你给视频添加文字

    在现今数字化的社会中,视频已经成为了我们生活和工作中不可或缺的一部分,而在视频制作和编辑过程中,添加文字是一个非常常见的操作,尤其是在一些商业和宣传广告视频中.例如当我们需要制作一个介绍产品或服务的视 ...

  8. 视频添加文字用什么软件,视频添加文字怎么弄

    随着plog.vlog等视频形式的兴起,视频添加文字变得越来越流行.与其选择插入音频解说,还不如加文字来得生动有趣.那么,视频添加文字用什么软件?视频添加文字怎么弄?接下来,本文会教大家使用一款简单好 ...

  9. php图片写入带问号_php实现图片上传时添加文字和图片水印技巧

    本文实现的功能特别适用于一些商城和图片站中,分享了图片在上传时添加文字和图片水印的技巧,供大家参考,具体内容如下 1. water.class.php header('Content-Type:tex ...

最新文章

  1. 深度linux win7分区,怎么安装Win7深度操作系统?
  2. Flask框架(SQLAlchemy(python3版本)中查询数据的方法,以及定义显示信息 )
  3. 【FPGA】相关介绍
  4. Windows上Tomcat启动,服务中没有Tomcat
  5. BRI OS 高级ping
  6. python pandas检验一列中是否只有一个值
  7. 深入理解密码学基本概念和应用
  8. 使用Selenium定位鼠标悬浮出现的下拉菜单
  9. C语言中extern关键字详解
  10. 003-Xshell和Xftp连接CentOS
  11. 应用案例 | 2011款保时捷卡宴3.0T车发动机怠速间歇性抖动故障诊断
  12. 长春公办计算机学校有哪些条件,长春小学初中哪些学校民办?哪些公办?最新一览表来也!...
  13. 微软拼音配置小鹤双拼
  14. 报错信息:Avoid mutating a prop directly since the value will be overwritten
  15. 那么浙江大学软件工程专业复试考试内容有哪些
  16. 《扫毒2》火爆来袭,刘德华不要片酬,却要了电影版权,网友:为啥
  17. Someone(某位大牛)的自述
  18. ts判断数据是否存在
  19. 电力系统非线性控制_认识避雷器—电力系统重要的一次保护元件
  20. 电子商务公司运营流程是什么怎样绘制

热门文章

  1. (MC维嘉)JAVA 面向对象(3)
  2. 用于音频信号去噪的谱相减和陷波滤波的比较(Matlab代码实现)
  3. 《0Day安全》之堆溢出
  4. vba 添加outlook 签名_调用Outlook发送邮件-附带签名
  5. php采集今日头条出现问题,PHP采集今日头条内容页时,解析页面上的JS转为json
  6. ahk捕捉连续按esc键
  7. 转换金额为大写人民币-Java
  8. POI 2011 切题记
  9. 程序逸的Java项目之旅-图书管理系统之环境的搭建
  10. java图形打字机_Android模仿打字机效果的自定义View实现