由于产品需要对视频做一系列的解析操作,利用FFmpeg命令来完成视频的音频提取、第一帧提取作为封面图片、音频重采样、字幕压缩等功能;

  前一篇文章已经记录了FFmpeg在JAVA中的使用-音频提取&字幕压缩 ,就不再重复说明,今天简单介绍下如何实现第一帧提取、重采样,然后再分享下Process.waitFor()引发的阻塞问题。

  一、首先,分享两个命令:

  1. 视频第一帧提取:ffmpeg -i [videofile]  -vframes 1 -q:v 2 -f image2  [imagefile]
  2. 音频重采样:ffmpeg -i [audiofile]  -ar 16000  [audiofile]

  说明:

  • -vframes 表示提取的第几帧,获取第一桢则后面的值为1,如果后面的值大于1,那么最后的[imagefile]不能指定一个文件,不然会报错,如下

  

  指定了输出的文件名为“1.jpeg”,报错:不能从1.jpeg文件中获取第二帧的文件名,因为-vframes只要大于1,则会提取出每一帧的图片,建议使用如%03d.jpeg来作为文件名,那么它解析的结果便是001.jpeg,002.jpeg,...依次编号往后;

  • -q:v 2 q代表质量quality, v代表视频流,2是控制质量的参数;-f指定输出的格式是image2;
  • 除了使用-vframes来获取视频帧,还有使用-ss参数来获取,-ss后的时间参数是自行设定,并且在视频的有效时间内(格式为00:00:00),使用-ss时,如果没有使用%03d.jpeg来作为文件名,则获取的是-ss参数后那个时间的帧;
  • -ar表示使用新的采样率,常用的有8,000Hz、16,000Hz、32,000Hz、44,100Hz;

  具体的代码依然使用Process类实现,可以参照之前的文章FFmpeg在JAVA中的使用-音频提取&字幕压缩

  二、接下来,重点讲一下在使用process.waitFor()发生的阻塞问题

  先介绍一下,这个功能由于11月6日需要演示,所以花了11月3日和4日两天开发完成的,主要流程是添加视频-音频提取-第一帧提取-语音识别-字幕处理-中英翻译,开发完成测试后功能ok,于是开开心心过周末。

  11月5日,周日下午产品经理打电话告诉我,4点开始的视频都没法正确处理了,于是我让他把视频发给我(当时他说这个视频是通过别的视频压缩工具压缩过的)。

  我测试了一下,通过查看log,发现在提取第一帧的时候,卡住了。但是我再次测试以前测试成功的那些视频,都是很顺利地处理完成,于是猜测,视频在压缩的过程中损坏,因为一开始他发视频给我后,我并没有播放,直接测试了,后来我双击播放了一下,竟然全是黑屏,只有声音???

  那么,到现在可以确定,问题确实出现在视频的本身,无法正确提取第一帧。

  可是无法提取第一帧,不应该是提取图片为空吗?为什么卡在那边不动了呢?暂时只能建议产品经理周一演示的时候,不要使用这些压缩损坏的视频,等周一去了之后再看看问题出现在哪。

  11月6日周一上午,到了公司,回想昨天的问题,首先看一下内存使用率(这是公司内部的监控系统,是不是很棒!哈哈哈哈!)

  

  内存图可以展示两个情况:

  1. 11月5日下午4点开始,内存使用率逐步上升,说明那段时间测试了视频,线程一直处于堵塞状态;

  2. 查看了一下dump文件(jmap -dump:live,format=b,file=heap.dmp PID),发现有很多线程在extractVideoFirstFrame方法时阻塞;

    

  3. 11月6日10点半左右,重启了一下应用,内存立马就下来了,可以断定,这就是因为内存使用率上升的原因,如果一直这样下去,肯定会导致OOM。

  三、最后,如何解决process.waitFor()发生的阻塞问题呢?

  一般需要调用系统命令时,使用Runtime.getRuntime().exec(command)返回一个process对象,再调用process.waitFor()来等待命令执行结束,获取执行结果。

  查看waitFor()源码可以发现,其实调用的是Object类中的,wait()方法,并且未指定等待时间,那么如果一直不返回,则会一直阻塞。

  并且查看了JDK的帮助文档,如下

  

  但是,我把执行提取视频第一帧的命令单独拿出来执行,虽然图片未提取成功,但是命令仍然执行结束了,按道理不应该一直堵塞啊???

  

  然后又重新看了一遍JDK的API,看到如下一段话:

  

  因此,可以得出结论:如果外部程序不断在向标准输出流(对于jvm来说就是输入流)和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,最终造成阻塞在waitFor()这里。

  解决方法:

  1. 在waitFor()之前,利用单独两个线程,分别处理process的getInputStream()和getErrorSteam(),防止缓冲区被撑满,导致阻塞;
  2. 记得释放文件流资源,以免导致“Too many open files”的错误;

  代码如下:

    /**
* 处理process输出流和错误流,防止进程阻塞
* 在process.waitFor();前调用
* @param process
*/
private static void dealStream(Process process) {
if (process == null) {
return;
}
// 处理InputStream的线程
new Thread() {
@Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
try {
while ((line = in.readLine()) != null) {
logger.info("output: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
// 处理ErrorStream的线程
new Thread() {
@Override
public void run() {
BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
try {
while ((line = err.readLine()) != null) {
logger.info("err: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
err.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}



FFmpeg进行视频帧提取&音频重采样-Process.waitFor()引发的阻塞超时的更多相关文章

  1. FFmpeg在JAVA中的使用以及Process.waitFor()引发的阻塞问题

    此文已由作者叶海啸授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. FFmpeg是一个开源免费跨平台的视频和音频流方案,可以快速对音视频流进行多方面的处理,本文主要介绍FFmp ...

  2. FFmpeg解码视频帧为jpg图片保存到本地

    FFmpeg解码视频帧为jpg图片保存到本地 - CSDN博客 https://blog.csdn.net/qq_28284547/article/details/78151635

  3. 分享macOS平台好用的视频分割、合并视频、提取音频、分离音频、音频转码的工具CCVideo

    CCVideo 是一款运行在macOS上可分割视频(可多段分割).合并视频.提取音频.分离音频.音频转码的工具,操作方便,只需简单几步,便可轻松完成. 下载地址

  4. 使用ffmpeg进行视频图片提取

    环境:windows10-x64 ffmpeg的功能很强大,可以进行音频和视频的处理,这里记录下需要从视频文件提取图片的情况. ffmpeg官方地址:https://www.ffmpeg.org/使用 ...

  5. 利用ffmpeg获取视频帧

    如果要对视频帧进行处理,可以先把视频帧读取出来. sh文件代码如下: #!/usr/bin/env sh VIDEO=/home/xxx/video/ FRAMES=/home/xxx/frame/ ...

  6. FFmpeg4.0笔记:封装ffmpeg的视频帧转换功能类CSws

    Github https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff CSws.h /************************* ...

  7. Java调用FFmpeg进行视频处理及Builder设计模式的应用

    1.FFmpeg是什么 FFmpeg(https://www.ffmpeg.org)是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.它用来干吗呢?视频采集.视频格式转化.视频 ...

  8. 利用Effmpeg 提取视频中的音频(mp3)

    在B站看到一个up发的病名为爱的钢琴曲,感觉很好听,然后当然是要加入歌单啊.然而不知道怎么转换成mp3,找来找去找到了EFFmpeg 这篇只是达到了我简单的需求,以后可能会有EFFmpeg更详细的使用 ...

  9. 如何用FFmpeg API采集摄像头视频和麦克风音频,并实现录制文件的功能

    之前一直用Directshow技术采集摄像头数据,但是觉得涉及的细节比较多,要开发者比较了解Directshow的框架知识,学习起来有一点点难度.最近发现很多人问怎么用FFmpeg采集摄像头图像,事实 ...

随机推荐

  1. collaborative filtering协同过滤

    每次我想看电影的时候,都会去问我的朋友,小健.一般他推荐的电影,我都比较喜欢.显然不是所有人都有小健这样的能力.因为我碰巧和小健有类似的品味. 这个生活中的经验,实际上有着广泛的用途. 当系统需要为某 ...

  2. 分享自己使用的在线UML画图工具

    刚接触UML时间不长,看了N多教学视频,下载好了几个软件各种不习惯 当我遇见了ProcessOn  从此我彻底“爱上”了它! http://www.processon.com/ UML各类例图它几乎全 ...

  3. Flask restful API如何解决跨站请求问题

    如果像下面这样只是在return的response添加header是不行的: response = make_response(jsonify(response=get_articles(ARTICL ...

  4. linux的cd命令

    面试时被问到了一个命令是什么意思 cd - 还真是一脸懵逼.... 回来试了下 发现真的是一个神奇的命令~ 会跳到之前目录下并输出, 比如

  5. atom编辑器社区插件推荐

    atom是github出品的文本编辑器,为开发者又提供了一款易用.牛逼的文本编译器.在开始接触前端并从工作开始一直用webstrom来进行前端开发,开始使用时,被他各种强大神奇的功能给折服:支持zen ...

  6. 【BZOJ3555】 [Ctsc2014]企鹅QQ

    BZOJ3555 [Ctsc2014]企鹅QQ Solution 只需要前缀Hash,然后考虑每一段的贡献就好了!!! 代码实现 #include<stdio.h> #include< ...

  7. MariaDB 库的基本操作(2)

    MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可MariaDB的目的是完全兼容MySQL,包括API和命令行,MySQL由于现在闭源了,而能轻松成为MySQ ...

  8. [HNOI2015]开店(树剖+主席树+标记永久化)

    听说正解点分树?我不会就对了 此题是 \([LNOI2014]LCA\) 强化版,也是差分一下,转化为区间加区间和 不过权值有大小要求,那么我们按照权值排序,依次加入主席树,询问的时候 \(lower ...

  9. 一步步Cobol 400 上手自学入门教程03 - 数据部

    数据部的作用 程序中涉及到的全部数据(输入.输出.中间)都要在此定义,对它们的属性进行说明.主要描述以下属性: 数据类型(数值/字符)和存储形式(长度) 数据项之间的关系(层次和层号) 文件与记录的关 ...

  10. C#简单操作MongoDB

    一 安装MongoDB 官网按需下载, 安装, 一步到位. 二 VS创建新项目 创建一个.netcore console项目, 然后nuget安装驱动MongoDB.Driver 三 建立连接 在Pr ...