由于产品需要对视频做一系列的解析操作,利用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获取视频帧

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

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

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

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

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

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

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

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

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

  9. ffmpeg-python 任意提取视频帧

    ▶ 环境准备 1.安装 FFmpeg 音/视频工具 FFmpeg 简易安装文档 2.安装 ffmpeg-python pip3 install ffmpeg-python 3.[可选]安装 openc ...

随机推荐

  1. html_02之表单、其它

    1.表单属性action:处理表单数据服务器端处理程序地址,默认提交本页: 2.表单属性method:①get:明文,数据显示地址栏,长度<2KB,向服务器请求数据时使用:②post:密文,提交 ...

  2. Win7下VS2010使用“ASP.Net 3.5 Claims-aware Template”创建ClaimsAwareWebSite报&quot;HRESULT: 0x80041FEB&quot;错误的解决办法

    问题描述: 使用VS2010的WIF开发模板创建“Claims-aware ASP.NET Site”.“Claims-aware WCF Service”,下载安装后,创建网站时,报错"H ...

  3. Ajax的实现

    一.JavaScript的ajax //Ajax var xhr; if(window.XMLHttpRequest){ //除IE外的浏览器 xhr = new XMLHttpRequest() } ...

  4. CSS: Float a div on another div, Ex: Text caption on picture

    <style type="text/css"> .figure { width: 316px; height: 205px; display: block; borde ...

  5. 【git】借助github学习成果

    1.创建分支 git branch dev   //创建分支 git checkout dev  //切换分支 或者用一句  git checkout -b dev 删除一个分支  git check ...

  6. 飘逸的python - 理解打开文件的模式

    当我们用open()函数去打开文件的时候,有好几种打开的模式.   'r'->只读 'w'->只写,文件已存在则清空,不存在则创建. 'a'->追加,写到文件末尾 'b'->二 ...

  7. 走进C标准库(1)——assert.h,ctype.h

    默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进C标准库. 自己就是菜鸟一只,第一次具体看C标准库,文章参杂了对<the standard C library>的阅读和对源码的一些 ...

  8. genymotion ddms查看data等文件目录

    使用ADB shell 命令: 打开 Cmd  ,输入  ADB shell 命令后,回车(前提是你已经配置好了adb 的环境变量,跟配置Java的环境变量一样); 输入su回车,获取超级管理员权限 ...

  9. 自动化测试 | UI Automator 入门指南

    自动化测试的定义,这里先引用一段维基百科的定义: 在软件测试中,测试自动化(英语:Test automation)是一种测试方法,使用特定的软件,去控制测试流程,并比较实际的结果与预期结果之间的差异. ...

  10. MoveIt! 源安装

    rosdep update sudo apt-get update sudo apt-get dist-upgrade sudo apt-get install python-wstool pytho ...