安装certbot

[root@ecs ~]# yum install -y certbot

证书操作

http-01验证

  1. 签发证书

    [root@ecs ~]# certbot certonly -d wiseidc.com -d www.wiseidc.com --webroot -w /data/wwwroot/wiseidc

    注:使用http-01验证方式,必须保证http://www.wiseidc.comhttp://wiseidc.com能够正常访问。

  2. 续签证书

    [root@ecs ~]# certbot renew --deploy-hook "systemctl restart nginx"
    [root@ecs ~]# certbot renew --renew-hook "/usr/local/nginx/sbin/nginx -s reload"
  3. 删除证书

    [root@ecs ~]# certbot delete --cert-name wiseidc.com

dns-01验证

  1. 安装aliyun-cli

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
    [root@ecs src]# tar xzvf aliyun-cli-linux-latest-amd64.tgz
    [root@ecs src]# mv aliyun /usr/local/bin
    [root@ecs src]# aliyun version
    3.4.11
  2. 配置凭证

    [root@ecs ~]# aliyun configure set --profile default --mode AK \
    --access-key-id ****** \
    --access-key-secret ****** \
    --region cn-shanghai

    --profile default:配置profile名称为default,cat ~/.aliyun/config.json可以看到有多个profiles,通过描述名区分不同的profile。

    验证ak凭证是否生效,查看当前region区域内的ecs列表:

    [root@ecs ~]# aliyun ecs DescribeInstances --profile default
  3. 安装certbot-dns-aliyun

    [root@ecs ~]# cd /usr/local/src
    [root@ecs ~]# wget http://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh
    [root@ecs ~]# mv alidns.sh /usr/local/bin
    [root@ecs ~]# chmod +x /usr/local/bin/alidns.sh
    [root@ecs ~]# ln -s /usr/local/bin/alidns.sh /usr/local/bin/alidns
  4. 签发证书

    [root@ecs ~]# certbot certonly -d wiseidc.com -d *.wiseidc.com \
    --manual --preferred-challenges dns \
    --manual-auth-hook "alidns" \
    --manual-cleanup-hook "alidns clean" \
    --dry-run
    • -d wiseidc.com:指定域名,可以指定多个域名。
    • manual:手动模式。
    • preferred-challenges dns:使用DNS-01方式验证。
    • manual-auth-hook "alidns":在DNS验证时调用alidns脚本。
    • manual-cleanup-hook "alidns clean":在DNS验证完成后调用alidns clean脚本。
    • --dry-run:模拟签发过程,不会实际签发证书,正式签发不需要此参数。
  5. 续期证书

    [root@ecs ~]# certbot renew --quiet --preferred-challenges dns \
    --manual-auth-hook "alidns" \
    --manual-cleanup-hook "alidns clean" \
    --deploy-hook "systemctl restart nginx"

CentOS 7.9安装LibreOffice

安装JRE

[root@ecs ~]# cd /usr/local/src
[root@ecs src]# tar -zxvf server-jre-8u301-linux-x64.tar.gz
[root@ecs src]# mv /usr/local/src/jdk1.8.0_301 /usr/local/jdk
[root@ecs src]# cat >> /etc/profile << EOF
export JAVA_HOME=/usr/local/jdk
export JRE_HOME=\$JAVA_HOME/jre
export CLASSPATH=.:\$JAVA_HOME/lib:\$JRE_HOME/lib
export PATH=\$JAVA_HOME/bin:\$PATH
EOF
[root@ecs src]# source /etc/profile

安装LibreOffice

  1. 安装主程序

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf LibreOffice_7.5.7.1_Linux_x86-64_rpm.tar.gz
    [root@ecs src]# cd LibreOffice_7.5.7.1_Linux_x86-64_rpm/RPMS && yum install -y *.rpm
  2. 安装中文语言包

    如需处理中文字体,必须安装中文语言包,否则无法正确识别中文字体名称。

    [root@ecs ~]# cd /usr/local/src
    [root@ecs ~]# tar -zxvf LibreOffice_7.5.7.1_Linux_x86-64_rpm_langpack_zh-CN.tar.gz
    [root@ecs ~]# cd LibreOffice_7.5.7.1_Linux_x86-64_rpm_langpack_zh-CN && yum install -y *.rpm
  3. 安装依赖

    [root@ecs ~]# yum install -y libXinerama cairo cups-libs

    不安装依赖会出现以下报错:

    • /opt/libreoffice7.5/program/oosplash: error while loading shared libraries: libXinerama.so.1: cannot open shared object file: No such file or directory
    • /opt/libreoffice7.5/program/soffice.bin: error while loading shared libraries: libcairo.so.2: cannot open shared object file: No such file or directory
    • /opt/libreoffice7.5/program/soffice.bin: error while loading shared libraries: libcups.so.2: cannot open shared object file: No such file or directory
  4. 安装中文字体

    必须安装中文字体,否则LibreOffice在处理文档时,中文字体会变成方框。

    [root@ecs ~]# cp /usr/local/src/fonts/*.ttf /usr/share/fonts
  5. 切换中文系统语言

    在非中文系统语言下,LibreOffice将无法识别中文字体名称,从而认为字体缺失,LibreOffice会使用第一个中文字体(按照拼音首字母排序)替换,如果找不到中文字体,则显示为方框。

    [root@ecs ~]# sed -i "/^LANG=\"en_US.UTF-8\"/cLANG=\"zh_CN.UTF-8\"" /etc/locale.conf
    [root@ecs ~]# reboot

    在安装CentOS 7.9时默认已经包含了大量语言包,因此可以直接修改/etc/locale.conf即可切换中文语言。但如果使用极简安装(如Docker CentOS),默认可能没有安装中文语言包,即使修改了/etc/locale.conf也无法显示中文,因为缺少语言包文件。

    查看系统已安装语言包:

    [root@ecs ~]# locale -a | grep zh_CN

    安装中文语言包

    [root@ecs ~]# localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8

    临时中文显示

    [root@ecs ~]# LC_ALL=zh_CN.UTF-8 date
    2026年 08月 06日 星期四 13:05:12 CS

    切换语言

    [root@ecs ~]# sed -i "/^LANG=/cLANG=\"zh_CN.UTF-8\"" /etc/locale.conf

    或者:

    [root@ecs ~]# localectl set-locale LANG=zh_CN.UTF-8

应用

  • 格式转换

    [root@ecs ~]# /opt/libreoffice7.5/program/soffice \
    --headless --invisible --convert-to pdf:writer_pdf_Export \
    --outdir /usr/local/src/ /usr/local/src/demo.docx 2>&1
  • 设置水印

    [root@ecs ~]# /opt/libreoffice7.5/program/soffice \
    --headless --invisible \
    --convert-to pdf:writer_pdf_Export:'{"Watermark":{"type":"string","value":"draft"}, "WatermarkColor":{"type":"long","value":"8355711"}, "WatermarkFontName":{"type":"string","value":"Times"}, "WatermarkFontHeight":{"type":"long","value":"100"}, "WatermarkRotateAngle":{"type":"long","value":"450"}}' \
    --outdir /usr/local/src/ /usr/local/src/demo.docx 2>&1
  • 服务器模式

    [root@ecs ~]# /opt/libreoffice7.5/program/soffice --headless \
    --accept="socket,host=127.0.0.1,port=3000;urp;" --nofirststartwizard &

    查看进程

    [root@ecs ~]# yum install -y net-tools
    [root@ecs ~]# netstat -anp | grep :3000
    tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      17416/soffice.bin
    [root@ecs ~]# ps -ef | grep libreoffice
    root     17394  1186  0 14:13 pts/0    00:00:00 /opt/libreoffice7.5/program/oosplash --headless --accept=socket,host=127.0.0.1,port=3000;urp; --nofirststartwizard
    root     17416 17394  0 14:13 pts/0    00:00:00 /opt/libreoffice7.5/program/soffice.bin --headless --accept=socket,host=127.0.0.1,port=3000;urp; --nofirststartwizard

