什么是FFmpeg
FFmpeg 既是一款音视频编解码工具,同时也是一组音视频编解码开发套件,作为编解码开发套件,它可以为我们提供丰富的音视频处理的调用接口。
FFmpeg 提供了媒体格式的封装和解封装,包括音视频编码、多种协议的流媒体、色彩格式转换、采样率转换、码率转换等。
FFmpeg 框架提供了多种丰富的插件模块,包含封装与解封装的插件、编码与解码的插件等。
"FFmpeg"中"FF"指的是"Fast Forward","mpeg"指的是一种压缩率比较大的活动图像和声音的压缩标准。
命令行工具
- ffmpeg: 包含FFmpeg的各种功能,如gif、格式转换、截图、编解码等。
- ffmpeg-all:包含FFmpeg工具及FFmpeg组件。
- ffplay:一个使用了FFmpeg和SDL库的简单可移植的媒体播放器。
- ffplay-all:包含ffplay工具及FFmpeg组件。
- ffprobe:用来查看多媒体文件的信息。
- ffprobe-all:包含ffprobe工具及FFmpeg组件。
- ffserver:与流媒体服务器相关,负责响应客户端的流媒体请求,把流媒体数据发送给客户端。
- ffserver-all:包含f'fserver工具及FFmpeg组件。
组件
- Utilities:libavutil提供的t通用的features及工具。
- Video scaling and pixel format converter:视频缩放和像素格式转换器。
- Audio resampler:音频重新采样。
- Encoders and decoders(codecs):编码和解码。
- Bitstream filters:码流过滤器。
- Muxers and demuxers(formats):数据合成及数据分离。
- Protocols:协议。
- Input and output devices:输入和输出设备。
- Filters:过滤器。
类库
- libavutil:包含一些公共的工具函数的使用库,包括算术运算、字符操作等。
- libswscale:(原始视频格式转换)用于食品场景比例缩放、色彩映射转换、图像颜色空间或格式转换,如RGB565、RGB888等与YUV420等之间的转换。
- libswresample:原始音频格式转码。
- libavcodec:用于各种类型声音/图像编解码。该库是音视频编解码核心库,实现了市面上可见的绝大部分编解码器的功能。
- libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能。音视频的格式解析协议,为
libavcodec 分析码流提供独立的音频或视频码流源。- libavdevice:硬件采集、加速、显示。操作计算机中常见的音视频捕获或输出设备有ALSA、AUDIO_BEOS、JACK、OSS、1394、VFW等。
- libavfilter:filter(FileIO、FPS、DrawText)音视频滤波器的开发,如宽高比、裁剪、格式化、非格式化、伸缩等。
- libavresample:音视频封装编解码格式预设等。
- libpostproc:(同步、时间计算的简单算法)用于后期效果处理,音视频应用的后处理,如图像的去块效应。
FFmpeg 的编解码工具-ffmpeg
ffmpeg 是 FFmpeg源码编译后生成的可执行程序,可以作为命令行工具来使用。
例如:
./ffmpeg -i input.mp4 output.avi
这是一条简单的 ffmpeg 命令,通过 -i 参数将 input.mp4 作为输入源,然后进行转码和转封装操作,输出到 output.avi 中。
上面指令也可以写成:./ffmpeg -i input.mp4 -f avi output.dat
-f 参数指定了输出文件的容器格式,输出的文件 output.dat 同样是 avi 格式文件。(不要光看文件后缀名就断定文件封装格式)
ffmpeg 大致处理流程:
1,读取输入源
2,解封装
3,解码
4,重新编码
5,重新封装
6,输出目标文件
(具体代码流程可以查阅ffmpeg源码)
FFmpeg 的播放器-ffplay
ffplay 也是 FFmpeg 源码编译生成的一个可执行程序,通常作为测试工具来使用。ffplay 提供了音视频显示和播放相关的图像信息,音频的波形信息等。
播放 input.mp4 文件:
./ffplay input.mp4
FFmpeg 的多媒体分析工具-ffprobe
ffprobe 也是 FFmpeg 源码编译生成的一个可执行程序,可以从媒体文件或媒体流中获取详细的媒体信息,如音视频的编码格式、媒体容器的参数信息等。
查看 input.mp4 中流的信息:
./ffprobe -show_streams input.mp4
linux下编译FFmpeg
环境准备
linux服务器或虚拟机(自行解决)
下载linux版ndk(android-ndk-r17c-linux-x86_64.zip)
NDK下载地址
wget https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip
解压ndk
unzip android-ndk-r17c-linux-x86_64.zip
下载FFmpeg(ffmpeg-4.2.1.tar.bz2)
wget https://ffmpeg.org/releases/ffmpeg-4.2.1.tar.bz2
解压FFmpeg
tar -xjvf ffmpeg-4.2.1.tar.bz2
configure文件
configure文件其实是一个shell脚本,用于生成MakeFile文件,然后可以使用make命令执行。我们可以通过执行 ./configure --help
来查看编译相关信息。
#将help信息输出到文本中便于查看
$ ./configure --help > ffmpeg_configure_help.txt
#发送到windows端查看更happy
$ sz ffmpeg_configure_help.txt
最新版本的ffmpeg默认使用clang编译,可以修改configure文件来关闭:
注释4210-4213行,简单粗暴:
4209
4210 #set_default target_os
4211 #if test "$target_os" = android; then
4212 # cc_default="clang"
4213 #fi
4214
编写交叉编译FFmpeg的shell脚本build.sh
#!/bin/bash
#NDK_ROOT 变量指向ndk目录
NDK_ROOT=/root/android-ndk-r17c
#TOOLCHAIN 变量指向ndk中的交叉编译gcc所在的目录
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
#指定android api版本
ANDROID_API=17
#此变量用于编译完成之后的库与头文件存放在哪个目录
PREFIX=./android/armeabi-v7a
#执行configure脚本,用于生成makefile
#--prefix : 安装目录
#--enable-small : 优化大小
#--disable-programs : 不编译ffmpeg程序(命令行工具),我们是需要获得静态(动态)库。
#--disable-avdevice : 关闭avdevice模块,此模块在android中无用
#--disable-encoders : 关闭所有编码器 (播放不需要编码)
#--disable-muxers : 关闭所有复用器(封装器),不需要生成mp4这样的文件,所以关闭
#--disable-filters :关闭视频滤镜
#--enable-cross-compile : 开启交叉编译
#--cross-prefix: gcc的前缀 xxx/xxx/xxx-gcc 则给xxx/xxx/xxx-
#disable-shared enable-static 不写也可以,默认就是这样的。
#--sysroot:
#--extra-cflags: 会传给gcc的参数
#--arch --target-os : 必须要给
./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--disable-shared \
--enable-static \
--sysroot=$NDK_ROOT/platforms/android-$ANDROID_API/arch-arm \
--extra-cflags="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC" \
--arch=arm \
--target-os=android
#上面运行脚本生成makefile之后,使用make执行脚本
make clean
make install
执行编译脚本build.sh
- 首先需要给脚本加上可执行权限:
chmod +x build.sh
- 执行shell脚本:
./build.sh
- 编译结束后会将编译的静态库放在 android/armeabi-v7a 目录下。
也可以将静态库打包成一个so库
cd lib export CC=/root/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc export AA="--sysroot=/root/android-ndk-r17c/platforms/android-17/arch-arm/" $CC $AA -shared -o libffmpeg.so -Wl,--whole-archive *.a -Wl,--no-whole-archive
编译集成librtmp
下载编译librtmp
源码下载此处省略,编译librtmp的脚本如下:
#!/bin/bash
NDK_ROOT=/root/android-ndk-r17c
CPU=arm-linux-androideabi
TOOLCHAIN=$NDK_ROOT/toolchains/$CPU-4.9/prebuilt/linux-x86_64
export XCFLAGS="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=17"
export XLDFLAGS="--sysroot=${NDK_ROOT}/platforms/android-17/arch-arm "
export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
make install SYS=android prefix=`pwd`/install CRYPTO= SHARED= XDEF=-DNO_SSL
由于ffmpeg 默认开启librtmp需要pkgconfig,这里我们手动关闭,修改ffmpeg的configure文件:
注释掉6256行,简单粗暴:
6254 enabled libpulse && require_pkg_config libpulse libpulse pulse/pulseaudio.h pa_context_new
6255 enabled librsvg && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo
6256 #enabled librtmp && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket
6257 enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && app end librubberband_extralibs "-lstdc++"
修改ffmpeg编译脚本,这里将前面脚本copy一份重命名 build_ffmpeg_with_librtmp.sh
来进行修改:
#!/bin/bash
NDK_ROOT=/root/android-ndk-r17c
CPU=arm-linux-androideabi
TOOLCHAIN=$NDK_ROOT/toolchains/$CPU-4.9/prebuilt/linux-x86_64
ANDROID_API=17
PREFIX=./build_outputs/armeabi-v7a/ffmpeg_rtmp
#rtmp路径
RTMP=/root/he/ffmpeg/librtmp/install
./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-librtmp \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/$CPU- \
--disable-shared \
--enable-static \
--sysroot=$NDK_ROOT/platforms/android-$ANDROID_API/arch-arm \
--extra-cflags="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC -I$RTMP/include" \
--extra-ldflags="-L$RTMP/lib" \
--extra-libs="-lrtmp" \
--arch=arm \
--target-os=android
make clean
make install