【音视频开发】2. FFmpeg 环境安装 + 开发中常用的命令

136 阅读9分钟

FFmpeg 环境安装 + 开发中常用的命令

1、快速安装 FFmpeg

  • 下载预编译的命令行程序和库文件Releases · BtbN/FFmpeg-Builds,带 shared 的版本
  • 官方的 命令行文档 和 API 文档Documentation
  • Windows 系统配置命令行环境:把 bin 目录放入 Path 环境变量
ffmpeg -version
  • Windows 系统配置开发环境:以 CMake 为例,替换其中的路径变量即可
cmake_minimum_required(VERSION 3.20)
project(ffmpeg_test)

set(CMAKE_CXX_STANDARD 20)
set(FFMPEG7_DIR "path/to/ffmpeg")
set(TARGET_NAME ${PROJECT_NAME})

add_executable(${TARGET_NAME} main.cpp)

target_include_directories(${TARGET_NAME} PRIVATE
	${FFMPEG7_DIR}/include
)

target_link_directories(${TARGET_NAME} PRIVATE
	${FFMPEG7_DIR}/lib
)

set(FFMPEG7_LIBS 
	avformat.lib # 文件格式和协议库
	avcodec.lib # 编解码库, 支持第三方 codec
	avutil.lib # 核心工具库
	avdevice.lib # 输入输出设备库
	avfilter.lib # 音视频滤镜库
	swscale.lib # 图像缩放和格式转换库
	swresample.lib # 音频重采样和格式转换库
	postproc.lib # 解码后的处理库
)
target_link_libraries(${TARGET_NAME} PRIVATE 
	${FFMPEG7_LIBS}
)

if (WIN32)
    file(GLOB FFMPEG7_DLLS "${FFMPEG7_DIR}/bin/*.dll")
    add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FFMPEG7_DLLS} $<TARGET_FILE_DIR:${TARGET_NAME}>
            COMMENT "Copying all required DLLs to output directory"
    )
endif ()
  • 第一个 FFmpeg 程序:
#include <cstdio>

extern "C" {
#include <libavformat/avformat.h>
}

int main() {
    printf("FFmpeg version: %s\n", av_version_info());
    return 0;
}

2、ffplay 命令

  • 常用命令
ffplay a.mp4 -fs			# 全屏播放视频
ffplay a.mp4 -autoexit -fs	# 播放结束后退出
ffplay a.mp4 -loop 2 -fs	# 循环播放两次
ffplay a.mp4 -ss 2 -fs		# 从第二秒开始播放
ffplay a.mp4 -t 2 -fs		# 只播放 2s
ffplay a.mp4 -x 512 -y 512	# 在自定义大小窗口中播放

ffplay a.mp4 -vf "setpts=0.5*PTS" -af "atempo=2" -fs # 音视频 2 倍速
ffplay a.mp4 -an 			# 禁用, an音频, vn视频, sn字幕
ffplay a.aac -showmode 1  	# 设置显示模式, 0 视频, 1 音频波形, 2 音频频谱
ffplay a.mp4 -sync audio  	# 同步, audio/video/ext
ffplay a.mp4 -vcodec name 	# 指定解码器, acodec/vcodec/scodec

ffplay a.mp4 -vf hflip -fs	# 水平翻转播放
ffplay a.mp4 -vf vflip -fs	# 垂直翻转播放
ffplay a.mp4 -vf transpose=1 -fs # 顺时针旋转 90° 播放
ffplay a.mp4 -vf transpose=2 -fs # 逆时针旋转 90° 播放
ffplay a.mp4 -vf transpose=1,transpose=1 -fs # 旋转 180° 播放

# 播放 yuv
ffplay -pixel_format yuv420p -video_size 1920*1080 -framerate 5 -i yuv420p_a.yuv -fs
# 播放 rgb
ffplay -pixel_format rgb24 -video_size 1920*1080 -framerate 5 -i rgb24_a.rgb -fs
# 播放 pcm
ffplay -ar 48000 -ac 2 -f f32le -i 48000_2_f32le.pcm
  • 快捷键