unoconv

  • 安装

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf unoconv-0.8.2.tar.gz
    [root@ecs src]# cd unoconv-0.8.2 && make install
  • socket连接

    LibreOffice以服务器模式运行后,unoconv可以直接通过UNO协议进行通信。

    [root@ecs ~]# unoconv --connection 'socket,host=127.0.0.1,port=3000,tcpNoDelay=1;urp;StarOffice.ComponentContext' -f pdf demo.docx

    或者:

    [root@ecs ~]# unoconv -f pdf -p 3000 demo.docx
  • 监听模式

    unoconv包含直接模式(Direct Mode)监听模式(Listener Mode)

    可以以服务器模式启动LibreOffice,然后unoconv通过--connection-p直接连接。也可以使用unoconv --listener创建Listener(默认端口号2002)。

    [root@ecs ~]# unoconv --listener --server=0.0.0.0 --port=2002 &

    unoconv在执行文档转换时,默认尝试连接2002端口的Listener,如果unoconv --listener监听在其它端口,连接就会失败。连接失败后会自动启动一个2002端口的Listener。

    新的Listener会尝试启动soffice.bin,但由于unoconv --listener已经启动了soffice.bin进程,因此新的Listener将2002端口路由到soffice.bin后就终止Listener进程,转换动作没完成,终端会报错:Error: Unable to connect or start own listener. Aborting.

    解决方法(二选一):

    • 使用-p指定连接端口

      直接指定连接端口,避免新建listener。

      [root@ecs ~]# unoconv -f pdf -p 2002 demo.docx
    • 重新执行

      再次执行时,由于2002端口已经路由到soffice.bin,因此可以正常执行。

      [root@ecs ~]# unoconv -f pdf demo.docx

      查看执行过程:

      [root@ecs ~]# unoconv -vvv -f pdf demo.docx

    查看端口监听状态

    [root@ecs ~]# netstat -tlnp | grep 2002
    tcp        0      0 127.0.0.1:2002          0.0.0.0:*               LISTEN      1342/soffice.bin
    [root@ecs ~]# lsof -i:2002 -P -n
    soffice.b 1342 root   14u  IPv4 137618      0t0  TCP 127.0.0.1:2002 (LISTEN)
    [root@ecs ~]# ss -tlnp | grep -E "2002|3000"
    LISTEN     0      128    127.0.0.1:2002                     *:*                   users:(("soffice.bin",pid=1342,fd=14))
    LISTEN     0      128          *:3000                     *:*                   users:(("soffice.bin",pid=1342,fd=11))

    新的Listener在尝试启动soffice.bin时,如果没有发现已存在的soffice.bin进程,则会进入直接模式,执行完转换任务后,会自动终止Listener进程。直接模式每次都会创建soffice.bin进程,转换完成后再终止soffice.bin进程。

    因此在没有执行unoconv --listener的情况下,每次执行unoconv -f pdf demo.docx都需要等待一会儿,因为每次都需要先启动soffice.bin(比较消耗时间),转换完成后再终止soffice.bin。

Docker部署

