0%

栽剪FFMPEG做GIF录屏工具

  • 看到网上做的一些gif图片,突然想到做一个gif录屏的工具,win,iso肯定有这些工具,linux 下只发现了peek,这个工具就是用ffmpeg去录的屏幕.

  • 其实不需要这篇文章,只要安装了ffmpeg或者使用静态编译的ffmpeg,使用参数脚本也就能实现录屏功能,可以录成各种视频格式(avi,mp4,…),或者图片格式(png,jpeg,gif…).

编译安装ffmpeg,

Linux 版本

  • 这里使用最新的ffmpeg-3.2.2做演示.
  • 这里保留gif,rawvideo,png,huffyuv,avi的相关功能.

栽剪功能说明

  • –disable-ffprobe , 不编译ffprobe
  • –disable-ffserver, 不编译ffserver
  • […]
  • –disable-encoders –enable-encoder=’gif,rawvido,png’ –disable-decoders –enable-encoder=’gif,rawvideo,huffyuv,png’, 这里设置禁止编译所有编译功能,后面只开起gif,rawvideo,png的功能.
  • –disable-muxers –enable-muxer=’gif,rawvideo,avi,image2’ –disable-demuxers –enable-demuxer=’gif,rawvideo,avi,image2’ ,这里同上,image2是生成png要用到的
  • –disable-protocols –enable-protocol=’file,data,pipe’,这三个选项是最基本要,不然不能写文件与管道的.
  • –diable-outdevs , 这里没用到任何的输出设备,全部禁用.
  • –disable-hwaccels –disable-vdpau –disable-xvmc –disable-nvenc ,禁用硬件加速,怕兼容性有问题.
  • –disable-parsers –enable-parser=’png’ –disable-bsfs ,这两个大的功能可以完全剪掉,png也是后要生成高质量GIF所使用到调色板的设置.
  • –diable-filters –enable-filter=’scale,zscale,fps,palettegen,paletteuse’, 这里的scale 过滤器是必须,palettegen,paletteuse依赖于image2,png,因为为了加强GIF的质量要用到这个调色板,关于过滤器的很多魔法功能可以网上自行搜索.
  • –disable-indevs –enable-indev=’x11grab,x11grab_xcb’ , x11grab是已经过时的,x11grab_xcb的功能与**–extra-libs=-static冲突.信赖于–enable-gpl –enable-nonfree**.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

$ tar xvf ffmpeg-3.2.2.tar.bz2
$ mkdir ffmpeg-3.2.2/build-linux && cd ffmpeg-3.2.2/build-linux

../configure --disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages --disable-logging --disable-protocols --enable-protocol='file,data,pipe' --disable-encoders --enable-encoder=gif,rawvideo,huffyuv,png --disable-decoders --enable-decoder='gif,rawvideo,huffyuv,png' --disable-outdevs --disable-filters --enable-filter='scale,zscale,fps,palettegen,paletteuse' --disable-muxers --enable-muxer='gif,rawvideo,avi,image2' --disable-demuxers --enable-demuxer='gif,rawvideo,avi,image2' --disable-hwaccels --disable-parsers --enable-parser='png' --disable-bsfs --disable-indevs --enable-indev='x11grab_xcb' --enable-x11grab --disable-shared --enable-static --extra-cflags=--static --disable-sdl2 --disable-bzlib --enable-gpl --enable-nonfree --disable-xvmc --disable-nvenc --disable-vdpau
install prefix /usr/local
source path /home/michael/Downloads/ffmpeg-3.2.2
C compiler gcc
C library glibc
ARCH x86 (generic)
big-endian no
runtime cpu detection yes
yasm yes
MMX enabled yes
MMXEXT enabled yes
3DNow! enabled yes
3DNow! extended enabled yes
SSE enabled yes
SSSE3 enabled yes
AESNI enabled yes
AVX enabled yes
XOP enabled yes
FMA3 enabled yes
FMA4 enabled yes
i686 features enabled yes
CMOV is fast yes
EBX available yes
EBP available yes
debug symbols yes
strip symbols yes
optimize for size no
optimizations yes
static yes
shared no
postprocessing support yes
new filter support yes
network support no
threading support pthreads
safe bitstream reader yes
SDL2 support no
opencl enabled no
JNI support no
texi2html enabled no
perl enabled yes
pod2man enabled yes
makeinfo enabled yes
makeinfo supports HTML yes

Enabled programs:
ffmpeg

External libraries:
iconv libxcb libxcb_shape libxcb_shm libxcb_xfixes xlib zlib

External libraries providing hardware acceleration:
vaapi

Libraries:
avcodec avdevice avfilter avformat avutil postproc swresample swscale

Enabled decoders:
gif huffyuv png rawvideo

Enabled encoders:
gif huffyuv png rawvideo

Enabled hwaccels:

Enabled parsers:
png

Enabled demuxers:
avi gif image2 rawvideo

Enabled muxers:
avi gif image2 rawvideo

Enabled protocols:
data file pipe

Enabled filters:
aformat anull atrim format fps null palettegen paletteuse scale setpts trim

