由于产品需要对视频做一系列的解析操作,利用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. DDL和DML的区别

    DML(data Manipulation Language)数据库操纵语言: 使用范围:对数据库中的数据进行一些简单的操作,如IDUS(增删改查) DDL(Data Definiton Langua ...

  2. struts2 18拦截器详解(十)

    ModelDrivenInterceptor 该拦截器处于defaultStack中的第九的位置,在ScopedModelDrivenInterceptor拦截器之后,要使该拦截器有效的话,Actio ...

  3. JAVA的初始化顺序

    这里主要是介绍JAVA的类的初始化顺序,比较基础:主要是以例子演示为主: 例子一: 1 package com.cnblog.GDUTtiantian; 2 3 /** 4 * 5 * @author ...

  4. 数据单位bit byte kb Mb Gb

    8 bit = 1 byte 2^10 bytes = 1 kb 2^10 kb = 1 Mb 2^10 Mb = 1Gb 2^32 bit = 2^2 * 2^10 * 2^10 * 2^10 bi ...

  5. tensorflow 安装命令

    sudo pip install --upgrade --ignore-installed six tensorflow-0.9.0-py2-none-any.whl

  6. Grid++repor报表连接事件

    //定义报表模板 private GridppReport Report = new GridppReport(); //载入报表模板数据 Report.LoadFromFile(GridppRepo ...

  7. 浏览器环境下JavaScript脚本加载与执行探析之defer与async特性

    defer和async特性相信是很多JavaScript开发者"熟悉而又不熟悉"的两个特性,从字面上来看,二者的功能很好理解,分别是"延迟脚本"和"异 ...

  8. 使用Flexbox:新旧语法混用实现最佳浏览器兼容

    Flexbox非常的棒,肯定是未来布局的一种主流.在过去的几年这之中,语法改变了不少,这里有一篇“旧”和“新”新的语法区别教程(如果你对英文不太感兴趣,可以移步阅读中文版本).但是,如果我们把Flex ...

  9. 03-创建高可用 etcd 集群

    本文档记录自己的学习历程! 创建高可用 etcd 集群 kuberntes 系统使用 etcd 存储所有数据,本文档介绍部署一个三节点高可用 etcd 集群的步骤,这三个节点使用以下机器: 192.1 ...

  10. 【xsy2194】Philosopher set+线段树合并

    题目大意:给你一个长度为$n$的序列,有$m$次操作,每次操作是以下两种之一: 对某个区间内的数按照升序/降序排序,询问某个区间内数的积在十进制下首位数字是多少. 数据范围:$n,m≤2\times ...