参考 https://github.com/transitive-bullshit/ffmpeg-gl-transition
插件本身支持 GPU 加速功能,需要用到 EGL 安装模式,本案例没有使用 EGL,部署环境为 Ubuntu 18.04
注意0:按照 git 教程来反正我的 Ubuntu 是死活启动失败,报如下错误,最后按照 Dockerfile 来安装才可以正常运行,花费了好长时间,告诫需要的朋友们。
[AVFilterGraph @ 0x55c5007bc180] Error initializing filter 'gltransition'
Error initializing complex filters.
Operation not permitted
注意1:如果是在没有显示设备的服务器上安装运行,需要安装xvfb
,然后在 ffmpeg 的执行命令前加xvfb-run -a -s '+iglx -screen 0 1920x1080x24'
,该命令的具体含义参考四、docker 环境下的开发
。
$ sudo apt-get -y update && apt-get -y upgrade
$ sudo apt-get -y install gcc g++ make xorg-dev pkg-config \
libglew2.0 libglew-dev libglfw3-dev \
nasm yasm libx264-dev libx265-dev libvpx-dev libglu1-mesa-dev \
libmp3lame-dev libopus-dev libfdk-aac-dev
$ cd ~
$ git clone https://github.com/transitive-bullshit/ffmpeg-gl-transition.git
$ cd ffmpeg-gl-transition
$ git clone https://github.com/gl-transitions/gl-transitions.git
$ cd ..
$ wget https://www.ffmpeg.org/releases/ffmpeg-4.2.2.tar.gz
$ tar -zxvf ffmpeg-4.2.2.tar.gz
$ grep -v "define GL_TRANSITION_USING_EGL" \
ffmpeg-gl-transition/vf_gltransition.c > \
ffmpeg-4.2.2/libavfilter/vf_gltransition.c
$ cd ffmpeg-4.2.2/
$ git apply ../ffmpeg-gl-transition/ffmpeg.diff
$ ./configure \
--enable-libx264 \
--enable-libx265 \
--enable-libvpx \
--enable-libfdk-aac \
--enable-libmp3lame \
--enable-libopus \
--enable-nonfree \
--enable-gpl \
--enable-opengl \
--enable-filter=gltransition \
--extra-libs='-lGLEW -lglfw -ldl'
$ make -j
$ sudo make install
$ sudo apt-get -y install xvfb
查看 ffmpeg 是否安装成功:
$ ffmpeg
ffmpeg: error while loading shared libraries: libGLEW.so.2.1: cannot open shared object file: No such file or directory
查看 ffmpeg 的时候提示找不到 libGLEW.so.2.1,是因为该文件在 /usr/lib64/ 路径下,ffmpeg 从 /usr/lib/ 路径下查找
$ sudo ln -s /usr/lib64/libGLEW.so.2.1 /usr/lib/libGLEW.so.2.1
$ ffmpeg
ffmpeg version 4.2.2 Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 7 (Ubuntu 7.4.0-1ubuntu1~18.04.1)
configuration: --enable-libx264 --enable-gpl --enable-opengl --enable-filter=gltransition --extra-libs='-lGLEW -lglfw'
libavutil 56. 31.100 / 56. 31.100
libavcodec 58. 54.100 / 58. 54.100
libavformat 58. 29.100 / 58. 29.100
libavdevice 58. 8.100 / 58. 8.100
libavfilter 7. 57.100 / 7. 57.100
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
Use -h to get full help or, even better, run 'man ffmpeg'
查看 ffmpeg-gl-transition 是否安装上
$ ffmpeg -v 0 -filters | grep gltransition
T.. gltransition VV->V OpenGL blend transitions
$ ffmpeg \
-t 1 -loop 1 -i input0.jpg \
-t 1 -loop 1 -i input1.jpg \
-filter_complex \
"gltransition=offset=0.5:duration=0.5:source=/home/jl/ffmpeg-gl-transition/gl-transitions/transitions/crosswarp.glsl" \
-y out.mp4
效果如下图:
参数:
注意: 该表达式只是一个简单的事例,合成视频的时长为第二个视频的时长。
$ ffmpeg -hide_banner \
-t 3 -loop 1 -i input0.jpg \
-t 3 -loop 1 -i input1.jpg \
-t 2 -loop 1 -i input2.jpg \
-stream_loop -1 -i music.mp3 -acodec aac \
-filter_complex "\
[0]split[v_sp_0_0][v_sp_0_1];[v_sp_0_0]trim=0:2[v_tr_0_0];[v_sp_0_1]trim=2:3[v_tr_0_1];[v_tr_0_1]setpts=PTS-STARTPTS[v_st_0];\
[1]split[v_sp_1_0][v_sp_1_1];[v_sp_1_0]trim=0:2[v_tr_1_0];[v_sp_1_1]trim=2:3[v_tr_1_1];[v_tr_1_1]setpts=PTS-STARTPTS[v_st_1];\
[v_st_0][v_tr_1_0]gltransition=duration=1:source=/home/jl/ffmpeg-gl-transition/gl-transitions/transitions/SimpleZoom.glsl[v0];\
[v_st_1][2]gltransition=duration=1:source=/home/jl/ffmpeg-gl-transition/gl-transitions/transitions/CrossZoom.glsl[v1];\
[v_tr_0_0][v0][v1]concat=n=3[v];\
afade=t=out:st=5:d=2" \
-map "[v]" \
-map "3:a" \
-t 7 \
-shortest \
-c:v libx264 \
-profile:v main \
-pix_fmt yuv420p \
-preset fast \
-y \
out.mp4
参数:
如上背景图为 1080x1920 尺寸的,中间的透明区域为 1080x720 的,当我们需要将上面的图片合成的视频以如下背景图作为背景的时候,那么我们的视频尺寸就必须缩放为 1080x720 的视频,我们当然可以通过 -s 1080x720 来缩放上面生成的视频,但是会存在视频变形的情况,我们可以通过如下命令来等比例缩放图片从而一步到位生成带背景的视频。
$ ffmpeg -hide_banner \
-t 3 -loop 1 -i input0.jpg \
-t 3 -loop 1 -i input1.jpg \
-t 2 -loop 1 -i input2.jpg \
-i bg.png \
-stream_loop -1 -i music.mp3 -acodec aac \
-filter_complex "\
[0]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),pad=1080:720:(1080-iw)/2:(720-ih)/2[p0];\
[1]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),pad=1080:720:(1080-iw)/2:(720-ih)/2[p1];\
[2]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),pad=1080:720:(1080-iw)/2:(720-ih)/2[p2];\
[p0]split[v_sp_0_0][v_sp_0_1];[v_sp_0_0]trim=0:2[v_tr_0_0];[v_sp_0_1]trim=2:3[v_tr_0_1];[v_tr_0_1]setpts=PTS-STARTPTS[v_st_0];\
[p1]split[v_sp_1_0][v_sp_1_1];[v_sp_1_0]trim=0:2[v_tr_1_0];[v_sp_1_1]trim=2:3[v_tr_1_1];[v_tr_1_1]setpts=PTS-STARTPTS[v_st_1];\
[v_st_0][v_tr_1_0]gltransition=duration=1:source=/home/jl/ffmpeg-gl-transition/gl-transitions/transitions/SimpleZoom.glsl[v0];\
[v_st_1][p2]gltransition=duration=1:source=/home/jl/ffmpeg-gl-transition/gl-transitions/transitions/CrossZoom.glsl[v1];\
[v_tr_0_0][v0][v1]concat=n=3[out];\
[3][out]overlay=0:600[v];\
afade=t=out:st=5:d=2" \
-map "[v]" \
-map "4:a" \
-t 7 \
-shortest \
-c:v libx264 \
-profile:v main \
-pix_fmt yuv420p \
-preset fast \
-y \
out.mp4
参数:
pad
指定尺寸不足的地方以黑色背景填充。force_original_aspect_ratio
参数,decrease
指定图片缩小,increase
扩大。合成视频效果如下
注意:有时候会因为生成视频的采样纵横比不同而报如下错误
[Parsed_concat_16 @ 0x55f8751e47c0] Input link in2:v0 parameters (size 1080x720, SAR 0:1) do not match the corresponding output link in0:v0 parameters (1080x720, SAR 1214:1215)
[Parsed_concat_16 @ 0x55f8751e47c0] Failed to configure output pad on Parsed_concat_16
Error reinitializing filters!
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #4:0
Conversion failed!
SAR :Sample aspect ratio,采样纵横比。
concat 滤波器要求它的所有视频输入具有相同的分辨率和采样纵横比,报错信息显示SAR 1214:1215
,近乎正方形1:1
,所以我们可以在图片缩放生成视频的时候指定采样纵横比为正方形setsar=1/1
从而解决该问题。
[0]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),setsar=1/1,pad=1080:720:(1080-iw)/2:(720-ih)/2[p0];\
[1]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),setsar=1/1,pad=1080:720:(1080-iw)/2:(720-ih)/2[p1];\
[2]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),setsar=1/1,pad=1080:720:(1080-iw)/2:(720-ih)/2[p2];\
思路为先将图片合成高斯模糊背景视频,然后将生成的视频覆盖到背景视频上。原图为 1200x800,要想生成 3 的效果,就要将当前视频的图片缩放为 2880x1920,然后截取中间的 1080x1920 部分。下面命令前 3 个输入图片是作为高斯背景合成视频使用的。
$ ffmpeg -hide_banner \
-t 2 -loop 1 -i input0.jpg \
-t 2 -loop 1 -i input1.jpg \
-t 2 -loop 1 -i input2.jpg \
-t 3 -loop 1 -i input0.jpg \
-t 3 -loop 1 -i input1.jpg \
-t 2 -loop 1 -i input2.jpg \
-stream_loop -1 -i music.mp3 -acodec aac \
-filter_complex "\
[0][1][2]concat=n=3[bout];\
[bout]scale=2880:1920[bv0];\
[bv0]crop=1080:1920:900:0[bv1];\
[bv1]avgblur=sizeX=90[bv2];\
[bv2]eq=contrast=1:brightness=-0.1[bv];\
[3]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),pad=1080:720:(1080-iw)/2:(720-ih)/2[p0];\
[4]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),pad=1080:720:(1080-iw)/2:(720-ih)/2[p1];\
[5]scale=min(iw*720/ih\,1080):min(720\,ih*1080/iw),pad=1080:720:(1080-iw)/2:(720-ih)/2[p2];\
[p0]split[v_sp_0_0][v_sp_0_1];[v_sp_0_0]trim=0:2[v_tr_0_0];[v_sp_0_1]trim=2:3[v_tr_0_1];[v_tr_0_1]setpts=PTS-STARTPTS[v_st_0];\
[p1]split[v_sp_1_0][v_sp_1_1];[v_sp_1_0]trim=0:2[v_tr_1_0];[v_sp_1_1]trim=2:3[v_tr_1_1];[v_tr_1_1]setpts=PTS-STARTPTS[v_st_1];\
[v_st_0][v_tr_1_0]gltransition=duration=1:source=/home/jl/ffmpeg-gl-transition/gl-transitions/transitions/SimpleZoom.glsl[v0];\
[v_st_1][p2]gltransition=duration=1:source=/home/jl/ffmpeg-gl-transition/gl-transitions/transitions/LinearBlur.glsl[v1];\
[v_tr_0_0][v0][v1]concat=n=3[out];\
[bv][out]overlay=0:600[v];\
afade=t=out:st=5:d=2" \
-map "[v]" \
-map "6:a" \
-t 7.0 \
-shortest \
-c:v libx264 \
-profile:v main \
-pix_fmt yuv420p \
-preset fast \
-y \
out.mp4
参数:
(1) 参考官网 https://docs.docker.com/install/linux/docker-ce/ubuntu/ 安装 docker 。
(2) Docker 需要用户具有 sudo 权限,为了避免每次命令都输入sudo,可以把用户加入 Docker 用户组 官方文档
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ newgrp docker
$USER 为你需要赋权限的用户名
(1) 复制 ffmpeg-gl-transition 项目中的 Dockerfile 文件,并创建 image 文件,大概需要十几分钟的时间,视机器配置和网络状况而定。
$ mkdir docker-ffmpeg
$ cp ../docker-ffmpeg/Dockerfile .
$ docker image build -t docker-ffmpeg .
(2) 查看 image 文件并启动容器
注意:docker 访问宿主机文件需要挂载宿主机目录,指定目录后 docker 的所有文件操作都要在这个目录下进行,即下文指定的-v /home/jl:/home/jl
。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-ffmpeg latest 079580061992 3 days ago 1.96GB
debian stretch f6c68e2ad82a 3 weeks ago 101MB
$ id jl
uid=1000(jl) gid=1000(jl) 组=1000(jl),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),126(sambashare),1001(docker)
$ docker container run -d -u 1000:1000 -it -v /home/jl:/home/jl docker-ffmpeg
参数:
$ docker container ls --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
850e26f669c7 docker-ffmpeg "/bin/sh -c /bin/bash" 3 days ago Exited (137) 2 days ago cool_dubinsky
$ docker container start 850e26f669c7
850e26f669c7
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
850e26f669c7 docker-ffmpeg "/bin/sh -c /bin/bash" 3 days ago Up 5 seconds cool_dubinsky
$ docker exec 850e26f669c7 xvfb-run -a -s '+iglx -screen 0 1920x1080x24' ffmpeg
ffmpeg version N-96379-g0dc0837960 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
configuration: --enable-libx264 --enable-libx265 --enable-libvpx --enable-libfdk-aac --enable-libmp3lame --enable-libopus --enable-nonfree --enable-gpl --enable-opengl --enable-filter=gltransition --extra-libs='-lGLEW -lglfw -ldl'
libavutil 56. 38.100 / 56. 38.100
libavcodec 58. 65.103 / 58. 65.103
libavformat 58. 35.102 / 58. 35.102
libavdevice 58. 9.103 / 58. 9.103
libavfilter 7. 71.100 / 7. 71.100
libswscale 5. 6.100 / 5. 6.100
libswresample 3. 6.100 / 3. 6.100
libpostproc 55. 6.100 / 55. 6.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
Use -h to get full help or, even better, run 'man ffmpeg'
参数
上面的视频合成的 ffmpeg 命令都可以通过 docker 容器来运行。
注意:文件路径都要用绝对路径,否则会提示找不到文件。
参考文献:
ffmpeg-gl-transition
gl-transitions
GLTransitions
ffmpeg 官网文档
ffmpeg - 将两个文件合并到ffmpeg时,视频编辑得到异常
ffmpeg实现同视频做模糊背景并前景正常播放
Docker 入门教程
docker挂载volume的用户权限问题,理解docker容器的uid