Enabled bsfs:

Enabled indevs:
x11grab_xcb

Enabled outdevs:

License: nonfree and unredistributable
Creating config.mak, config.h, and doc/config.texi...


$ make

运行测试

  • 具体使用参数以ffmpeg为准.
1
2
3
$ ./ffmpeg -y -video_size 1024x768 -framerate 10  -f x11grab -i :0.0+0,0 -vf scale=1024:-1 -t 10  -pixel_format rgb24  -r 5  -vcodec gif output.gif
[...]

打包成静态库

  • 打包成静态库需要重命名ffmpeg.c 里的main 函数.

  • 需要修改ffmpeg.c,cmdutils.c如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
diff ffmpeg.c ~/ffmpeg-3.2.2/ffmpeg.c 
113d112
< int ffmpeg(int argc, char **argv);
323,325c322,323
<
< void sigterm_handler(int sig);
< void sigterm_handler(int sig)
---
> static void
> sigterm_handler(int sig)
596d593
<
4536,4545c4533
< static void my_logoutput(void* ptr, int level, const char* fmt,va_list vl){
< FILE *fp = fopen("my_log.txt","a+");
< if(fp){
< vfprintf(fp,fmt,vl);
< fflush(fp);
< fclose(fp);
< }
< }
<
< int ffmpeg(int argc, char **argv)
---
> int main(int argc, char **argv)
4552,4553c4540
<
< //register_exit(ffmpeg_cleanup);
---
> register_exit(ffmpeg_cleanup);
4580,4581c4567
< goto fail;
< // exit_program(1);
---
> exit_program(1);
4586,4591c4572
< for(int i = 0 ; i < argc;i++)
< {
< av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run %s\n", argv[i]);
< }
< goto fail;
< // exit_program(1);
---
> exit_program(1);
4597,4598c4578
< goto fail;
< // exit_program(1);
---
> exit_program(1);
4613c4593
< // exit_program(1);
---
> exit_program(1);
4621,4622c4601
< goto fail;
< // exit_program(69);
---
> exit_program(69);
4624,4635c4603
< //exit_program(received_nb_signals ? 255 : main_return_code);
< fail:
< ffmpeg_cleanup(received_nb_signals ? 255: main_return_code);
< nb_output_streams = 0;
< nb_filtergraphs = 0;
< nb_output_files = 0;
< nb_input_files = 0;
< nb_input_streams = 0;
< received_sigterm = 0;
< received_nb_signals = 0;
< transcode_init_done = 0;
< ffmpeg_exited = 0;
---
> exit_program(received_nb_signals ? 255 : main_return_code);
4638d4605
<


