本人的Blog是建在自己的私有云上的,之前在《有了云服务器能够做什么》中简略提及过我在小云上跑了不少的使用服务,其中就有为Blog供给视频播映功用NextCloud。尽管后来我觉得NextCloud并不那么实用,还很占用体系资源,所以用相对更轻量的WebDAV服务替换了NextCloud,但它仍然为一款不错的私家网盘使用服务。另外经过网盘共享资源的办法,完成视频点播对小云的体系资源耗费也是挺大的,所以我又想办法《让小云支撑视频在线播映》,即便如此,关于我的1G2G的丐版装备,仍然有不小的资源压力。

  终究我的解决方案是,Blog中的视频都用GIF代替,耗费资源的事儿就交给客户端想办法吧☺。可问题又来了,我的主力电脑体系是Linux(Deepin、Ubuntu),怎样才干把视频转化成GIF呢?

运用在线转化东西

  这类在线东西,用百度查找一下视频转GIF,就能出来许多成果。可是好用的却不太多,假如视频比较大,尽管界面上显现转化完成,可是实际上却什么都没有,比方这样的:

基于Linux命令行实现将视频文件快速转GIF文件

  有些在线东西转化的成果又会添加水印或其它什么东西,总归,作用并不是特别理想

运用软件东西

  假如是在Windows渠道上的话,有许多优秀的东西能够运用,比方FastStone Capture、Screen2GIF等,而且运用也很便利。关于Linux渠道上,尽管没有那么多可挑选的使用,可是仍然有优秀的东西,比方Peek便是一款优秀的Linux渠道视频录制转GIF东西。

  细细研究一下Linux渠道的使用软件,能发现大多都是利用各种开源组件或模块组合在一起的,比方Peek中GIF功用便是利用了gifski,那么常用的组件有哪些呢?在Linux渠道上,常用的有 ffmpeg、convert以及刚刚提到的gifski。

运用三方组件

FFmpeg

  FFmepg算是Linux渠道用处最广、运用频率最高的开源组件了,不管是视频播映、仍是视频后期处理,乃至视频推流都离不开FFmpeg,几乎一切涉及多媒体的东西都能够找到FFmpeg组件。

FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created. It supports the most obscure ancient formats up to the cutting edge. No matter if they were designed by some standards committee, the community or a corporation. It is also highly portable: FFmpeg compiles, runs, and passes our testing infrastructure FATE across Linux, Mac OS X, Microsoft Windows, the BSDs, Solaris, etc. under a wide variety of build environments, machine architectures, and configurations.

  作为视频处理一哥,将视频转化为GIF,天然不在话下,合作简略的参数即可完成。

用法

ffmpeg -i test.mp4 ffmpeg.gif,这句指令的意思是将test.mp4依照其视频分辨率、帧率转化为ffmpeg.gif文件。假如想调整生产GIF文件的参数,能够合作以下参数完成:

-ss time_off: 从指定的时刻(单位为秒)开端,支撑[-]hh:mm:ss[.xxx]的格式

-t duration : 指定时长

-r rate : 帧速率(fps)

-s size : 指定分辨率

  当然FFmpeg的参数可不止这点,还支撑许多的操作,比方按比例缩放-vf scale等等,有兴起的能够去网上查找下相关的介绍,这儿就不过多展开了。

装置

  一般来说主流的Linux发行版都支撑指令行直接装置,网上查找一下就能找到,比方:

apt install ffmpeg
yum install ffmpeg

  经过指令行装置,尽管便利,可是ffmpeg版别一般比较低(与主机版别能更好的兼容)。假如想测验新的功用,请确认当时版别可支撑。

  另一种办法是经过源码进行编译装置,优点在于能用上最新版别的ffmpeg,不过编译进程稍显费事。因为不同的Linux发行版,编译办法也略有不同,可在网上查找一下最新的编译办法,大致步骤如下:

./configure
make
make install

Convert

  Convert并不是一个独立的组件或使用,它只是ImageMagick供给的一个图画转化功用。所以假如想在Linux渠道上运用Convert,则需要完好装置ImageMagick才行。

Use ImageMagick to create, edit, compose, or convert digital images. It can read and write images in a variety of formats (over 200) including PNG, JPEG, GIF, WebP, HEIC, SVG, PDF, DPX, EXR and TIFF. ImageMagick can resize, flip, mirror, rotate, distort, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and Bzier curves.

  convert尽管只是ImageMagick的子功用,可是其功用也是很丰厚的。

