一、背景介绍
将ffmpeg运用到项目上已经有一段时间了,趁现在有空赶紧记下来。
二、技术点总结
2.1 实现方式
项目里面主要运用的形式是,在java端,调用操作系统的方法,并执行切片命令。
在执行切片之前,出于对代码的健壮性考虑,一般会下意识地对文件和目标地址进行检查和创建路径。
这里除了,判断传入的String对象是否为空之外,还需要对实际的文件进行判断以及目标地址的路径是否存在。这样可以在发布上线之后避免很多问题。
2.2 时长的获得
除了切片还需要,统计被切片的文件时长,这个是后来的需求。针对这个问题,有两种解决方案,一种是调用以下两个依赖包
import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.MultimediaInfo;
即使用jave的包去解决,但实际原理也是使用ffmpeg的方式去截取时间长短。我使用过这个方案,除了遇到了maven库下载不到,并且需要自己去官网下载,并上传到本地库这一系列操作之后,我仍然遇到了时不时的空指针异常。
这个错误,让我很抓狂,尤其这个jave这个东西我并不熟悉的情况下。第二种方案,偶然的情况下 我执行ffmpeg命令的时候发现
其实是有duration 这个数值的。那么我当时就想,是不是我执行命令并把返回的内容进行截取,再转换我就可以得到视频的时长。于是这就是第二个方案,并且已经在使用了。这个方法更加稳定,并且依赖性更少。、
2.3 切片请求的实现
其实切片这个操作,主要是对cpu 有高的要求,同时系统又要求实时。所以我采取的办法,是通过nginx 来分发切片的请求,并且把切片服务独立出来,并用线程池的方式来实现。
这样,需要切片的主业务程序,只需要将切片的相关参数发给切片服务,切片服务接受到参数之后立即返回接受成功,等到切片完成之后,再回调主业务的结果接收接口即可。说起来负责,画图就很简单,见下图:
在发送切片请求的时候,实际上是被nginx拦截的,然后平均转发到几台后台切片服务,这样子就可以避免大量的切片任务会导致单点切片直接卡死(具体表现就是切片切到一定程度,就停止了,我还没找到具体原因,但是我怀疑跟linux 最大文件数限制有有关系)。
这里要注意监控服务器的cpu相关属性 (top 、sar -u)等
2.4 结果的记录
在之前的方案中,实际上只采取的各个切片服务直连数据库的方式。当完成切片任务之后,就直接连数据库去修改。后来,我想了一下,这个方案是有问题的,尤其是在多点部署的情况下。如果同样的切片请求,被请求两次,并且被转发到不同的节点,这样子不仅切片相互会干扰,同时,在去数据库记录update的时候,有可能会导致死锁。后来将这个方式改为回调接口,把连接数据库的session归拢到主业务中去。
2.5 待完善
事实上,这个业务模块还有很多需要完善的,比如系统的资源监控防止异常的任务波动,日志报警,消息队列来接受切片请求,并且防止重复执行切片任务以及最重要的 切片优化(语句的优化以及 后期考虑上GPU的想法)等。还有,在返回的时候标记这个任务是哪台机器执行的。这样更好的方便,事后,去追溯问题的原因。
三、总结
做完这个项目之后,越发地感觉把任务拆分成为一个一个简单的单元的重要性(WBS)。构建高内聚,低耦合的系统,也不再是一句口号。是需要认真去思考的,并且一个无法回避的问题。