4、FFmpeg入门:FFmpeg核心组件、常用命令、交叉编译Android库

好,咱们今天聊聊FFmpeg。说实话,做Android音视频开发,FFmpeg是绕不过去的一道坎。我当年刚接触时也觉得这东西又大又复杂,编译一次能折腾一整天。但等你真正理解了它的核心组件和设计思路,你会发现——嗯,其实也没那么玄乎。

4.1 FFmpeg是什么?

FFmpeg,全称是Fast Forward MPEG。说白了,它是一个开源的、跨平台的音视频处理工具集。你能想到的跟音视频有关的操作——转码、剪辑、拼接、推流、拉流、滤镜、截图——它几乎都能干。

我个人习惯把它比作「音视频领域的瑞士军刀」。你想想看,一个工具能处理几乎所有格式,能跑在Windows、Linux、macOS、Android、iOS上,这本身就说明它的设计有多扎实。

核心要点:FFmpeg不是单个程序,而是一套完整的音视频处理框架。它由多个库和可执行文件组成,你可以按需取用。

4.2 FFmpeg核心组件

FFmpeg的架构,我建议你从这几个核心组件入手理解:

组件 全称 作用
libavformat Format Library 封装/解封装,处理容器格式(MP4、MKV、FLV等)
libavcodec Codec Library 编解码核心,处理H.264、AAC、MP3等编码格式
libavutil Utility Library 工具库,提供内存管理、数学运算、数据结构等基础能力
libswscale Software Scaling 图像缩放、色彩空间转换(比如YUV转RGB)
libswresample Software Resample 音频重采样、格式转换、声道布局调整
libavfilter Filter Library 滤镜处理,支持复杂的音视频滤镜链
libavdevice Device Library 设备输入输出,比如摄像头、麦克风采集

我记得刚开始学的时候,总搞不清libavformat和libavcodec的区别。后来在项目中调试一个MP4文件播放卡顿的问题,才真正理解了:libavformat负责把文件拆成一个个数据包,libavcodec负责把这些包解码成原始图像或声音。一个是拆快递的,一个是拆包装的——这么想就清楚了。

我的建议:先重点掌握libavformat、libavcodec、libavutil这三个。其他组件可以在用到时再深入。一口吃不成胖子,做音视频开发尤其如此。

4.3 FFmpeg常用命令

命令行的FFmpeg,是调试和验证思路最快的方式。我在项目中经常先用命令行跑通流程,再把它翻译成代码。下面这几个命令,我建议你背下来:

4.3.1 查看文件信息

ffmpeg -i input.mp4

这个命令会输出文件的编码格式、分辨率、帧率、码率、时长等信息。排查问题时的第一步,我几乎都是先跑这个。

4.3.2 格式转换

ffmpeg -i input.avi -c:v libx264 -c:a aac output.mp4

把AVI转成MP4,视频用H.264编码,音频用AAC编码。这里-c:v和-c:a分别指定视频和音频的编码器。

4.3.3 截取片段

ffmpeg -i input.mp4 -ss 00:01:00 -t 10 -c copy output.mp4

从第1分钟开始,截取10秒的内容。-ss指定起始时间,-t指定时长。-c copy表示直接复制,不重新编码,速度极快。

注意:-ss放在-i前面还是后面,效果不一样。放在前面是「快速定位」,放在后面是「精确定位」。我曾经因为搞混这个,截出来的视频总是多出几帧黑屏。后来养成了习惯:需要快速截取时用前者,需要精确到帧时用后者。

4.3.4 缩放视频

ffmpeg -i input.mp4 -vf "scale=1280:720" output.mp4

-vf是视频滤镜参数,scale是缩放滤镜。这里把视频缩放到1280x720。

4.3.5 提取音频

ffmpeg -i input.mp4 -vn -c:a copy audio.aac

-vn表示不要视频流,只提取音频。如果音频编码是AAC,直接用-c:a copy复制,不需要重新编码。

4.4 交叉编译Android库

好,到了最让人头疼的部分——交叉编译。说白了,就是在你的电脑上编译出能在Android手机上运行的库。我当年第一次编译FFmpeg for Android,折腾了整整两天。现在回头看,其实只要搞明白几个关键点,就没那么难。

4.4.1 准备工作

你需要准备:

  • NDK(Native Development Kit)——推荐使用r21或r23版本
  • FFmpeg源码——从官网下载,我习惯用4.4.x稳定版
  • Linux或macOS环境——Windows下建议用WSL或Docker

4.4.2 编写编译脚本

下面是我常用的编译脚本模板,针对Android ARM64架构:

#!/bin/bash

NDK=/path/to/android-ndk-r23b
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
API=21

export CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
export CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
export LD=$TOOLCHAIN/bin/ld
export AR=$TOOLCHAIN/bin/llvm-ar
export AS=$TOOLCHAIN/bin/llvm-as
export NM=$TOOLCHAIN/bin/llvm-nm
export STRIP=$TOOLCHAIN/bin/llvm-strip

./configure \
  --target-os=android \
  --arch=aarch64 \
  --cc=$CC \
  --cxx=$CXX \
  --ld=$LD \
  --ar=$AR \
  --as=$AS \
  --nm=$NM \
  --strip=$STRIP \
  --enable-cross-compile \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --disable-programs \
  --disable-avdevice \
  --enable-avformat \
  --enable-avcodec \
  --enable-avutil \
  --enable-swscale \
  --enable-swresample \
  --enable-avfilter \
  --prefix=./android/arm64

make -j8
make install

关键点说明:

  • --enable-shared:编译成动态库(.so),Android上推荐用动态库
  • --disable-programs:不编译ffmpeg、ffplay等可执行文件,我们只需要库
  • --disable-avdevice:Android上一般用不到设备输入输出,关掉可以减小体积
  • API=21:最低支持Android 5.0,覆盖了绝大多数设备

4.4.3 编译产物

编译完成后,在./android/arm64/lib目录下会生成一系列.so文件:

libavcodec.so
libavformat.so
libavutil.so
libswscale.so
libswresample.so
libavfilter.so

把这些.so文件放到Android项目的app/src/main/jniLibs/arm64-v8a/目录下,再把对应的头文件放到app/src/main/cpp/include/目录下,就可以在JNI代码中调用了。

避坑指南:我曾经在编译时忘了加--enable-cross-compile,结果编译出来的库在手机上跑起来就崩。排查了半天才发现是交叉编译标志没开。嗯,这种低级错误,犯过一次就记住了。

4.5 知识体系总览

下面这张图,是我梳理的FFmpeg入门知识体系。你可以把它当作学习路线图:

FFmpeg入门知识体系 核心组件(7个库) libavformat libavcodec libavutil libswscale/swresample 常用命令(5类核心操作) 查看信息 格式转换 截取片段 缩放视频 提取音频 交叉编译Android库(NDK + 编译脚本 → .so文件)

从这张图你可以看到,FFmpeg入门其实就三条线:理解组件、会用命令、能编译库。三条线缺一不可,但也不用同时精通。我个人建议的顺序是:先玩命令,再学组件,最后搞编译。命令玩熟了,你对FFmpeg的能力边界就有了直观感受,后面学组件和编译时心里就有底了。

最后说一句:FFmpeg的学习曲线确实有点陡,但只要你把核心组件搞明白,把编译流程跑通一遍,后面再遇到音视频相关的问题,你至少知道该从哪里下手。我在项目中遇到过的绝大多数音视频问题,最终都能用FFmpeg找到答案——要么是命令行验证,要么是库调用。所以,花时间把这一章吃透,绝对值。


公众号:蓝海资料掘金营,微信deep3321