----------------------------------------------
diff cmdutils.c ~/ffmpeg-3.2.2/cmdutils.c
754d753
<
756,758c755
< //prepare_app_arguments(&argc, &argv);
<
<
---
> prepare_app_arguments(&argc, &argv);
851a849
>

  • 直接make 会报下面的错误无需理会
    1
    2
    3
    4
    5
    6
    7
    8

    libavutil/libavutil.a(reverse.o): warning: definition of `ff_reverse' overriding common
    libavutil/libavutil.a(eval.o): warning: common is here
    /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o: In function `_start':
    /build/glibc-qK83Be/glibc-2.19/csu/../sysdeps/x86_64/start.S:118: undefined reference to `main'
    collect2: error: ld returned 1 exit status
    /home/michael/3TB-DISK/Downloads/ffmpeg-3.2.2/Makefile:131: recipe for target 'ffmpeg_g' failed
    make: *** [ffmpeg_g] Error 1
  • 直接用脚本打包所有的点o文件.
1
$ find . -iname "*.o" | xargs ar crv libffmpeg-linux.a

MinGW 版本

  • MinGW版本与Linux 版本有一些小的区别,都是用GCC编译器,只是这里要指交叉编译器
  • 与上面Linux版相比,indev=gdigrab,添加了**–extra-libs-static –enable-cross-compile –target-os=mingw32 –arch=x64 –cross-prefix=i686-w64-ming32.static-**
  • windows ,有几个输入设备可以选,dshow,vfwcap可以用来做摄像头的输入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
../configure  --disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages --disable-logging --disable-protocols --enable-protocol='file,data,pipe' --disable-encoders --enable-encoder='gif,rawvideo,huffyuv,png' --disable-decoders --enable-decoder='gif,huffyuv,png,rawvideo' --disable-outdevs --disable-filters --enable-filter='scale,zscale,fps,palettegen,paletteuse' --disable-muxers --enable-muxer='gif,avi,image2,rawvideo' --disable-demuxers --enable-demuxer='gif,avi,image2,rawvideo' --disable-hwaccels --disable-parsers --enable-parser=png --disable-bsfs --disable-indevs --enable-indev=gdigrab --disable-shared --enable-static --extra-libs=-static --extra-cflags=--static --disable-sdl2 --disable-bzlib --disable-vdpau --disable-xvmc --disable-nvenc --enable-gpl --enable-nonfree --enable-cross-compile --target-os=mingw32 --arch=x86 --cross-prefix=i686-w64-mingw32.static-


install prefix /usr/local
source path /home/michael/3TB-DISK/Downloads/ffmpeg-3.2.2
C compiler i686-w64-mingw32.static-gcc
C library mingw64
host C compiler gcc
host C library glibc
ARCH x86 (generic)
big-endian no
runtime cpu detection yes
yasm yes
MMX enabled yes
MMXEXT enabled yes
3DNow! enabled yes
3DNow! extended enabled yes
SSE enabled yes
SSSE3 enabled yes
AESNI enabled yes
AVX enabled yes
XOP enabled yes
FMA3 enabled yes
FMA4 enabled yes
i686 features enabled yes
CMOV is fast no
EBX available yes
EBP available yes
debug symbols yes
strip symbols yes
optimize for size no
optimizations yes
static yes
shared no
postprocessing support yes
new filter support yes
network support no
threading support w32threads
safe bitstream reader yes
SDL2 support no
opencl enabled no
JNI support no
texi2html enabled no
perl enabled yes
pod2man enabled yes
makeinfo enabled yes
makeinfo supports HTML yes

Enabled programs:
ffmpeg

External libraries:
iconv schannel

External libraries providing hardware acceleration:
dxva2

Libraries:
avcodec avdevice avfilter avformat avutil postproc swresample swscale

Enabled decoders:
bmp gif rawvideo

Enabled encoders:
gif

Enabled hwaccels:

Enabled parsers:

Enabled demuxers:
gif rawvideo

Enabled muxers:
gif rawvideo

Enabled protocols:
data file pipe

Enabled filters:
aformat anull atrim format null scale setpts trim

Enabled bsfs:

Enabled indevs:
dshow gdigrab vfwcap

Enabled outdevs:

License: nonfree and unredistributable
Creating config.mak, config.h, and doc/config.texi...

$ make
[...]

## PE32 是64bit的标识
$ file ffmpeg.exe
ffmpeg.exe: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows

windows下面运行测试

  • 如果直接用下面的命令参数直接生成GIF文件会很大的色差与抖动.
    1
    ffmpeg.exe -y  -framerate 10  -f gdigrab -i desktop -video_size vga -vf scale=1024:-1   -pixel_format rgb24  -r 5 -vcodec gif output.gif

打包成静态库

  • 打包方式同Linux版相同,替换ar 为 i686-w64-mingw32.static-ar.

QT C++工程调用

  • Qt的工程文件设置如下. 至于为什么要链接这些库,请参照编译时的config.mak文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unix:!macx: LIBS += -L$$PWD/ -lffmpeg-linux -ldl -lxcb -lxcb-shm -lxcb \
-lxcb-xfixes -lxcb-render -lxcb-shape \
-lxcb -lxcb-shape -lxcb -lX11 -lm -llzma -lz -pthread

INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.

unix:!macx: PRE_TARGETDEPS += $$PWD/libffmpeg-linux.a


win32:CONFIG(release, debug|release): LIBS += -L$$PWD/ -lffmpeg-win -lgdi32 -liconv -lsecur32 -lm -llzma -lz -lpsapi -ladvapi32 -lshell32 -static
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/ -lffmpeg-win -lgdi32 -liconv -lsecur32 -lm -llzma -lz -lpsapi -ladvapi32 -lshell32 -static

INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.

win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/libffmpeg-win.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/libffmpeg-win.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/./release/ffmpeg-win.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/./debug/ffmpeg-win.lib

调用静态库函数

  • C++ 中需要导出三个函数,还要做如下的必要修改,才能被其它工程调用.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[...]

/* C++ 中需要导出三个函数 */
extern "C" {
int ffmpeg(int argc,char *argv[]) //原ffmpeg程序的入口函数
int sigterm_handler(int sig); // 终止ffmpeg程序
void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); // 设置日志打印的回调函数.
};

[...]

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
//out(stdout, QIODevice::WriteOnly),
ui(new Ui::MainWindow),
{
[...]

QList<QByteArray> tmp;
tmp << "ffmpeg"
<< "-v" << "quiet" << "-y"
// Video Size 要在-f 的前面.
<< "-video_size" << wsize.toLocal8Bit()
<< "-framerate" << "15"
#if _WIN32
<< "-f" << "gdigrab"
<< "-i" << "desktop"
<< "-offset_x" << QString("%1").arg(QString::number(mWindow->pos().x())).toLocal8Bit()
<< "-offset_y" << QString("%1").arg(QString::number(mWindow->pos().x())).toLocal8Bit()
#else
<< "-f" << "x11grab"
<< "-i" << pos.toLocal8Bit()

#endif
<< "-vcodec" << "huffyuv"
<< "-pix_fmt" << "yuv422p"
<< outputvideo;

char *argv[tmp.size()+1] = {NULL};
for(int i =0 ;i < tmp.size() ;i++)
{
argv[i] = tmp[i].data();
}
ffmpeg(tmp.size(),argv);
[...]

录制效果图


谢谢支持