P 或	<SPACE> # 暂停/继续播放
F 或 双击 # 进入/退出满屏显示
Q 或 <ESC> # 退出播放器
S # 显示下一帧
W # 切换显示视频/音频波形/音频频谱
<LEFT> 和 <RIGHT> # 前进/后退 10s(可自定义)
<UP> 和 <DOWN> # 前进/后退 60s
9 和 0 # 减少/增加音量
M # 静音
C # 多路视频的切换, A/V 单独切换 音频/视频

3、ffprobe 命令

  • 常用命令
# 输出图片信息
ffprobe a.png -hide_banner -show_format
# 输出视频格式信息
ffprobe a.mp4 -v error -show_format -print_format json
# 输出每个流的信息(音频, 视频等)
ffprobe a.mp4 -v error -show_streams -print_format json
# 把视频格式信息和所有流的信息都用 json 格式输出到文件
ffprobe a.mp4 -v error -show_format -show_streams -print_format json > a.txt
# 把每个帧的信息用 json 格式输出到文件
ffprobe a.mp4 -hide_banner -show_frames -print_format json > frames.txt
  • 视频格式输出
codec_name=h264     # 编码器名称
codec_type=video    # 流类型
width=1920          # 视频宽度
height=1080         # 视频高度
duration=78.730000  # 总播放秒数
bit_rate=12917774   # 平均码率
r_frame_rate=30/1   # 帧率
nb_frames=2362      # 总帧数
has_b_frames=1      # 是否含有 B 帧
nal_length_size=4   # NAL单元长度
pix_fmt=yuvj420p    # 像素格式
color_space=bt709   # 色彩空间

4、ffmpeg 命令

  • ffmpeg 常见的编解码器
    • libx264/libx265/libaom-av1:开源的软件编码器,较慢
    • h264_nvenc/hevc_nvenc/av1_nvenc:NVIDIA 显卡的硬件编码器
    • h264_cuvid/hevc_cuvid/av1_cuvid:NVIDIA 显卡的硬件解码器
    • h264_amf/hevc_amf/av1_amf:AMD 显卡的硬件编码器,ffmpeg 暂不支持解码
    • h264_qsv/hevc_qsv:Intel 显卡的硬件编解码器
    • h264_videotoolbox/hevc_videotoolbox:苹果 M 芯片的硬件编码器
    • 查看特定编码器用法:ffmpeg -v error -h encoder=h264_nvenc
  • 查看配置信息:
ffmpeg -v error -h          # 帮助
ffmpeg -v error -h muxer=flv# 详细的帮助信息
ffmpeg -v error -buildconf  # 查看环境
ffmpeg -v error -formats    # 查看支持的媒体格式
ffmpeg -v error -muxers     # 查看可用的的复用器
ffmpeg -v error -demuxers   # 查看可用的的解复用器
ffmpeg -v error -codecs     # 查看可用的的编解码器, 
ffmpeg -v error -encoders   # 查看可用的编码器
ffmpeg -v error -decoders   # 查看可用的解码器
ffmpeg -v error -devices    # 查看输入输出设备
ffmpeg -v error -protocols  # 查看支持的协议
ffmpeg -v error -bsfs       # 查看可用的比特流过滤器
ffmpeg -v error -filters    # 查看可用的音视频过滤器
ffmpeg -v error -pix_fmts   # 查看可用的像素格式
ffmpeg -v error -layouts    # 查看可用的声道格式
ffmpeg -v error -sample_fmts# 查看可用的采样格式
ffmpeg -v error -colors     # 查看颜色
  • 复用和解复用:
