使用ffmpeg截取视频封面并批量上传

时间:2023-03-08 19:58:09

需求:将视频文件压入zip包,然后上传服务器.服务器对zip解压,使用bat/shell,使用ffmpeg对视频进行封面截取.再使用OSS对视频和封面进行批量上传.最后将信息存入数据库

遇到的问题

1.bat批量截取视频封面

  • 在之前的代码中,遍历视频解压后的目录.通过ProcessBuilder调用bat/shell对某一个视频进行封面截取.然后再上传.这一次更改了方案,直接调用一次bat/shell文件对所有视频截取封面.
  • 很显然想到了要在bat/shell中进行循环.在bat循环中要注意 bat for循环 变量赋值的问题.

bat for循环 变量赋值的问题

  • 预处理机制:批处理读取命令时是按行读取的(另外例如 for 命令等,其后用一对圆括号闭合的所有语句也当作一行),在处理之前要完成必要的预处理工作,这其中就包括对该行命令中的变量赋值。在不启用变量延迟,也不对变量动态捕获其扩展变化时,变量在预处理阶段不作改变
  • setlocal enabledelayedexpansion ,就是启用变量延迟,我们可以形象的认为是启用了“对变量动态捕获扩展变化”。而 ! 括起来的变量,就是要动态捕获扩展的目标变量,如果不需要,可以继续使用 % 括变量。
  • 在调用该类型变量时也应注意,不是使用 %var% 而是使用 !var!
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /r D:\upload\zip\out\ %%i in (*.mp4) do (
set mp4=%%i
set res=!mp4:~0,-4!_pic.jpg
D:\ffmpeg\bin\ffmpeg.exe -i !mp4! -y -f image2 -t 0.001 !res!)
)

2.ffmpeg存在部分视频截取不到封面问题

  • 在使用ffmpeg的过程中发现存在部分视频截取不到的情况,通过尝试后发现是 -ss参数导致

    原始代码:
ffmpeg.exe  -ss 3 -i a.mp4  -y -f image2 -t 0.001 -s 300*240 a_pic.jpg

ss参数表示截取第几秒,存在截取不到的原因之一为视频没有那么长.估计还有其他原因,这里没有深究

3.ffmpeg截取封面图片尺寸大小问题

  • 代码如上. -s 参数后面可以指定所要截取出的图片的大小.移动端使用后反馈图片像素和视频像素存在差别.[需要 封面图片 和 视频像素大小一致] 在尝试后发现如果不加 -s 参数 那么默认生成的图片和视频像素一致.

4.使用ProcessBuilder调用bat/shell导致的进程挂起问题

  • 在普通java程序中使用ProcessBuilder调用bat/shell去截取封面,没有问题.但是在web工程中发现调用bat/shell 后,只会截取第一个视频的封面,然后一直卡着.直到停止web工程.然后bat/shell程序才会继续执行,生成所有的封面图片.从现象可以看出,排除bat/shell脚本问题.一定是程序和bat/shell进行交互的地方卡住了.
  • 问题解决参考博文:http://blog.****.net/sj13051180/article/details/47865803

使用Java代码调用shell脚本,执行后会发现Java进程和Shell进程都会挂起,无法结束。

挂起原因

  1. 主进程中调用Runtime.exec会创建一个子进程,用于执行shell脚本。子进程创建后会和主进程分别独立运行。
  2. 因为主进程需要等待脚本执行完成,然后对脚本返回值或输出进行处理,所以这里主进程调用Process.waitfor等待子进程完成。
  3. 通过shell脚本可以看出:子进程执行过程就是不断的打印信息。主进程中可以通过Process.getInputStream和Process.getErrorStream获取并处理。
  4. 这时候子进程不断向主进程发生数据,而主进程调用Process.waitfor后已挂起。当前子进程和主进程之间的缓冲区塞满后,子进程不能继续写数据,然后也会挂起。
  5. 这样子进程等待主进程读取数据,主进程等待子进程结束,两个进程相互等待,最终导致死锁。

解决方法

  • 基于上述分析,只要主进程在waitfor之前,能不断处理缓冲区中的数据就可以。因为,我们可以再waitfor之前,单独启两个额外的线程,分别用于处理InputStream和ErrorStream就可以。