用法

比方这样:

#转化图片格式,支撑JPG, BMP, PCX, GIF, PNG, TIFF, XPM和XWD等类型
convert xxx.jpg xxx.png   #讲jpeg转化为png文件
#改动图画巨细
convert -resize 1024x768 xxx.jpg  xxx1.jpg #将图画的像素改为1024768(留意1024与768之间是小写字母x)
*convert -sample 50%x50% xxx.jpg  xxx1.jpg #将图画缩小为本来的50%50%
#旋转图画
*convert -rotate 270 sky.jpg sky-final.jpg #将图画顺时针旋转270度 
#为图画加上文字
*convert -fill black -pointsize 60 -font helvetica -draw 'text 10,80 "hello world ! "' #xxx.jpg xxx1.jpg在图画的10,80方位用60磅全黑Helvetica字体上写hello world!
#批量文件格式转化
mogrify -path newdir -format png *.jpg

  关于视频转GIF,则能够经过将视频按帧,拆分为许多许多的单张图片,然后将这些单张图片再兼并为一个GIF图片。图片兼并可用下面的指令:

convert -delay 10 -loop 0 *.png convert.gif

  这句指令的意思是将一切png图片转化为一张GIF文件,这儿用到了2个新的参数-delay-loop,它们的界说别离是:

-delay value         间隔多久(毫秒)显现下一张图片
-loop iterations     在文件中添加循环播映标志

  看到这儿天然就会发现一个问题,假如我的png图片足够多,或者单张png图片足够大(比方4K分辨率),那么合成的GIF文件是不是就越大?假如我构造一个足够多,且文件足够大的图库,然后履行convert转化为GIF,是不是会把主机的资源悉数占完?OOM?这个假设完全没毛病,实际情况也的确这样,再需要转化超大文件的时候convert常常会报cache resources exhausted反常。

反常处理

  一般来说convert报cache类的反常都是因为没有足够的体系资源用于转化图片导致。不过值得幸亏的是,convert并不是将体系一切资源耗费光了,才报这样的反常,主机体系仍然能够正常作业运行。

  这得益于convert自己的内存分配战略。经过指令convert -list policy能够查询当时体系下convert的内存战略。

Path: /etc/ImageMagick-6/policy.xml Policy: Resource name: disk value: 2GiB Policy: Resource name: map value: 1GiB Policy: Resource name: memory value: 512GiB … … Policy: Coder rights: None pattern: XPS

Path: [built-in] Policy: Undefined rights: None

  从回来的成果中,能看到policy装备文件的途径以及各种场景下的内存装备巨细,能够根据需要修正policy装备文件中对应的子项即可。

装置

  和FFmpeg相同,主流的Linux发行版都能够经过指令行直接装置。

apt install imagemagick
yum install imagemagick

  也能够经过官网下载已编译好的二进制文件或封装包,运用装置指令进行装置。

GifSki

  GifSki是独立的开源软件,其目标便是将视频转化为更优的GIF,支撑简略的参数装备,由于其现在并未布置在常见的使用仓库中,所以只能经过Rust进行装置。

gifski converts video frames to GIF animations using pngquant’s fancy features for efficient cross-frame palettes and temporal dithering. It produces animated GIFs that use thousands of colors per frame.

It’s open-source! It’s a CLI tool, but it can also be compiled as a library for seamless use in other apps ([ask me](mailto: kornel@pngquant.org?) or get a commercial license if you want to use it in a closed-source app or web service).

  上面介绍的几种东西都能够完成视频转GIF,那么他们究竟谁才是最优(转化作用最好)的挑选呢?接着咱们就别离试试看。

用法

  GifSki和FFmepg相同,支撑直接从视频转化为GIF文件。

gifski -fps 10 -width 320 -o result.gif test.mp4

  上面的比如将“test.mp4”文件转化为GIF,最大分辨率为320像素,每秒10帧。

  当然也和convert相同,支撑将许多的PNG图片。按帧率生成GIF文件。

gifski -o result.gif *.png

作用对比

  那么它们转化作用究竟怎样样呢?咱们对同一个视频(1920 1080)文件(27M)进行转化,看看转化之后是什么样。