# 提取视频流(注意输出文件选 .264 还是 .hevc)
ffmpeg -hide_banner -i a.mp4 -an -vcodec copy a.hevc
ffmpeg -hide_banner -i a.mp4 -an -c:v copy a.hevc
# 提取音频流
ffmpeg -hide_banner -i a.mp4 -vn -acodec copy a.aac
ffmpeg -hide_banner -i a.mp4 -vn -c:a copy a.aac
# 合并音频流和视频流
ffmpeg -hide_banner -i a.hevc -i a.aac -c copy a.mp4
# .hevc 转 .mp4
ffmpeg -hide_banner -i a.hevc -c:v copy a.mp4 
# .mp4 转 .mov 
ffmpeg -hide_banner -i a.mp4 -c copy a.mov
  • 音视频转码:假设 a.mp4 格式为1920*1080; 13Mbps + 200Kbps; 60fps
# 截取视频的前 10s
ffmpeg -hide_banner -i a.mp4 -t 0:0:10.000 -c:v h264_amf -b:v 13M -c:a aac -b:a 200k b.mp4
# 从 5 秒处开始截取 5 秒视频
ffmpeg -hide_banner -i a.mp4 -ss 0:0:5.000 -t 0:0:5.000 -c:v h264_amf -b:v 13M -c:a aac -b:a 200k b.mp4
# 改为 2 倍速: 帧率翻倍, 码率翻倍(画面质量接近)
ffmpeg -hide_banner -i a.mp4 -vf "setpts=0.5*PTS" -c:v hevc_amf -b:v 26M -af "atempo=2.0" -c:a aac -b:a 400k -r 120 b.mp4
# 改为 2 倍速: 帧率翻倍, 码率不变(画面质量下降)
ffmpeg -hide_banner -i a.mp4 -vf "setpts=0.5*PTS" -c:v hevc_amf -b:v 13M -af "atempo=2.0" -c:a aac -b:a 200k -r 120 b.mp4
# 改为 2 倍速: 帧率不变, 码率不变(画面质量接近)
ffmpeg -hide_banner -i a.mp4 -vf "setpts=0.5*PTS" -c:v hevc_amf -b:v 13M -af "atempo=2.0" -c:a aac -b:a 200k b.mp4
# 改为 0.5 倍速: 帧率减半, 码率减半
ffmpeg -hide_banner -i a.mp4 -vf "setpts=2*PTS" -c:v hevc_amf -b:v 6M -af "atempo=0.5" -c:a aac -b:a 100k -r 30 b.mp4

# 把直播内容拉流到本地保存(注意: 非 rtmp 协议需要转码)
ffmpeg -i rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid -c copy  dump.flv
  • 视频流转码:假设 a.mp4 格式为1920*1080; 13Mbps + 200Kbps; 60fps
# 缩放视频: 固定分辨率(1280*720) + 固定码率(6Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "scale=1280:720" -c:v hevc_amf -b:v 6M -c:a copy b.mp4
# 缩放视频: 固定纵向宽度(720p) + 固定质量(crf = 18)
ffmpeg -hide_banner -i a.mp4 -vf "scale=-1:720" -c:v hevc_amf -crf 18 -c:a copy b.mp4
# 缩放透明背景 GIF
ffmpeg -i oiiai.gif -filter_complex "[0:v]split[x][z];[z]palettegen[y];[x]scale=50:50[x1];[x1][y]paletteuse" oiiai_50x50.gif

# 裁剪视频画面: 1080p => 720p 居中裁剪 + 固定码率(6Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "crop=1280:720:320:180" -c:v h264_amf -b:v 6M -c:a copy b.mp4
# 填充视频画面: 16:9 => 16:10 画面居中(上下填充黑色) + 固定码率(13Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "pad=1920:1200:0:60:black" -c:v h264_amf -b:v 13M -c:a copy b.mp4

# 在视频右上角添加图片水印(改为 60*60 并贴到右上角)
# [0:v] 表示第一个输入的视频流, [1:v] 表示第二个输入的视频流
# [new_icon] 是自定义的标签, 表示引用了 scale 滤镜的结果
ffmpeg -hide_banner -i a.mp4 -i a.png -filter_complex "[1:v]scale=60:60[new_icon];[0:v][new_icon]overlay=1860:0" -c:v h264_amf -b:v 13M -c:a copy b.mp4

