ffmpeg使用入门

1 ffmpeg安装

1.1 安装vcpkg

直接从github上下载Release版本,并进行安装

复制代码
https://github.com/microsoft/vcpkg

从GitHub克隆vcpkg存储库。存储库包含用于获取vcpkg可执行文件的脚本,以及由vcpkg社区维护的特选开放源代码库的注册表。要执行此操作,请运行:

复制代码
git clone https://github.com/microsoft/vcpkg.git

vcpkg特选注册表是一组数量超过2000个的开源库。 这些库已通过vcpkg的持续集成管道进行验证,可以协同工作。虽然vcpkg存储库不包含这些库的源代码,但它保存方案和元数据,以便在系统中生成和安装它们。

导航到vcpkg目录并执行启动脚本:

复制代码
cd vcpkg && bootstrap-vcpkg.bat

启动脚本执行先决条件检查并下载vcpkg可执行文件。就这么简单,vcpkg已安装并可供使用。

配置VCPKG_ROOT环境变量。

复制代码
set "VCPKG_ROOT=C:\path\to\vcpkg"
set PATH=%VCPKG_ROOT%;%PATH%

以这种方式设置环境变量只会影响当前终端会话。若要使这些更改在所有会话中永久存在,请通过"Windows 系统环境变量"面板进行设置。

1.2 安装其他库

一切准备就绪,在cmd命令行执行如下命令安装ffmpeg静态库:

复制代码
vcpkg.exe install ffmpeg:x86-windows-static

在cmd命令行执行如下命令安装ffmpeg动态库:

复制代码
vcpkg.exe install ffmpeg:x86-windows

安装过程如下:

使用vcpkg list可以列出当前所有安装的库,使用vcpkg remove可以卸载安装的库。

1.3 exe文件获取