ffmpeg -i test.mp4 -r 5 ffmpeg.gif
ffmpeg -i test.mp4 -r 5  tmp/frame%04d.png
gifski --width 1920 -o gifski.gif tmp/frame*.png
convert -delay 10 -loop 0 tmp/frame*.png convert.gif

  转化之后会发现一个共性问题,不管哪一种办法转化的GIF文件,文件巨细都会比原视频更大。

ray@MyDeepin:~/Videos/MyVideos/Screen Recordings$ ls -lh
-rw-r--r-- 1 ray ray 433M 10月 22 12:50 convert.gif
-rw-r--r-- 1 ray ray 150M 10月 22 12:42 ffmpeg.gif
-rw-r--r-- 1 ray ray 200M 10月 22 12:45 gifski.gif
-rw-r--r-- 1 ray ray  27M 10月 22 12:38 test.mp4

GIF紧缩

  那么要怎样才干削减GIF文件的巨细呢?一般从3个方面下手。

  • 图画分辨率巨细

  经过缩小图画的分辨率,能够在很大程度上削减终究GIF文件的巨细,这也是最有用的办法。

  • 图画帧率

  下降帧率是另一个削减GIF文件巨细的办法,不过太低的帧率会让GIF的作用大打折扣。

  • 下降颜色通道与添加透明值

  简略来说便是将颜色鲜艳程度下降、并恰当添加透明值,这样图片中颜色数据巨细就会下降,可是会明显影响GIF的显现作用。

  假如前面2步都已无法再调整了,那么可经过convert的转化指令完成。

convert result.gif -fuzz 10% -layers Optimize result.min.gif

脚本

  终究分享一个基于上述三方组件的Shell脚本。该脚本可自动将目录下的视频文件转化为GIF文件(同时保留未紧缩与紧缩的文件)

#!/bin/bash
helpinfo() {
    echo "Version: GIF Creator Tools 1.0.0"
    echo "Usage: $0 [options ...] Video File Directory"
    echo ""
    echo "Video File Settings:"
    echo "-w       video size scaling width"
    echo "-r       set frame rate (Hz value, fraction or abbreviation)"
    echo "GIF File Settings:"
    echo "-f       colors within this distance are considered equal"
    exit -1
}
createDirectories(){
    if [ ! -d "$DSTPATH" ];then
        mkdir -p "$DSTPATH"
    fi
    if [ ! -d "$TMPPATH" ];then
        mkdir -p "$TMPPATH"
    fi
}
convertgif(){
    for FILE in `ls "$SRCPATH"/*.mp4 | tr " " "\?"`
    do
        FILENAME=`echo "$FILE"|awk -F "/" '{print $NF}'|awk -F "." '{print $1}'`
        ffmpeg -i "$SRCPATH/$FILENAME.mp4" -r $RATE -vf scale=$WIDTH:-1 "$TMPPATH"/TMP_%04d.png
        gifski -W $WIDTH -r 10 -o "$DSTPATH/$FILENAME.gifski.gif" "$TMPPATH"/TMP_*.png
        convert -delay 10 -loop 0 "$TMPPATH"/TMP_*.png "$DSTPATH/$FILENAME.convert.gif"
        rm -rf "$TMPPATH"/TMP_*.png
        convert "$DSTPATH/$FILENAME.gifski.gif" -fuzz $FUZZ% -layers Optimize "$DSTPATH/$FILENAME.gifski.min.gif"
        convert "$DSTPATH/$FILENAME.convert.gif" -fuzz $FUZZ% -layers Optimize "$DSTPATH/$FILENAME.convert.min.gif"
    done
    rm -rf "$TMPPATH"
}
setdefault(){
    if ["$SRCPATH" = ""]; then
        SRCPATH=`pwd`
    fi
    if ["$WIDTH" = ""]; then
        WIDTH=800
    fi
    if ["$RATE" = ""]; then
        RATE=5
    fi
    if ["$FUZZ" = ""]; then
        FUZZ=10
    fi
}
while getopts ':w:r:f:h' OPT; do
    case $OPT in
        w) WIDTH="$OPTARG";;
        r) RATE="$OPTARG";;
        f) FUZZ="$OPTARG";;
        h) helpinfo;;
    esac
done
shift $(($OPTIND - 1))
SRCPATH=$*
setdefault
DSTPATH="$SRCPATH/gif"
TMPPATH="$SRCPATH/tmp"
createDirectories
convertgif