# 视频画面拼接方法1(pad + overlay)
ffmpeg -hide_banner -i a.mp4 -i a.mp4 -i a.mp4 -filter_complex "[0:v]pad=1920:3240:0:0[pad];[pad][1:v]overlay=0:1080[pad1];[pad1][2:v]overlay=0:2160" b.mp4

# 视频画面拼接方法2(nullsrc + overlay)
ffmpeg -hide_banner -f lavfi -i nullsrc=size=1920x3240:r=60 -i a.mp4 -i a.mp4 -i a.mp4 -filter_complex "[0:v][1:v]overlay=0:0:shortest=1[temp0];[temp0][2:v]overlay=0:1080[temp1];[temp1][3:v]overlay=0:2160" b.mp4

# 竖直翻转视频: 固定码率(13Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "vflip" -c:v h264_amf -b:v 13M -c:a copy b.mp4
# 水平翻转视频: 固定分辨率(1920*1080) + 固定码率(13Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "hflip, scale=1920:1080" -c:v h264_amf -b:v 13M -c:a copy b.mp4
# 顺时针旋转 90°: 固定码率(13Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "transpose=1" -c:v h264_amf -b:v 13M -c:a copy b.mp4
# 逆时针旋转 90°: 固定码率(13Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "transpose=2" -c:v h264_amf -b:v 13M -c:a copy b.mp4
# 旋转 180°: 固定码率(13Mbps)
ffmpeg -hide_banner -i a.mp4 -vf "transpose=1, transpose=1" -c:v h264_amf -b:v 13M -c:a copy b.mp4

# 提取 1s 的 YUV
ffmpeg -hide_banner -i a.mp4 -t 1 -pix_fmt yuv420p yuv420p_a.yuv
ffmpeg -hide_banner -i a.mp4 -t 1 -pix_fmt yuv420p -s 1920*1080 yuv420p_a.yuv
# 提取 1s 的 RGB
ffmpeg -hide_banner -i a.mp4 -t 1 -pix_fmt rgb24 rgb24_a.rgb
ffmpeg -hide_banner -i a.mp4 -t 1 -pix_fmt rgb24 -s 1920*1080 rgb24_a.rgb
# YUV 转 RGB
ffmpeg -hide_banner -s 1920*1080 -pix_fmt yuv420p -i yuv420p_a.yuv -pix_fmt rgb24 rgb24_a1.rgb
  • 音频流转码:
# 音量翻倍(增加 6dB)
ffmpeg -hide_banner -i a.mp4 -af "volume=6dB" -c:v copy -c:a aac -b:a 200k b.mp4
# 音量减半(减少 6dB)
ffmpeg -hide_banner -i a.mp4 -af "volume=-6dB" -c:v copy -c:a aac -b:a 200k b.mp4
# 音频流提取 PCM 
ffmpeg -i a.mp4 -ar 48000 -ac 2 -f s16le 48000_16bit_2ch.pcm
  • 前后拼接两段视频:a.mp4 和 b.mp4 格式都是 1920*1080; 13Mbps + 200Kbps; 60fps
# 注意: 待拼接的两个视频的(分辨率, 帧率, 编码格式)需要提前转码成完全相同
# 首先新建一个 mylist.txt, 包括以下内容
file 'a.mp4'
file 'b.mp4'
# 拷贝拼接两个视频
ffmpeg -hide_banner -f concat -safe 0 -i mylist.txt -c copy c.mp4
# 转码拼接两个视频
ffmpeg -hide_banner -f concat -safe 0 -i mylist.txt -c:v h264_amf -b:v 13M -c:a aac -b:a 200k -r 60 c.mp4
  • 视频与图片互转:
# 帧率15的视频 => 多张图片
ffmpeg -i believe.mp4 -r 15 -f image2 frames/frame-%05d.jpg
# 多张图片 => 帧率15的视频
ffmpeg -f image2 -framerate 15 -i frames/frame-%05d.jpg -b:v 150k output.mp4
# 截取一张图片
ffmpeg -i test.mp4 -f image2 -ss 00:00:02 -vframes 1 -s 1920*1080 test.jpg