vcpkg install ffmpeg默认不会安装ffmpeg.exe等工具程序,它只安装了作为库使用的 FFmpeg C/C++开发接口,如:avcodec、avformat、avutil、swscale等.lib/.dll,以及include/*/*.h头文件,因为vcpkg的目标是为C/C++项目提供开发依赖(SDK/库),而不是提供命令行工具(像ffmpeg.exe这种完整可执行程序)。要想使用ffmpeg.exe这种命令行工具,可以从官网https://ffmpeg.org/download.html下载预编译版本:

如下载 "release full"版本,解压后会包含ffmpeg.exe、ffplay.exe、ffprobe.exe三个可执行文件,将其路径添加到环境变量PATH中即可在cmd命令行直接使用这三个命令。

2 命令使用介绍

2.1 ffmpeg.exe

1. 查看帮助

-h,-?,-help,--help [arg]:显示帮助。可以指定可选参数来打印有关特定项目的帮助,如果未指定参数 arg,则仅显示基本工具选项,若指定参数,arg 可能值为:

long:除了基本工具选项之外,还打印高级工具选项。

full:输出完整的选项列表,包括编码器、解码器、解复用器、复用器、过滤器等的共享和私有选项。

type=name:输出相应类型的相关参数。如:decoder=msmpeg4v2,输出有关名为msmpeg4v2编码器的详细信息。

复制代码
Decoder msmpeg4v2 [MPEG-4 part 2 Microsoft variant version 2]:
    General capabilities: horizband dr1
    Threading capabilities: none

接下来还有以下帮助选项

-version:显示查看版本(包括子模块的详细版本信息)。

-muxers:显示所有支持的封装格式(如mp4、mkv)

-demuxers:显示所有支持的解封装格式

-devices:显示支持的音视频输入/输出设备

**-decoders:**显示所有可用的解码器

**-encoders:**显示所有可用的编码器(如H.264、AAC等)

-filters:显示可用过滤器。

**-pix_fmts:**显示支持的像素格式(如yuv420p,rgb24)

-layouts:显示标准的音频通道布局(如stereo,5.1)

-sample_fmts:显示音频采样格式(如s16,flt,dbl)

更多详细命令参数见官方文档及后续部分介绍,如果希望将帮助文档保存到文件中,可以输入ffmpeg -h full > ffmpeg_h_full.log命令,将输出结果重定向到一个文件中,然后再打开该文件即可查看完整的帮助文档。

2. 命令执行常用参数

**-y:**若输出目录已存在同名同容器格式的文件,直接输出当前文件将其覆盖而不再询问。

**-n:**不要覆盖输出文件,如果已经存在同名同容器格式的文件,立即结束运行,效果与 -y 相反。

**-f:**强制设定文件格式,需使用能力集列表中的名称(缺省是根据扩展名选择的)。

**-hide_banner:**隐藏FFmpeg版本号及一些描述信息。

**-itsoffset:**用于指定输入文件的偏移时间,后接时间值,正值向后偏移,负值向前偏移,可以对齐多个输入文件的时间轴,使它们在合并或处理时保持同步。

3. 视频帧操作

(1)基本时间剪辑

-ss:设置媒体文件的起始时间,如想要从视频的2秒开始剪切处理,我们输入"-ss 2",如想要更精确的时间也可以,如"-ss 1:23.789"表示设置从1分23秒789毫秒开始。

-t:设置媒体文件的持续时间,用法同上面-ss ,如"-t 0:13.234"表示持续13秒234毫秒。

-to:设置媒体文件的截止时间,用法与前两个相同,-to和-t是互斥的,并且-t具有优先权,两者不能同时出现使用。

复制代码
ffmpeg.exe -ss 0:10 -t 0:5 -i .\zhouxingchi.mp4 -c copy out.mp4

如以上命令将mp4文件从10秒处开始截取并持续5秒,最后将该部分另存到out.mp4文件。

通常将-ss 、-t和-to放在-i之前,这些参数用于指定输入文件的开始时间(-ss)、持续时间(-t)或结束时间(-to),因此它们需要在输入文件(-i)之前进行设置,以确保正确地应用到指定的输入文件上,以防混乱。

(2)截取视频中某帧

复制代码
ffmpeg -ss 00:00:10 -i zhouxingchi.mp4 -frames:v 1 -q:v 2 out.jpg

-ss 00:00:10:跳到第 10 秒,-frames:v 1:只保存一帧,-q:v 2:图像质量(1 为最好,31 最差,建议用 2~4)。

(3)导出片段视频帧

复制代码
ffmpeg.exe -ss 13 -to 15 -i .\zhouxingchi.mp4 .\out\%03d.png

导出从视频第13秒到15秒这两秒内所有帧图片。该命令还可以增加-vf "fps=1"参数,表示每秒截一帧:

复制代码
ffmpeg.exe -ss 13 -to 20 -i .\zhouxingchi.mp4 -vf "fps=1" .\out\%03d.png

4. 录屏操作

直接使用ffmpeg内置的gdigrab对桌面进行录屏

复制代码
ffmpeg -f gdigrab -i desktop -pix_fmt yuv420p D:\out.mp4

这个命令使用FFmpeg工具来捕获Windows桌面并将其保存为一个mp4格式的视频文件。"-f gdigrab"表示使用 GDI (Graphics Device Interface) 来捕获屏幕;"-i desktop"指定要捕获的对象为desktop即桌面内容;"-pix_fmt yuv420p"指定输出视频的像素格式为 YUV 4:2:0 planar。

5. 解封装与解码

通过ffmpeg命令,可以将MP4视频转为H.264流(裸流.264文件),然后再提取成YUV数据文件(原始像素数据)。

(1)将MP4转为H.264裸流

复制代码
ffmpeg -i out.mp4 -c:v libx264 -bsf:v h264_mp4toannexb -an -f h264 out.264

-c:v libx264:使用H.264编码器(libx264)对视频重新编码。如果不想重新编码,可以用-c:v copy保留原始流。

-bsf:v h264_mp4toannexb:将MP4封装格式中的H.264转为 Annex B 格式(常见裸流格式)。

-an:去除音频流,仅保留视频。

-f h264:指定输出文件格式为H.264裸流。

(2)将H.264裸流转为YUV数据

接着H.264裸流中的编码数据需要解码后才能获得原始YUV数据。

复制代码
ffmpeg -i out.264 -pix_fmt yuv420p -vsync 0 out.yuv

-i output.264:输入文件为 H.264 裸流。

-pix_fmt yuv420p:指定输出像素格式为 YUV 4:2:0(标准格式)。

-vsync 0:禁用帧同步,确保输出的帧数与输入一致。

output.yuv:输出文件名。

(3)直接从MP4提取YUV

如果不需要中间的 H.264 裸流步骤,可以直接从 MP4 转为 YUV:

复制代码
ffmpeg -i out.mp4 -pix_fmt yuv420p -fps_mode passthrough out.yuv

6. 码流提取

(1)提取视频

通过移除音频流,可以单独提取视频使用,保留原始的视频编码。具体命令如下:

复制代码
ffmpeg -i out.mp4 -vcodec copy -an video0.mp4

(2)提取音频

利用ffmpeg命令,可轻松实现视频中的音频提取。具体命令如下:

复制代码
ffmpeg -i out.mp4 -acodec copy -vn voice.aac

如果需要将AAC音频流直接复制到MP3容器中,则需要执行如下命令:

使用ffmpeg命令将LOGO(例如logo.png)叠加到原始视频文件(例如out.mp4)上,可以通过调整overlay参数的位置来改变LOGO的放置位置。具体命令如下:

复制代码
左上角:ffmpeg -i out.mp4 -i logo.png -filter_complex overlay out1.mp4
右上角:ffmpeg -i out.mp4 -i logo.png -filter_complex overlay=W-w out2.mp4
左下角:ffmpeg -i out.mp4 -i logo.png -filter_complex overlay=0:H-h out3.mp4
右下角:ffmpeg -i out.mp4 -i logo.png -filter_complex overlay=W-w:H-h out4.mp4

以上命令中W是视频分辨率中的宽,w是logo文件图片的宽,H是视频分辨率中的高,h是logo文件图片的高。

2.2 ffplay.exe

ffplay是基于SDL与ffmpeg库实现的一个轻量级媒体播放器,可以使用它来播放原始的YUV/PCM 数据、编码后的H.264/H.265等数据,封装好的MP4/M4A等数据,还可以播放来自网络的流媒体数据。

1. 命令行格式

ffplay [选项] [输入文件路径]。它使用ffmpeg库进行解码和解码,并且可以通过命令行参数来控制播放行为,如调整音量、播放速度、画面比例等。

2. 常用基本选项

-x <宽度> 和 -y <高度>:强制设置视频显示的宽度和高度。

-fs:以全屏模式启动。

-an、-vn、-sn:分别禁用音频、视频和字幕。

-acodec、-vcodec、-scodec:分别强制使用设置的音频、视频和字幕解码器来播放。

-threads <个数>:设置线程个数,可以控制 ffplay 在解码和渲染过程中的并行度,从而提高播放性能。

-ss <开始时间>:从特定的时间点开始播放。

-t <持续时间>:设置播放的持续时间。

-vol <音量>:设置播放的初始音量。

-vf 和 -af:应用视频和音频滤镜。

-autoexit:视频播放完毕后自动退出。

-loop <循环播放次数>:指定文件循环播放次数。

-showmode [mode]:设置显示模式,mode 默认为0显示视频,为1显示音频波形,为2显示音频频谱。

3. 播放中按键控制

w:切换播放模式,比如在音频波形图、音频频谱图、视频画面之间切换。

s:步进模式,每按一次就播放下一帧图像。

right:快进 10s。

left:快退 10s。

up:快进 1min。

down:快退 1min。

space:暂停。

esc/q:退出播放。

2.3 ffprobe.exe

ffprobe是FFmpeg源码编译后生成的一个可执行程序,可以从媒体文件或网络媒体流中获得音视频及媒体容器的参数信息,用于查看和分析多媒体文件。

1. 命令行格式

ffprobe [选项] [ [-i] 输入文件路径],不加任何选项时输出如下所示:

根据ffprobe的输出,视频文件"zhouxingchi.mp4"包含了两个流:一个是视频流,另一个是音频流。

  • 视频流的信息:编解码器 av1 (libdav1d) (Main) (av01 / 0x31307661)、像素格式 yuv420p(tv, bt709)、分辨率 1920x1080、帧率 24 fps、比特率 845 kb/s。
  • 音频流的信息:编解码器 aac (LC) (mp4a / 0x6134706D)、采样率 44100 Hz、stereo(立体声)、比特率 128 kb/s。

2. 常用基本选项

-show_format:查看媒体文件的封装信息,输出内容的前半部分和不加选项时的输出一样,后半部分会得到该视频文件的封装文件信息如下所示。

-show_streams:查看媒体文件的流信息,如下所示其中一条媒体流的信息:

复制代码
[STREAM]
index=0
codec_name=av1
codec_long_name=Alliance for Open Media AV1
profile=Main
codec_type=video
codec_tag_string=av01
codec_tag=0x31307661
width=1920
height=1080
coded_width=1920
coded_height=1080
closed_captions=0
film_grain=0
has_b_frames=0
sample_aspect_ratio=1:1
display_aspect_ratio=16:9
pix_fmt=yuv420p
level=8
color_range=tv
color_space=bt709
color_transfer=bt709
color_primaries=bt709
chroma_location=unspecified
field_order=unknown
refs=1
id=0x1
r_frame_rate=24/1

show_streams

-show_packets:查看文件的所有数据包信息,一个视频文件由多个数据包组成。

-show_frames:查看媒体文件的每一帧信息,我们分析其中两个如下所示。如下是音频帧类型,然后key_frame=1表示这是IDR frame,如果key_frame=0表示这是Non-IDR frame。

-select_streams <type>:选择特定类型的流进行显示,<type>可以是v(视频)、a(音频)或s(字幕)。

-of/-print_format <format>:指定输出格式,常用的输出格式有csv、json、flat、xml等。

复制代码
ffprobe.exe -i .\out.mp4 -show_format -show_streams -of json

3 SDK使用Demo实例

3.1 SDL编译

SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。该库编译比较简单,直接下载源码使用CMake进行配置编译即可,需要注意的是要确定编译版本是32位还是64位版本,这里编译器用的VS2019,编译的是64位版本。

配置完成后,直接用VS打开生成的工程进行编译即可。

3.2 基于SDL的视频播放demo

可以直接在SDL解决方案下添加Console项目,主文件内容如下:

复制代码
  1 extern "C" {
  2 #include <libavcodec/avcodec.h>
  3 #include <libavformat/avformat.h>
  4 #include <libavutil/imgutils.h>
  5 #include <libswscale/swscale.h>
  6 }
  7 
  8 #define SDL_MAIN_HANDLED
  9 #include <SDL2/SDL.h>
 10 #include <iostream>
 11 
 12 int main(int argc, char *argv[])
 13 {
 14     if (argc < 2) {
 15         std::cerr << "请指定视频文件路径,例如:\n";
 16         std::cerr << "  " << argv[0] << " sample.mp4\n";
 17         return -1;
 18     }
 19 
 20     const char *filepath = argv[1];
 21 
 22     avformat_network_init();
 23 
 24     AVFormatContext *fmt_ctx = nullptr;
 25     if (avformat_open_input(&fmt_ctx, filepath, nullptr, nullptr) < 0) {
 26         std::cerr << "无法打开文件: " << filepath << "\n";
 27         return -1;
 28     }
 29 
 30     if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
 31         std::cerr << "无法获取视频流信息\n";
 32         return -1;
 33     }
 34 
 35     int video_stream_idx = -1;
 36     for (unsigned int i = 0; i < fmt_ctx->nb_streams; ++i) {
 37         if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
 38             video_stream_idx = i;
 39             break;
 40         }
 41     }
 42 
 43     if (video_stream_idx == -1) {
 44         std::cerr << "没有找到视频流\n";
 45         return -1;
 46     }
 47 
 48     AVCodecParameters *codecpar = fmt_ctx->streams[video_stream_idx]->codecpar;
 49     const AVCodec *decoder = avcodec_find_decoder(codecpar->codec_id);
 50     if (!decoder) {
 51         std::cerr << "找不到解码器\n";
 52         return -1;
 53     }
 54 
 55     AVCodecContext *codec_ctx = avcodec_alloc_context3(decoder);
 56     avcodec_parameters_to_context(codec_ctx, codecpar);
 57     avcodec_open2(codec_ctx, decoder, nullptr);
 58 
 59     AVFrame *frame = av_frame_alloc();
 60     AVFrame *rgb_frame = av_frame_alloc();
 61     AVPacket *pkt = av_packet_alloc();
 62 
 63     int width = codec_ctx->width;
 64     int height = codec_ctx->height;
 65     enum AVPixelFormat dst_pix_fmt = AV_PIX_FMT_YUV420P;
 66 
 67     struct SwsContext *sws_ctx = sws_getContext(
 68         width, height, codec_ctx->pix_fmt,
 69         width, height, dst_pix_fmt,
 70         SWS_BILINEAR, nullptr, nullptr, nullptr);
 71 
 72     int num_bytes = av_image_get_buffer_size(dst_pix_fmt, width, height, 1);
 73     uint8_t *buffer = (uint8_t *)av_malloc(num_bytes * sizeof(uint8_t));
 74     av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, buffer, dst_pix_fmt, width, height, 1);
 75 
 76     // 初始化 SDL
 77     SDL_Init(SDL_INIT_VIDEO);
 78     SDL_Window *window = SDL_CreateWindow("FFmpeg Player",
 79                                           SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
 80                                           width, height, SDL_WINDOW_SHOWN);
 81     SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
 82     SDL_Texture *texture = SDL_CreateTexture(renderer,
 83                                              SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, width, height);
 84 
 85     // 解码 & 渲染循环
 86     while (av_read_frame(fmt_ctx, pkt) >= 0) {
 87         if (pkt->stream_index == video_stream_idx) {
 88             if (avcodec_send_packet(codec_ctx, pkt) == 0) {
 89                 while (avcodec_receive_frame(codec_ctx, frame) == 0) {
 90                     sws_scale(sws_ctx,
 91                               frame->data, frame->linesize,
 92                               0, height,
 93                               rgb_frame->data, rgb_frame->linesize);
 94 
 95                     SDL_UpdateYUVTexture(texture, nullptr,
 96                                          rgb_frame->data[0], rgb_frame->linesize[0],
 97                                          rgb_frame->data[1], rgb_frame->linesize[1],
 98                                          rgb_frame->data[2], rgb_frame->linesize[2]);
 99 
100                     SDL_RenderClear(renderer);
101                     SDL_RenderCopy(renderer, texture, nullptr, nullptr);
102                     SDL_RenderPresent(renderer);
103                     SDL_Delay(1000 / 30); // 简单帧率控制
104                 }
105             }
106         }
107         av_packet_unref(pkt);
108 
109         SDL_Event event;
110         SDL_PollEvent(&event);
111         if (event.type == SDL_QUIT) {
112             break;
113         }
114     }
115 
116     // 清理
117     sws_freeContext(sws_ctx);
118     av_free(buffer);
119     av_frame_free(&frame);
120     av_frame_free(&rgb_frame);
121     av_packet_free(&pkt);
122     avcodec_free_context(&codec_ctx);
123     avformat_close_input(&fmt_ctx);
124 
125     SDL_DestroyTexture(texture);
126     SDL_DestroyRenderer(renderer);
127     SDL_DestroyWindow(window);
128     SDL_Quit();
129 
130     return 0;
131 }

main.cpp

注意第8行语句,如果不包含该语句编译时会提示错误:

复制代码
MSVCRT.lib(exe_main.obj) : error LNK2001: 无法解析的外部符号 _main

在网上查了下原因,因为SDL2在SDL_main.h中定义了如下代码:

复制代码
#if defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE)
#define main    SDL_main
#endif

它会把main重命名为SDL_main,然后SDL库中会试图用它自己的WinMain入口去调用你的SDL_main,从而接管程序,这在Windows GUI项目中是正常的,但现在用的是控制台项目(需要标准main函数),但是上面的语句已经将main重定向到SDL_main,所以链接时会提示"无法解析的外部符号 _main"。

头文件包含目录配置如下:

链接器配置如下:

输入库包含如下:

复制代码
SDL2d.lib;avformat.lib;avcodec.lib;avutil.lib;swscale.lib;

为了能在VS环境下直接运行调试,可以在调试选项配置中增加运行库目录到PATH环境变量,并给出要播放的文件为命令参数。

参考:

https://zhuanlan.zhihu.com/p/684158932

https://blog.csdn.net/lsb2002/article/details/136568262

相关推荐
bubiyoushang88813 小时前
CentOS安装ffmpeg并转码视频为mp4
ffmpeg·centos·音视频
云霄IT1 天前
python使用ffmpeg录制rtmp/m3u8推流视频并按ctrl+c实现优雅退出
python·ffmpeg·音视频
rjszcb2 天前
通过v4l2,采集视频,FFmpeg编码压缩封装视频(三)
ffmpeg·音视频
老谢不老2 天前
ffmpeg-7.1.1 下载安装 windows 版,MP4 转 m3u8 切片,遇到报错 Unrecognized option ‘vbsf‘的解决办法
ffmpeg
xhBruce2 天前
FFmpeg+javacpp中FFmpegFrameGrabber
ffmpeg·ffmpeg+javacpp
努力做小白2 天前
Linux驱动20 --- FFMPEG视频API
linux·驱动开发·单片机·嵌入式硬件·ffmpeg·lvgl
肥or胖4 天前
【音视频协议篇】WebRTC 快速入门
ffmpeg·音视频·webrtc
aqi004 天前
FFmpeg开发笔记(七十八)采用Kotlin+Compose的NextPlayer播放器
android·ffmpeg·音视频·直播·流媒体