自建镜像

  1. 创建Dockerfile

    FROM maisi/centos:7.9.2009
    
    WORKDIR /opt/libreoffice7.5/program
    
    ENV LANG=zh_CN.UTF-8 \
        LC_ALL=zh_CN.UTF-8
    
    ADD http://mirrors.aliyun.com/repo/Centos-7.repo /etc/yum.repos.d/CentOS-Base.repo
    RUN yum clean all && yum makecache
    
    RUN yum install libXinerama cairo cups-libs -y \
        yum clean all && \
        rm -rf /tmp/* rm -rf /var/cache/yum/* && \
        localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8 && \
        sed -i "/^LANG=/cLANG=\"zh_CN.UTF-8\"" /etc/locale.conf && \
        ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    
    ADD LibreOffice_7.5.7.1_Linux_x86-64_rpm.tar.gz /usr/local/src/
    ADD LibreOffice_7.5.7.1_Linux_x86-64_rpm_langpack_zh-CN.tar.gz /usr/local/src/
    
    RUN cd /usr/local/src/LibreOffice_7.5.7.1_Linux_x86-64_rpm/RPMS/ && \
        yum localinstall *.rpm -y && \
        cd /usr/local/src/LibreOffice_7.5.7.1_Linux_x86-64_rpm_langpack_zh-CN/RPMS/ && \
        yum localinstall *.rpm -y
    
    ENV PATH=/opt/libreoffice7.5/program/:/opt/libreoffice7.5/program/python-core-3.8.18/bin:${PATH}
    
    ARG JDK_PATH=/usr/local/jdk
    ADD server-jre-8u351-linux-x64.tar.gz /usr/local/src/
    RUN mv /usr/local/src/jdk1.8.0_351 ${JDK_PATH}
    ENV JAVA_HOME=${JDK_PATH} \
        JRE_HOME=${JDK_PATH}/jre \
        CLASSPATH=.:${JDK_PATH}/lib:${JDK_PATH}/jre\lib \
        PATH=${JDK_PATH}/bin:${PATH}
    
    ADD setuptools-68.2.2.tar.gz /usr/local/src/
    ADD pip-23.3.1.tar.gz /usr/local/src/
    RUN cd /usr/local/src/setuptools-68.2.2 && \
        python setup.py install && \
        cd /usr/local/src/pip-23.3.1 && \
        python setup.py install && \
        rm -rf /usr/local/src/*.* && yum clean all
    
    RUN python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn unoserver flask gunicorn && \
        ln -s /opt/libreoffice7.5/program/soffice libreoffice && \
        sed -i s#/program/python.bin#/program/python#g /opt/libreoffice7.5/program/python-core-3.8.18/bin/unoserver && \
        sed -i s#/program/python.bin#/program/python#g /opt/libreoffice7.5/program/python-core-3.8.18/bin/unoconvert && \
        sed -i s#/program/python.bin#/program/python#g /opt/libreoffice7.5/program/python-core-3.8.18/bin/gunicorn
    
    COPY ./app /app
    
    EXPOSE 3000
    
    # CMD ["soffice", "--headless", "--accept=socket,host=0.0.0.0,port=3000;urp;", "--nofirststartwizard"]
    
    ENTRYPOINT unoserver --daemon & gunicorn -w 2 -b :3000 --chdir /app app:app
  2. 构建镜像

    [root@ecs ~]# docker build -t libreoffice:7.5.7.1-centos7.9.2009 --progress=plain --no-cache .
  3. 创建容器

    [root@ecs ~]# docker run --name=libreoffice \
    --restart unless-stopped \
    --privileged=true \
    -e TZ=Asia/Shanghai \
    -p 3000:3000 \
    -v /data/libreoffice:/data \
    -d libreoffice:7.5.7.1-centos7.9.2009
  4. 中文支持

    [root@ecs ~]# docker cp /data/libreoffice/fonts/STKaiti.ttf libreoffice:/opt/libreoffice7.5/share/fonts/truetype
    [root@ecs ~]# docker cp /data/libreoffice/fonts/方正仿宋_gbk.ttf libreoffice:/opt/libreoffice7.5/share/fonts/truetype
    [root@ecs ~]# docker restart libreoffice
  5. 上传镜像

    [root@ecs ~]# docker tag libreoffice:7.5.7.1-centos7.9.2009 registry.cn-shanghai.aliyuncs.com/maisi/libreoffice:7.5.7.1-centos7.9.2009
    [root@ecs ~]# docker push registry.cn-shanghai.aliyuncs.com/maisi/libreoffice:7.5.7.1-centos7.9.2009
  6. 格式转换

    • 容器内调用

      [root@ecs ~]# docker exec -it libreoffice /bin/bash
      [root@cc3b8a72e553 program]# ./soffice --headless --invisible --convert-to pdf --outdir /data /data/demo.docx
      [root@cc3b8a72e553 program]# unoconvert /data/demo.docx --convert-to pdf /data/demo.pdf
    • 宿主机调用

      [root@ecs ~]# docker exec libreoffice ./soffice --headless --invisible --convert-to pdf --outdir /data /data/demo.docx
    • 容器间调用

      [root@ecs ~]# docker run -it --rm --privileged --name node \
      -v /var/run/docker.sock:/var/run/docker.sock maisi/node:22-alpine sh
      / # apk add --no-cache docker-cli
      / # docker exec libreoffice ./soffice --version
    • api转换容器内文件

      [root@ecs ~]# curl -X POST http://127.0.0.1:3000/convert-to/pdf \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d "file=/data/demo.docx"

      返回:/data/l29126e7v3nn037y6bi7vnbhkwramafq.pdf

      将容器内的文件/data/demo.docx转换后保存到容器/data/l29126e7v3nn037y6bi7vnbhkwramafq.pdf

    • api转换宿主机文件

      [root@ecs ~]# curl -X POST http://127.0.0.1:3000/convert-to/pdf \
      -F 'file=@/data/libreoffice/demo.docx' > /data/libreoffice/demo.pdf

      将宿主机的文件/data/libreoffice/demo.docx上传到api服务器,再将转换后的文件下载到宿主机/data/libreoffice/demo.pdf

使用LibreOffice/online

  1. 创建容器

    [root@ecs ~]# docker run --name=libreoffice \
    --restart unless-stopped \
    --privileged=true \
    -e TZ=Asia/Shanghai \
    -e username=admin -e password=123456 \
    -e extra_params=--o:ssl.enable=false \
    -p 9980:9980 \
    -v /data/libreoffice:/data:Z \
    -d libreoffice/online
    • 控制台不允许有特殊字符,如果密码设置为admin@123,实际密码会变成admin。
    • libreoffice/online默认开启ssl,强制https方式访问,如果需要通过http方式访问,必须关闭ssl。设置环境变量-e extra_params=--o:ssl.enable=false即可关闭ssl。
    • :Z:z仅在操作系统启用了SELinux时才有效。:z映射的卷可以被多个容器共享,而:Z仅限当前容器私有使用。

    浏览器访问:http://192.168.3.103:9980,返回OK表示部署已成功。

    管理中心:http://192.168.3.103:9980/loleaflet/dist/admin/admin.html

  2. 查看启动日志

    [root@ecs ~]# docker logs --tail 50 --follow --timestamps libreoffice
  3. 关闭ssl访问

    除了通过设置环境变量-e extra_params=--o:ssl.enable=false来关闭ssl之外,还可以通过修改配置文件来关闭ssl。

    [root@ecs ~]# docker exec -it libreoffice sed -i "/SSL support to enable./s/>true/>false/" /etc/loolwsd/loolwsd.xml
    [root@ecs ~]# docker restart libreoffice
  4. 允许使用本地文件系统

    [root@ecs ~]# docker exec -it libreoffice sed -i "/filesystem/s/false/true/" /etc/loolwsd/loolwsd.xml
    [root@ecs ~]# docker restart libreoffice

    打开本地文件:http://127.0.0.1:9980/loleaflet/dist/loleaflet.html?file_path=file:///data/hello.docx

    /data/hello.docx是容器内的文件路径,-v /data/libreoffice:/data:Z将宿主机的/data/libreoffice挂载到容器内的/data目录,因此/data/hello.docx实际是宿主机的/data/libreoffice/hello.docx

  5. 添加中文字体

    [root@ecs ~]# docker cp /data/libreoffice/fonts/STKaiti.ttf libreoffice:/opt/libreoffice/share/fonts/truetype
    [root@ecs ~]# docker cp /data/libreoffice/fonts/方正仿宋_gbk.ttf libreoffice:/opt/libreoffice/share/fonts/truetype
    [root@ecs ~]# docker restart libreoffice
  6. 转换文件

    [root@ecs ~]# curl -F "data=@/data/libreoffice/demo.docx" http://127.0.0.1:9980/lool/convert-to/pdf > demo.pdf

基础概念

容器格式(Container Format)

容器格式又称封装格式,用于封装视频、音频、字幕、元数据(标题、章节信息等)等各种流媒体内容,容器决定了文件的扩展名。

常见的容器格式:

容器格式说明
mp4支持多种编解码器,广泛用于互联网和移动设备
mkv支持多轨音频、字幕,灵活性强,常用于高清电影和视频
avi支持功能有限,但兼容性强
mov苹果格式,主要用于QuickTime
flvFlash流媒体,现在使用较少
webm由Google提出,专为web视频流设计,轻量且开放
ogg免费、无专利限制、高质量的音频压缩格式

编码格式(Codec)

编码格式也称编解码器(Codec,Compressor/Decompressor),是对音视频数据进行压缩和解压缩的技术。编码器将原始多媒体数据压缩为更小的文件,以便于存储和传输,而解码器则负责将压缩的数据还原为可播放的音频或视频。

常见的视频编码格式:

编码格式说明
H.264 (AVC)最常用的压缩标准,广泛用于网络流媒体、蓝光等
H.265 (HEVC)H.264的升级版,压缩效率更高,适用于4K、8K视频
MPEG-4早期的压缩标准,主要用于流媒体和在线视频
VP9Google开发的开源编解码器,常用于YouTube视频
AV1更先进的开源编解码器,旨在取代H.265和VP9

容器格式和编码格式密切相关,但职责不同。容器负责封装和管理音视频、字幕等数据,编码格式负责压缩和解压实际的音视频数据。

同一容器可以支持多种编码格式。例如mp4容器可以使用H.264、H.265等不同的编解码器,mkv容器支持H.264、VP9等多种音视频编码。

安装编译环境

nasm/yasm

nasm/yasm都是汇编编译器,yasm是从nasm的基础上开发出来的,属于同宗,使用了相同的语法,所以nasm的代码可以用yasm编译。yasm对nasm一些不合理的地方进行了改良。但yasm更新较慢,而nasm更新较快,能支持更新的指令集,而且还支持Gas语法和AMD64(EM64T)架构,跨平台,支持多种目标文件格式。在Window平台上,fasm支持最好。

必须安装nasm/yasm,否则会报错:nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.。

nasm下载地址:https://www.nasm.us/pub/nasm/releasebuilds/

[root@ecs ~]# yum install -y gcc
[root@ecs ~]# tar -xvf nasm-2.15.05.tar.gz && cd nasm-2.15.05
[root@ecs nasm-2.15.05]# ./configure && make && make install

nasm和yasm二者安装其一即可,但由于x265 2.6版之后,只能使用nasm 2.13或更高版本编译,因此如果要安装x265 2.6之后的版本就只能选择nasm。

安装媒体开发库

SDL

SDL是一套开源的跨平台多媒体开发库,专注于提供图形、音频和输入设备的访问。SDL主要用于:

  • 图形显示:提供对窗口、渲染器和纹理的控制,用于显示图像或视频;
  • 音频输出:处理和播放音频数据;
  • 输入处理:管理键盘、鼠标等输入设备。

SDL通常和ffmpeg搭配使用,可以实现功能上的互补。ffmpeg主要负责音视频解码,再由SDL负责将视频原始帧数据显示到屏幕,将解码后的音频数据输出到扬声器。在需要实时处理和播放的音视频应用中,ffmpeg解码后的数据通过SDL进行渲染和播放。

编译ffmpeg的时候加上参数--enable-ffplay即可生成ffplay

[root@ecs ~]# cd /usr/local/src
[root@ecs src]# tar -zxvf SDL2-2.0.20.tar.gz && cd SDL2-2.0.20
[root@ecs SDL2-2.0.20]# ./configure && make -j 16 && make install

注:SDL只有在生成ffplay时才是必须的,如果不需要编译ffplay则忽略SDL。

安装依赖库

  • libmp3lame

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar xzvf lame-3.100.tar.gz && cd lame-3.100
    [root@ecs src]# ./configure --enable-nasm && make && make install

    ffmpeg不支持mp3编码,因此需要依赖libmp3lame实现编码功能,但ffmpeg支持mp3解码,因此无需安装libMAD。

  • xvid

    xvid是一个开放源代码的MPEG-4(Moving Picture Experts Group-4 Part 2)视频编解码器。与x264相比,相同质量下,x264压缩的视频体积更小。

    下载地址:https://downloads.xvid.org/downloads/xvidcore-1.3.7.tar.gz

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf xvidcore-1.3.7.tar.gz && cd xvidcore/build/generic
    [root@ecs src]# ./configure && make && make install
  • libx264

    H.264(AVC),全称MPEG-4 Part 10或Advanced Video Coding(AVC),是由ITU-T的视频编码专家组(VCEG)和ISO/IEC的动态图像专家组(MPEG)联合制定的视频编码标准。ITU-T称为H.264,ISO/IEC则归纳与MPEG系列,称为MPEG-4 Part 10,另一个代称是MPEG-4 AVC。

    x264是一个开源的H.264/MPEG-4 AVC视频编码库,是最好的有损视频编码器之一。

    下载地址:https://www.videolan.org/developers/x264.html

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf x264-master.tar.gz && cd x264-master
    [root@ecs src]#./configure --enable-shared --enable-static --disable-asm
    [root@ecs src]#make && make install
  • libx265

    H.265又称High Efficiency Video Coding(HEVC),是H.264的升级版。

    x265是一个开源的H.265视频编码库。

    下载地址:https://www.videolan.org/developers/x265.html

    x265需要CMake 2.8.8或更高版本,yum的cmake版本为2.8.12,因此直接yum安装即可。

    [root@ecs ~]# yum install -y gcc-c++ cmake numactl-devel
    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf x265_4.0.tar.gz
    [root@ecs src]# cd x265_4.0/build/linux
    [root@ecs linux]# sed -i 's/string(SUBSTRING "\${X265_REVISION_ID}" 0 12 X265_REVISION_ID)/set(X265_LATEST_TAG "4.0")\n  set(X265_TAG_DISTANCE "23")\n  set(X265_REVISION_ID "487105d")\n  string(SUBSTRING "\${X265_REVISION_ID}" 0 7 X265_REVISION_ID)/g' /usr/local/src/x265_4.0/source/cmake/Version.cmake
    [root@ecs linux]# cmake -G "Unix Makefiles" ../../source
    [root@ecs linux]# make -j$(nproc) && make install

    常见报错:

    • 报错:CMake Error: your CXX compiler: "CMAKE_CXX_COMPILER-NOTFOUND" was not found.,解决方法:安装gcc-c++
    • 报错:Could NOT find nasm,解决方法:安装nasm
    • 报错:Could NOT find NUMA (missing: NUMA_ROOT_DIR NUMA_INCLUDE_DIR NUMA_LIBRARY),解决方法:安装numactl-devel

    注:ffmpeg自身支持H.264和H.265的解码,因此无需安装其它解码器。

  • libvpx

    VP8是google定义并开源的视频编解码标准和编解码库实现。

    MPEG系列格式商用需要缴纳授权费用,因此Google和On2 Technologies制定了VP8,并在收购On2 Technologies之后将VP8开源(BSD授权),使其成为可免费授权使用的高品质视频编码格式。

    VP8号称比H.264编码性能更好,实际上没那么夸张,差不多相当于ffmpeg内置默认的openh264编解码库。VP8的压缩实现与H.264有点区别就是VP8没有B帧,而H.264有B帧。

    VP8的优点是开源,没有H.264/H.265的专利版权风险,除了IE9以下版本的浏览器外,现代浏览器都支持VP8视频编码,即webm视频格式。

    VP9也是google开源的,用于比拼H.265(HEVC)的编解码器。兼容性方面,除了IE9以下版本的浏览器外,现代浏览器都支持VP9视频编码。

    libvpx是WebM项目的子库,可以同时支持VP8和VP9视频编码。

    下载地址:https://github.com/webmproject/libvpx/archive/v1.11.0/libvpx-1.11.0.tar.gz

    [root@ecs ~]# yum install -y perl
    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zvxf libvpx-1.11.0.tar.gz && cd libvpx-1.11.0
    [root@ecs src]# ./configure --enable-shared && make && make install
  • aac

    AAC全称Advanced Audio Coding,高级音频编码。是目前最常用的一种音频编码格式,与MP3相比,AAC是一种编码效果更好,编码音质更高的音频编码格式,常见的使用AAC编码后的文件存储格式为m4a。

    ffmpeg可以调用的AAC编码器主要有:

    • aac:ffmpeg自带的aac编码器;
    • libfaac:第三方aac编码器,faac是aac音频编码库,可将pcm音频编码为aac格式。faad是aac音频解码库,可将aac格式数据解码为pcm数据;
    • libfdk_aac:第三方aac编解码器。

    libfaac和libfdk_aac为非GPL协议,所以在预编译时需采用nonfree支持。

    性能对比:libfdk_aac > aac > libfaac,新版ffmpeg已经弃用了--enable-libfaac,因此只能选择libfdk_aac。

    fdk-aac下载地址:https://downloads.sourceforge.net/opencore-amr/fdk-aac-2.0.1.tar.gz

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar xzvf fdk-aac-2.0.1.tar.gz && cd fdk-aac-2.0.1
    [root@ecs src]# ./configure && make && make install
  • ogg

    Ogg是一种流式容器格式,提供对流式数据进行分割、存储、排序、按时间顺序查找以及检查数据丢失的框架。Ogg格式主要采用Vorbis/Opus编码格式。

    Vorbis是Xiph.Org基金会为了对抗MP3收费音频格式而推出的一种有损压缩音频编码格式,支持多通道。它完全免费、开放且没有专利限制。

    libvorbis是Vorbis的编解码库,下载地址:https://www.xiph.org/downloads/

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -xzvf libogg-1.3.5.tar.gz && cd libogg-1.3.5
    [root@ecs libogg-1.3.5]# ./configure && make && make install
    [root@ecs libogg-1.3.5]# echo /usr/local/lib >> /etc/ld.so.conf; ldconfig
    [root@ecs libogg-1.3.5]# cd /usr/local/src
    [root@ecs src]# tar -zxvf libvorbis-1.3.7.tar.gz && cd libvorbis-1.3.7
    [root@ecs libvorbis-1.3.7]# ./configure && make && make install
    [root@ecs libvorbis-1.3.7]# echo export PKG_CONFIG_PATH="\$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig" >> /etc/profile
    [root@ecs libvorbis-1.3.7]# source /etc/profile

    libvorbis依赖于libogg,安装完libogg后,需要配置ld.so.conf,否则会报错:configure: error: must have Ogg installed!。

    安装好libvorbis后,还需要配置PKG_CONFIG_PATH,否则编译ffmpeg时会报错:ERROR: vorbis not found using pkg-config。

    或者直接安装libvorbis-devel(自动安装libogg-devel)。

    Vorbis在中高码率时优势明显,低码率时效果不佳。Xiph.Org随后开发了Speex有损压缩音频格式,专攻低码率语音,适用于视频通话、游戏聊天、有声读物等。

    后来Xiph研发CELT技术(继承自Vorbis的MDCT)以改进Speex,互联网工程任务组(IETF)将CELT和Skype公司的SILK(LP线性预测)这两个技术集成为Opus。Opus是一个完全开源、免费、通用性高的音频编解码器,由Xiph和Skype合作开发,8kHz以下(语音)用LP,8~20kHz用MDCT,强强联手,无缝切换,不仅音质极佳,而且适用范围广。

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf opus-1.3.1.tar.gz && cd opus-1.3.1
    [root@ecs opus-1.3.1]# ./configure --disable-static && make && make install

    或者直接安装opusfile-devel(自动安装libogg-devel和opus-devel)。

  • flac

    FLAC既是一个容器格式,也是一个编码格式。是目前最快、支持最广泛的无损音频格式,也是唯一一个开源无专利的无损音频格式。FLAC原为Josh Coalson发起的项目,后并入Xiph.Org基金会。ffmpeg支持flac的编解码,无需安装编解码库。

安装FFmpeg

[root@ecs ~]# cd /usr/local/src
[root@ecs src]# yum install -y bzip2
[root@ecs src]# tar -jvxf ffmpeg-7.0.2.tar.bz2 && cd ffmpeg-7.0.2
[root@ecs ffmpeg-7.0.2]# ./configure --prefix=/usr/local/ffmpeg \
--enable-ffplay --enable-libmp3lame \
--enable-libfdk-aac --enable-nonfree \
--disable-static --enable-shared \
--enable-libx264 --enable-libx265 --enable-gpl --enable-version3 \
--enable-libvpx --enable-libxvid
[root@ecs ffmpeg-7.0.2]# make -j$(nproc) && make install
[root@ecs ffmpeg-7.0.2]# cat >> /etc/profile << EOF
export PATH=\$PATH:/usr/local/ffmpeg/bin
LD_LIBRARY_PATH=/usr/local/ffmpeg/lib:/usr/local/lib:\$LD_LIBRARY_PATH
EOF
[root@ecs ffmpeg-7.0.2]# source /etc/profile

编译参数说明:

参数说明
--prefix安装目录
--enable-debug打开debug模式
--disable-static --enable-shared编译成动态库,默认编译成静态库
--disable-static:禁止编译静态链接库(.a或.lib)
--enable-shared:编译动态链接库(.so、.dll或.dylib)
--enable-ffplay生成ffplay(默认编译不带ffplay),必须先安装SDL,否则即使--enable-ffplay也无法生成ffplay
--enable-libx264 --enable-gpllibx264采用GPL协议,所以用到libx264的ffmpeg必须gpl
--enable-version3启用‌LGPLv3(GNU Lesser General Public License version 3)许可,必须先--enable-gpl
--enable-filter=delogo启用去水印滤镜
--enable-libfdk-aac --enable-nonfree使用libfdk-aac库进行aac编解码
fdk-aac使用非自由许可证,与GPL不兼容,必须添加--enable-nonfree,生成的FFmpeg(库或二进制文件)不可公开分发

必须将/usr/local/ffmpeg/lib目录加入环境变量LD_LIBRARY_PATH中,否则在使用ffmpeg的过程中就会出现类似cannot open shared object file: No such file or directory这样的报错。

如果需要避免运行时依赖,须要同时设置:--enable-static --disable-shared

注:只设置--enable-static而不设置--disable-shared,ffmpeg会同时生成.a.so,默认情况下gcc链接时优先使用.so,导致ffmpeg仍是动态链接的。

常见报错

  • ffmpeg: error while loading shared libraries: libavdevice.so.61: cannot open shared object file: No such file or directory。

    此类报错一般会出现在--enable-shared方式编译的情况下。

    查看ffmpeg依赖

    [root@ecs ~]# ldd /usr/local/ffmpeg/bin/ffmpeg
        linux-vdso.so.1 =>  (0x00007ffcd1fbb000)
        libavdevice.so.61 => not found
        libavfilter.so.10 => not found
        libavformat.so.61 => not found
        libavcodec.so.61 => not found
        libpostproc.so.58 => not found
        libswresample.so.5 => not found
        libswscale.so.8 => not found
        libavutil.so.59 => not found
        libm.so.6 => /lib64/libm.so.6 (0x00007fb088914000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fb0886f8000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fb08832a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fb088c16000)

    发现很多都是not found,查找libavdevice.so.59共享库:

    [root@ecs ~]# find / -name libavdevice.so
    /usr/local/ffmpeg/lib/libavdevice.so

    /usr/local/ffmpeg/lib/存在libavdevice.so,但为什么还提示not found呢?

    ffmpeg在调用动态链接库时,会到系统默认的动态链接库路径下查找,查看系统默认的动态链接库路径:

    [root@ecs ~]# ld --verbose | grep SEARCH
    SEARCH_DIR("=/usr/x86_64-redhat-linux/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/x86_64-redhat-linux/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");

    返回的路径中并没有/usr/local/ffmpeg/lib/,因此就无法找到libavdevice.so了。解决方法只需将/usr/local/ffmpeg/lib/添加到动态链接库路径即可。

    [root@ecs ~]# echo export LD_LIBRARY_PATH="/usr/local/ffmpeg/lib:/usr/local/lib:\$LD_LIBRARY_PATH" >> /etc/profile
    [root@ecs ~]# source /etc/profile

    或者:

    [root@ecs ~]# echo "/usr/local/ffmpeg/lib" >> /etc/ld.so.conf; ldconfig

安装SoX

安装依赖

  • libmp3lame

    libmp3lame是目前最好的mp3编码器,编码高质量mp3最好也是唯一的选择。

    [root@ecs ~]# yum install -y lame-devel

    lame-devel包含了libmp3lame.so,SoX调用libmp3lame.so实现解码mp3功能。

    windows sox默认不支持编解码mp3,需要依赖libmp3lame-0.dlllibmad-0.dll才能实现编解码功能。将wav等音频格式转为mp3时,使用libmp3lame-0.dll进行编码。将mp3转为wav等格式时,使用libmad-0.dll进行解码。

    linux lame即可以编码,也可以解码mp3、wav和aif格式,等效于windows sox + libmp3lame-0.dll + libmad-0.dll。

    • wav转mp3

      [root@ecs ~]# lame -h input.wav output.mp3
    • mp3转wav

      [root@ecs ~]# lame input.mp3 output.wav
  • libmad

    libMAD是一个开源的高精度MPEG音频解码库,支持MPEG-1。MPEG-1音频分3层,分别是:MPEG-1 Layer1、MPEG-1 Layer2和MPEG-1 Layer3(简称mp3)。

    [root@ecs ~]# yum install -y libmad-devel

    虽然lame工具有解码mp3的功能,但libmp3lame并不具备解码mp3的功能,因此SoX需要依赖libmad实现mp3解码功能。

  • id3tag

    mp3格式标准里没有特别定义保存曲目相关信息的结构,于是在1996年有人提出在mp3文件的末尾添加128字节额外的数据空间用于存储歌曲名、演唱者、专辑名、音轨编号、曲目类型等信息,这些信息成为ID3Tag。

    [root@ecs ~]# yum install -y libid3tag-devel zlib-devel

    注:sox编译id3tag时依赖zlib库。

  • towlame

    TwoLAME is an optimised MPEG Audio Layer 2 (MP2) encoder based on tooLAME by Mike Cheng, which in turn is based upon the ISO dist10 code and portions of LAME.

    [root@ecs ~]# yum install -y twolame-devel

    注:twolame-devel自动安装twolame-libs。lame-devel、libmad-devel和twolame-libs均来自epel源,需要先安装epel源。

  • flac

    flac是一套著名的自由音频无损压缩编码器,不同于其它有损编码(mp3、aac等),flac不会破坏任何原有的音频信息。

    [root@ecs ~]# yum install -y flac-devel
  • vorbis

    有损音频编解码器(需配合ogg容器使用),完全免费、开放,没有专利限制。

    [root@ecs ~]# yum install -y libvorbis-devel
  • opus

    有损音频编解码器,和vorbis都是由xiph.org基金会开发。opus后由IETF(互联网工程任务组)进行标准化,目的用一种格式包含声音和语音,取代speex和vorbis。

    [root@ecs ~]# yum install -y opusfile-devel

    windows可以使用opus-tools实现ogg音频转换,opus-tools等效于sox + libogg-0.dll。

    • wav转ogg

      [root@ecs ~]# opusenc input.wav output.ogg
    • ogg转wav

      [root@ecs ~]# opusdec input.ogg output.wav
    • 查看ogg信息

      [root@ecs ~]# opusinfo input.ogg
  • amr

    全称Adaptive Multi-Rate,自适应多速率编码,主要用于移动设备的音频,压缩比大,但相对其他的压缩格式质量差,多用于人声通话。amr一般是指amr-nb,8kHz采样,有8种比特率的编解码算法,另外有amr-wb,16kHz采样,有9种比特率的编解码算法。由于amr-wb采样率高,所以复杂度大概是amr-nb的两倍。amr-nb和amr-wb都属于speech codec,对audio的编码效果并不好。

    [root@ecs ~]# yum install -y gcc-c++
    [root@ecs ~]# tar -zxvf opencore-amr-0.1.6.tar.gz && cd opencore-amr-0.1.6
    [root@ecs opencore-amr-0.1.6]# ./configure
    [root@ecs opencore-amr-0.1.6]# make && make install

    或者:

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# rpm -ivh opencore-amr-devel-0.1.6-1.el7.x86_64.rpm

    注:opencore-amr(包含amrnb和amrwb)

  • wavpack

    由David Bryant于1998年开发的一款自由、开放的无损音频编解码器。

    [root@ecs ~]# yum install -y wavpack-devel
  • libsndfile

    一款专注于音频文件读写的跨平台C语言库,支持wav、flac等主流格式,适用于音频数据处理、格式转换等场景。sox通常自带对大量音频格式支持,同时也支持通过libsndfile库扩展其格式处理能力,sox不强制依赖libsndfile。

    [root@ecs ~]# yum install -y libsndfile-devel
  • libmagic

    智能处理没有扩展名或扩展名错误的音频,通过读取文件头部的magic number来确认真实格式。

    [root@ecs ~]# yum install -y file-devel

安装驱动

  • ALSA

    [root@ecs ~]# yum install -y alsa-lib-devel

    不安装驱动不影响SoX的音频处理能力,但会导致playrec命令无法调用系统的扬声器和麦克风。

  • PulseAudio

    [root@ecs ~]# yum install -y pulseaudio-libs-devel
  • AO

    [root@ecs ~]# yum install -y libao-devel

    安装libao-devel会自动安装flac-libs、libogg、libsndfile、libvorbis和pulseaudio-libs等。

安装SoX

[root@ecs ~]# yum install -y gcc libtool-ltdl-devel
[root@ecs ~]# cd /usr/local/src && tar -zxvf sox-14.4.2.tar.gz && cd sox-14.4.2
[root@ecs sox-14.4.2]# ./configure --prefix=/usr/local/sox \
--enable-dl-amrnb \
--enable-dl-amrwb \
--enable-dl-lame \
--enable-dl-mad \
--enable-dl-twolame \
--enable-dl-sndfile \
--enable-shared
[root@ecs sox-14.4.2]# make -s && make install
[root@ecs sox-14.4.2]# echo export PATH="\$PATH:/usr/local/sox/bin" >> /etc/profile
[root@ecs sox-14.4.2]# source /etc/profile

--enable-shared改成--enable-static可以生成静态文件,对比生成的sox程序大小:

ll -h /usr/local/sox/bin/sox

注:

  • --enable-dl-*生效,必须先安装libtool-ltdl-devel
  • 如果使用--enable-dl-amrnb,可无需安装opencore-amr
  • --enable-dl使用动态链接,推荐搭配--enable-shared,不使用--enable-dl则可以使用--enable-static

安装脚本

[root@ecs ~]# yum install -y gcc lame-devel libmad-devel libid3tag-devel zlib-devel twolame-devel \
flac-devel \
libvorbis-devel opusfile-devel \
wavpack-devel libsndfile-devel file-devel \
alsa-lib-devel pulseaudio-libs-devel \
libtool-ltdl-devel
[root@ecs ~]# cd /usr/local/src
[root@ecs src]# rpm -ivh opencore-amr-0.1.6-1.el7.x86_64.rpm opencore-amr-devel-0.1.6-1.el7.x86_64.rpm
[root@ecs src]# tar -zxvf sox-14.4.2.tar.gz && cd sox-14.4.2
[root@ecs sox-14.4.2]# ./configure --prefix=/usr/local/sox \
--enable-dl-amrnb \
--enable-dl-amrwb \
--enable-dl-lame \
--enable-dl-mad \
--enable-dl-twolame \
--enable-dl-sndfile \
--enable-shared
[root@ecs sox-14.4.2]# make -s && make install
[root@ecs sox-14.4.2]# echo export PATH="\$PATH:/usr/local/sox/bin" >> /etc/profile
[root@ecs sox-14.4.2]# source /etc/profile
[root@ecs sox-14.4.2]# sox --version
sox:      SoX v14.4.2

操作SoX

sox可以处理self-describing和raw格式音频文件,self-describing音频包含一个用于描述编码属性的文件头(如wav、flac、mp3等),而raw格式不包含这些信息,使用sox时需要通过以下选项指定相关信息:

参数说明
-b, --bits指定采样大小
音频采样时用于存储每个样本的数据位数(bits),目前广泛使用的是16bit采样大小
-c, --channels指定通道数
文件包含的音频通道数量。目前常见的有单声道(mono)和双声道(stereo)
-e, --encoding指定编码器
-r, --rate指定采样率
指声音由模拟信号(平滑的波形)转换成数字信号(锯齿的波形)的过程中,每秒从连续信号中提取的用于组成离散信号的样本个数。CD的采样率通常使用44100Hz,即1秒内采样44100次
-t, --type指定音频文件类型
-C指定比特率大小
一个单位时间内编码音频信号占用的存储空间大小
未压缩格式(wav)比特率不能指定,而是通过采样率 × 采样位深 × 声道数计算而来
对于有损压缩,可以按照指定大小做限制
  • 播放音频

    [root@ecs ~]# sox input.wav -t waveaudio -d
    • -t waveaudio:指定输出文件类型为waveaudio(windows特有设备驱动程序别名,代表声卡输出)
    • -d:代表输出设备为默认(default)设备
    • linux系统去掉-t waveaudio(windows专属)
    • 放大音量

      [root@ecs ~]# sox input.wav -t waveaudio -d vol 2.0
    • 2倍速播放

      [root@ecs ~]# sox input.wav -t waveaudio -d tempo 2
    • 2倍速播放

      [root@ecs ~]# sox input.wav -t waveaudio -d speed 2

      speed 2会重新采样,丢掉一半的采样点,加原本1秒的数据压缩到0.5秒内播放完,速度和音调都会翻倍。

  • 录音

    从默认设备(麦克风)读取音频数据,输出(录制)到record.mp3文件。

    [root@ecs ~]# sox -t waveaudio -d record.mp3
  • 获取音频元数据

    [root@ecs ~]# sox --i input.flac
  • 查看比特率

    [root@ecs ~]# sox --i -B input.flac
  • 双声道变单声道

    [root@ecs ~]# sox input.flac -c 1 output.mp3
  • 融合声道

    将左右声道的数据融合(mix)成单声道。

    [root@ecs ~]# sox input.flac output.mp3 remix 1,2
  • 合并声道

    [root@ecs ~]# sox -M left.wav right.wav output.flac

    mp3最多支持双声道,当声道数超过2个时,不能导出mp3。

  • 放大音量

    [root@ecs ~]# sox -v 1 input.wav output.wav

    为了防止过大造成消波,可以使用sox input.wav -n stat -v查看可放大倍数。

  • 裁剪

    [root@ecs ~]# sox input.flac output.wav trim 0 30
    [root@ecs ~]# sox input.flac output.wav trim 2:00 1:00

    trim接收2个参数,第一个参数为裁剪的起始位置,第二个参数为音频持续时间。持续时间可以为正整数(单位秒),也可以使用hh:mm:ss.fs时间格式。

  • 拼接

    [root@ecs ~]# sox input1.mp3 input2.mp3 output.mp3

    拼接不同于-M合并,拼接是将所有音频放在同一个声道按顺序连接到一起。

  • 混合

    [root@ecs ~]# sox -m input.flac -v 1.1 input.wav output.mp3

    将input.flac音量提高1.1倍后与input.wav融合(mix)。

    注:-m(Mix)是将输入音频相同声道的数据进行叠加,叠加后声道数据不可逆。而-M(Merge)是将输入音频存放于不同的声道,每个声道的数据是相互独立的。

WebP-Server工具,可将JPG/PNG即时压缩为WebP格式,可以大幅度的减少图片体积,减少出口带宽,提高用户体验。目前支持的图片格式:JPEG、PNG、BMP、GIF。

WebP

WebP是由Google推出的一种全新图片文件格式,也是Telegram Stickers主力使用的文件格式,可为Web上的图像提供卓越的压缩,它是在保证原有的图像质量前提下尽可能减少图形体积的一种格式,从而使Web加载性能的提升更快。

  • WebP的有损压缩算法是基于VP8视频格式的帧内编码,并以RIFF作为容器格式。 因此,它是一个具有八位色彩深度和以1:2的比例进行色度子采样的亮度-色度模型(YCbCr 4:2:0)的基于块的转换方案。不含内容的情况下,RIFF容器要求只需20字节的开销,依然能保存额外的元数据(metadata)。
  • WebP图像的边长限制为16383像素。
WebP lossless images are 26% smaller in size compared to PNGs. WebP lossy images are 25-34% smaller than comparable JPEG images at equivalent SSIM quality index.

通过是否对图片进行压缩,我们可以分为:

  • 无压缩。不对图片数据进行压缩处理,能准确地呈现原图片;
  • 无损压缩。压缩算法对图片的所有的数据进行编码压缩,能在保证图片的质量的同时降低图片的尺寸。
  • 有损压缩。压缩算法不会对图片所有的数据进行编码压缩,而是在压缩的时候,去除了人眼无法识别的图片细节,因此有损压缩可以在同等图片质量的情况下大幅降低图片的尺寸。

简单来说,WebP图片格式的存在,让我们在Web上展示的图片体积可以有较大幅度的缩小,也就带来了加载性能的提升。

要生成一个WebP图片非常简单,只需要下载Google提供的cwebp工具,并且使用cwebp -q 70 picture_with_alpha.png -o picture_with_alpha.webp命令就可以转换了,并且转换出来的webp图片比原图会小不少。

安装

CentOS 7.9

  • 安装libvips

    webp-server从0.6.0开始不再依赖libaom.so.3,开始依赖libvips.so.42,因此必须安装libvips 8.10.0或更高版本。

    安装libwebp

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.3.2.tar.gz
    [root@ecs src]# tar -xzf libwebp-1.3.2.tar.gz
    [root@ecs src]# cd libwebp-1.3.2
    [root@ecs libwebp-1.3.2]# ./configure --prefix=/usr/local --enable-libwebpmux --enable-libwebpdemux
    [root@ecs libwebp-1.3.2]# make -j$(nproc) && make install
    [root@ecs libwebp-1.3.2]# echo "export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:\$PKG_CONFIG_PATH" >> /etc/profile
    [root@ecs libwebp-1.3.2]# source /etc/profile
    [root@ecs libwebp-1.3.2]# pkg-config --modversion libwebp
    [root@ecs libwebp-1.3.2]# pkg-config --libs libwebp
    [root@ecs libwebp-1.3.2]# echo "/usr/local/lib" > /etc/ld.so.conf.d/libwebp.conf
    [root@ecs libwebp-1.3.2]# ldconfig
    [root@ecs libwebp-1.3.2]# ldconfig -p | grep libwebp
    [root@ecs libwebp-1.3.2]# webpinfo -version
    • pkg-config在编译程序时为编译器和构建系统(make、cmake)提供已安装库的元数据(头文件路径、库路径、依赖项、版本号等)。
    • ldconfig配置动态链接器(Dynamic Linker),在运行程序时能够快速找到所需的共享库(.so)。

    安装libimagequant

    4.0之开始用Rust重写,编译前需先安装Rust工具链。因此推荐2.18.0,完全满足libvips功能要求。

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# git clone https://github.com/ImageOptim/libimagequant.git -b 2.18.0
    [root@ecs src]# cd libimagequant
    [root@ecs libimagequant]# make static && make install

    安装niftiio

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf nifti_clib-3.0.0.tar.gz
    [root@ecs src]# cd nifti_clib-3.0.0
    [root@ecs nifti_clib-3.0.0]# yum install -y help2man
    [root@ecs nifti_clib-3.0.0]# cmake3 -DBUILD_SHARED_LIBS=ON \
    -DNIFTI_USE_PACKAGING=ON \
    -DUSE_CIFTI_CODE=ON \
    -DUSE_FSL_CODE=ON \
    -DNIFTI_BUILD_APPLICATIONS=ON \
    -DTEST_INSTALL=ON \
    -DDOWNLOAD_TEST_DATA=OFF .
    [root@ecs nifti_clib-3.0.0]# make && make install

    安装cfitsio

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# wget http://heasarc.gsfc.nasa.gov/FTP/software/fitsio/c/cfitsio_latest.tar.gz
    [root@ecs src]# tar -zxvf cfitsio_latest.tar.gz
    [root@ecs src]# cd cfitsio-4.6.4
    [root@ecs cfitsio-4.6.4]# ./configure --prefix=/usr/local --enable-reentrant
    [root@ecs cfitsio-4.6.4]# make && make install

    安装libspng

    [root@ecs ~]# cd /usr/loca/src
    [root@ecs src]# tar -zxvf libspng-0.7.4.tar.gz
    [root@ecs src]# cd libspng-0.7.4 && mkdir build && cd build
    [root@ecs build]# meson setup --prefix /usr/local ..
    [root@ecs build]# ninja
    [root@ecs build]# ninja install

    安装PDFium

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# wget https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-x64.tgz
    [root@ecs src]# tar -xvf pdfium-linux-x64.tgz -C /usr/local
    [root@ecs src]# cat /usr/local/VERSION
    MAJOR=153
    MINOR=0
    BUILD=7988
    PATCH=0
    [root@ecs src]# cat > /usr/local/lib/pkgconfig/pdfium.pc << EOF
    prefix=/usr/local
    exec_prefix=\${prefix}
    libdir=\${exec_prefix}/lib
    includedir=\${prefix}/include
    
    Name: PDFium
    Description: Google's PDF rendering engine
    Version: 153.0.7988
    Libs: -L\${libdir} -lpdfium
    Cflags: -I\${includedir}
    EOF
    • 验证是否安装成功

      [root@ecs ~]# pkg-config --modversion pdfium
      [root@ecs ~]# pkg-config --libs pdfium
      [root@ecs ~]# ldconfig -p | grep libpdfium
      [root@ecs ~]# ldd /usr/local/lib/libpdfium.so
    • 测试示例

      [root@ecs ~]# cat > pdfium_test.cpp << EOF
      #include <fpdfview.h>
      
      int main() {
          FPDF_InitLibrary();
          FPDF_DestroyLibrary();
          return 0;
      }
      EOF
      
      [root@ecs ~]# g++ pdfium_test.cpp $(pkg-config --cflags --libs pdfium) -o pdfium_test
      [root@ecs ~]# ./pdfium_test

      没有任何报错则说明pdfium已经安装成功。

    安装libvips

    [root@ecs ~]# yum install -y gcc-c++ \
    glib2-devel expat-devel \
    fftw-devel ImageMagick-devel orc-devel lcms2-devel OpenEXR-devel openslide-devel \
    poppler-glib-devel librsvg2-devel pango-devel \
    libpng-devel libtiff-devel giflib-devel libjpeg-devel libgsf-devel libexif-devel
    [root@ecs ~]# wget https://gh-proxy.org/https://github.com/libvips/libvips/releases/download/v8.10.5/vips-8.10.5.tar.gz
    [root@ecs ~]# tar -zxvf vips-8.10.5.tar.gz && cd vips-8.10.5
    [root@ecs vips-8.10.5]# ./configure --prefix=/usr/local --disable-static --enable-introspection=no \
    --with-pdfium-includes=/usr/local/include \
    --with-pdfium-libraries=/usr/local/pdfium/lib
    [root@ecs vips-8.10.5]# make && make install
    [root@ecs vips-8.10.5]# echo "/usr/local/lib" > /etc/ld.so.conf.d/vips.conf && ldconfig
    [root@ecs vips-8.10.5]# ldconfig -p | grep libvips

    注:

    • 如果使用PDFium,则必须设置--with-pdfium-includes--with-pdfium-libraries,否则即使安装了PDFium,PDF import with PDFium依旧为no。
    • pdfium优先级高于poppler-glib,一旦指定了pdfium,poppler-glib就会失效。

    示例

    • pdf转jpg

      [root@ecs ~]# vips copy input.pdf[dpi=72,page=0,n=1] output.jpg
      • dpi:控制输出图片分辨率,默认值72,数值越大,清晰度越高,文件越大。
      • page:指定转换起始页码(从0开始),不指定默认从第1页开始。
      • n:指定连续转换的页数,-1表示起始页到文档结尾所有页。输出多图时,所有页面垂直拼接成一张长图。
    • python

      import pyvips
      
      image = pyvips.Image.new_from_file('input.pdf', dpi=200, n=-1)
      image.write_to_file('output.jpg')
    • javascript

      const sharp = require('sharp');
      
      (async () => {
          sharp('input.pdf', { page: 0 })
              //设置宽度,高度自适应
              .resize(1024)
              //输出高质量jpeg
              .jpeg({ quality: 100 })
              .toFile('output.jpg');
      })();

    核心依赖库

    • glib2-devel(glib 2.x开发包)缺少则报错:configure: error: Package requirements (glib-2.0 >= 2.15 gmodule-2.0 gobject-2.0 gio-2.0) were not met
    • expat-devel(xml解析库)缺少则报错:configure: error: Could not find the Expat library

    其它依赖库(缺少不影响编译libvips,但会缺少相应的功能)

    配置项功能
    fftw-develuse fftw3 for FFT快速傅里叶变换
    ImageMagick-develMagick package
    Magick API version
    load with libMagick
    save with libMagick
    ImageMagick格式支持
    orc-develaccelerate loops with orc提升图像处理速度
    lcms2-develICC profile support with lcms色彩管理(防止图片偏色)
    niftiiofile import with niftiioNIfTI格式(核磁共振图像)支持
    libheiffile import with libheif苹果HEIC/HEIF格式支持
    OpenEXR-develfile import with OpenEXR高动态范围(HDR)图像支持
    openslide-develfile import with OpenSlide全切片(显微镜切片)病理图像支持
    matio-develfile import with matioMATLAB .mat数据支持
    PDFiumPDF import with PDFiumGoogle PDF渲染引擎(poppler-glib二选一)
    poppler-glib-develPDF import with poppler-glibpdf首页转图片
    librsvg2-develSVG import with librsvg-2.0将矢量图转位图
    cfitsiofile import with cfitsioFITS(天文望远镜图像)格式支持
    libwebpfile import/export with libwebpWebP格式导入导出支持
    pango-develtext rendering with pangoft2文本渲染(图片加文字水印)
    libspngfile import/export with libspnglibpng替代品(libpng二选一)
    libimagequantsupport 8bpp PNG quantisation8位png颜色量化
    libtiff-develfile import/export with libtifftiff格式支持
    giflib-develfile import/export with giflibgif格式支持
    libjpeg-develfile import/export with libjpegjpg格式支持
    libgsf-develimage pyramid export多分辨率切片格式支持
    libexif-develuse libexif to load/save JPEG metadata读取/保存 jpeg exif信息
  • 升级glibc

    webp-server从0.13.3开始依赖`GLIBC_2.34',必须升级glibc到2.34或更高版本。

    如果不想升级glibc,CentOS 7.9默认glibc支持的webp-server最高版本是0.13.1

  • 安装webp-server

    [root@ecs ~]# useradd -s /sbin/nologin www
    [root@ecs ~]# mkdir -p /data/webps && chown www:www /data/webps && chmod 755 /data/webps
    [root@ecs ~]# wget --no-check-certificate https://gh-proxy.org/https://github.com/webp-sh/webp_server_go/releases/download/0.13.1/webp-server-linux-amd64 -O /usr/local/bin/webp-server
    [root@ecs ~]# chmod +x /usr/local/bin/webp-server
    [root@ecs ~]# yum install -y libaom-devel
    [root@ecs ~]# webp-server -dump-config > /data/webps/config.json
    [root@ecs ~]# sed -i -e "s#127.0.0.1#0.0.0.0#" \
    -e "s#./pics#/data/wwwroot#" /data/webps/config.json
    [root@ecs ~]# webp-server --config=/data/webps/config.json

    预热模式(后台提前将/opt/pics目录内的所有图片转换成webp并缓存)

    [root@ecs ~]# webp-server --config=/data/webps/config.json -prefetch -jobs=${nproc}
    • -jobs=${nproc}控制-prefetch转换时使用的线程数,默认为CPU的内核数。
      查看方式:grep -c 'processor' /proc/cpuinfolscpu | grep "^CPU(s)"或者nproc
  • 开机自启动

    [root@ecs ~]# webp-server -dump-systemd > /lib/systemd/system/webp-server.service
    [root@ecs ~]# sed -i -e 's#WorkingDirectory=/opt/webps#WorkingDirectory=/data/webps#g' \
    -e 's#/opt/webps/webp-server#/usr/local/bin/webp-server#g' \
    -e 's#/opt/webps/config.json#/data/webps/config.json#g' \
    /lib/systemd/system/webp-server.service
    [root@ecs ~]# systemctl daemon-reload
    [root@ecs ~]# systemctl enable --now webp-server

    注:使用-dump-systemd参数生成的配置文件,webp-server的默认路径为:/opt/webps/webp-server,配置文件的默认路径:/opt/webps/config.json,需要修改为实际路径。

Docker部署

  1. 创建镜像

    [root@ecs ~]# cd /usr/local/src
    [root@ecs src]# tar -zxvf webp_server_go-0.15.1.tar.gz && cd webp_server_go-0.15.1
    [root@ecs webp_server_go-0.15.1]# cat > /tmp/trixie.tmp << 'DOCKERFILE'
    
    RUN rm -f /etc/apt/sources.list.d/*.sources /etc/apt/sources.list.d/*.list
    
    RUN cat > /etc/apt/sources.list <<EOF
    deb http://mirrors.aliyun.com/debian/ trixie main contrib non-free non-free-firmware
    deb http://mirrors.aliyun.com/debian/ trixie-updates main contrib non-free non-free-firmware
    deb http://mirrors.aliyun.com/debian-security/ trixie-security main contrib non-free non-free-firmware
    EOF
    
    ENV GOPROXY=https://mirrors.aliyun.com/goproxy/,direct/
    DOCKERFILE
    [root@ecs webp_server_go-0.15.1]# sed -i -e '/golang:1.26-trixie/r /tmp/trixie.tmp' -e '/debian:trixie-slim/r /tmp/trixie.tmp' Dockerfile
    [root@ecs webp_server_go-0.15.1]# docker build -t webp-server-go --progress=plain --no-cache .

    或者直接使用官方镜像:webpsh/webp-server-go

  2. 创建配置文件

    [root@ecs ~]# mkdir -p /data/webps
    [root@ecs ~]# cat > /data/webps/config.json << EOF
    {
        "HOST": "0.0.0.0",
        "PORT": "3333",
        "QUALITY": "80",
        "IMG_PATH": "/opt/pics",
        "EXHAUST_PATH": "./exhaust",
        "IMG_MAP": {},
        "ALLOWED_TYPES": ["jpg","png","jpeg","gif","bmp","svg","heic","nef"],
        "CONVERT_TYPES": ["webp"],
        "STRIP_METADATA": true,
        "ENABLE_EXTRA_PARAMS": true,
        "READ_BUFFER_SIZE": 4096,
        "CONCURRENCY": 262144,
        "DISABLE_KEEPALIVE": false,
        "CACHE_TTL": 259200
    }
    EOF
    • "ENABLE_EXTRA_PARAMS": true:允许图片url传参。
  3. 创建容器

    [root@ecs ~]# docker run -d \
    --restart always \
    --name webp-server \
    -p 3333:3333 \
    -v /data/webps/exhaust:/opt/exhaust \
    -v /data/webps/metadata:/opt/metadata \
    -v /data/wwwroot:/opt/pics \
    -v /data/webps/config.json:/etc/config.json:ro \
    webp-server-go

    注:docker容器不支持访问宿主的软链接,通过-v /data/webp/pics:/opt/pics,然后在/data/webp/pics中创建软件是无效的,必须使用-v /data/wwwroot/maisi:/opt/pics/maisi方式进行挂载。

  4. 测试

    • 拷贝baidu.png到宿主机/data/wwwroot/

      [root@ecs ~]# curl -I -H "Accept: image/webp" http://139.196.100.56:3333/baidu.png
    • 拷贝00248.jpg到宿主机/data/wwwroot/maisi

      [root@ecs ~]# curl -I -H "Accept: image/webp" http://139.196.100.56:3333/maisi/00248.jpg
      HTTP/1.1 200 OK
      Server: WebP Server Go
      Date: Sun, 02 Aug 2026 13:19:09 GMT
      Content-Type: image/webp
      Content-Length: 531136
      X-Compression-Rate: 0.34
      Accept-Ranges: bytes
      Last-Modified: Sun, 02 Aug 2026 13:02:04 GMT
      [root@ecs ~]# curl -I -H "Accept: image/webp" http://139.196.100.56:3333/maisi/00248.jpg?width=200
      HTTP/1.1 200 OK
      Server: WebP Server Go
      Date: Sun, 02 Aug 2026 13:18:10 GMT
      Content-Type: image/webp
      Content-Length: 2734
      X-Compression-Rate: 0.00
      Accept-Ranges: bytes
      Last-Modified: Sun, 02 Aug 2026 13:15:35 GMT

整合nginx

server {
    # CORS
    add_header Access-Control-Allow-Origin '*.maisi.com';
    add_header Access-Control-Allow-Methods 'GET,POST';
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

    # HSTS(强制浏览器在后续请求中只通过https与服务器通信)
    add_header Strict-Transport-Security "max-age=15768000;includeSubDomains;preload" always;
    
    # XXS-Protection
    add_header X-XSS-Protection "1; mode=block";

    # ssl
    ssl_certificate ../cert/maisi.com.pem;
    ssl_certificate_key ../cert/maisi.com.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;

    location ~* \.(?:jpg|jpeg|gif|png)$ {
        # 禁止cdn缓存
        add_header Cache-Control 'private';
        proxy_pass http://127.0.0.1:3333/maisi$request_uri;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_hide_header X-Powered-By;
        proxy_set_header HOST $http_host;
        add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
    }

}