logo头像

技术引领生活!

Windows下Mingw版本的FFMPEG源码编译

本文于648天之前发表,文中内容可能已经过时。

众所周知FFMPEG是非常牛逼的存在,但是在学习FFMPEG时一般都是依库的形式调用,总有种隔靴搔痒的感觉,于是爆肝了两天终于把代码加入到Qt工程中了

Mingw 版本编译 FFMPEG(动态静态库版本)

前置条件:

  1. 先跳坑在ubuntu编译FFMPEG和ffplay中的Window小节有详细介绍,这个还是比较重要的,起码有个感性的认识
  2. 一个bash解析器,这个选git就行了,程序员还能不装个这?
  3. mingw编译器一套(Qt自带的就行了)
  4. 打开git终端输入以下命令 (我是装了cywin以及另外的mingw64套件)所以要直接将PATH变量清零(只保留mingw和git命令环境),还有个要注意DOS中的c:\这里要改成/c,因为冒号 :linux中起到路径分割的作用, 而windows下是分号 ;
1
2
3
4
export PATH=/c/Qt/Qt5.7.0/5.7/mingw53_32/bin:/c/Qt/Qt5.7.0/Tools/mingw530_32/bin:/c/programes/Git/usr/bin/

cd ffmepg
./configure

移到Qt中

其实实现的有点挫(只实现了window环境下的x86_32位),为每个子模块编写一个pri文件包含起来

重要知识点:

  1. 如何使用qmake编译汇编文件asm
    参考mingw链接库版本中的下面一句话,结合QMake的非公开wiki(见文末)
    1
    yasm -f win32 -DPREFIX -I./ -I.// -Ilibavutil/ -Pconfig.asm    -o libavutil/fixed_dsp.o libavutil/fixed_dsp.asm
    可以新建一个yasm.pri内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ASM_INCLUDE +=\
$$PWD/config.asm

#ASM_SOURCE += xxxxx.asm

ASM.name = yasm ${QMAKE_FILE_IN}
#所用到的汇编文件
ASM.input = ASM_SOURCE
ASM.variable_out = OBJECTS
ASM.commands = yasm -f win32 -DPREFIX -I$$PWD -I$$PWD/.. -I$$PWD/../.. -P$${ASM_INCLUDE} ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}
ASM.output = ${QMAKE_FILE_IN_BASE}$${first(QMAKE_EXT_OBJ)}

QMAKE_EXTRA_COMPILERS += ASM

  1. 编译步骤
    依次为libavutil, libswresample, libavcodec, libavformat, libswscale, libpostproc, libavdevice, libavfilter, 其中第一个必须编译libavutil模块,这个是个工具库,所有其他的部分可能会依赖它, 然后照猫画虎编译其他模块大致按照上面顺序, 在遇到依赖的就延后处理就是了

思路

  1. 在克隆好的ffmpeg 中先执行 .configure命令 得到一些必要的配置文件(config.h, config_components.h等文件)
  2. 新建一个ffmpeg.pri
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
INCLUDEPATH += $$PWD
INCLUDEPATH += $$PWD/compat/atomics/pthread

HEADERS += $$PWD/config.h\
$$PWD/config_components.h\
$$PWD/compat/w32pthreads.h

SOURCES += $$PWD/compat/atomics/pthread/stdatomic.c

# 引入编译器
include($$PWD/yasm.pri)

# 引入各个模块
include($$PWD/libavutil/libavutil.pri)
include($$PWD/libswresample/libswresample.pri)
include($$PWD/libavcodec/libavcodec.pri)
include($$PWD/libavformat/libavformat.pri)
include($$PWD/libswscale/libswscale.pri)
include($$PWD/libavdevice/libavdevice.pri)
include($$PWD/libavfilter/libavfilter.pri)
include($$PWD/libpostproc/libpostproc.pri)

#下面这些是为了利用configure的结果
DEFINES += HAVE_AV_CONFIG_H

#这句可以避免一些编译错误
DEFINES += _WIN32_WINNT=0x0600 _POSIX_C_SOURCE=200112 _XOPEN_SOURCE=600 ZLIB_CONST

# 这一句可以避免文件同名冲突比如libavutil有两个cpu.c文件,编译时会遇到重定义错误
CONFIG += object_parallel_to_source
#CONFIG += object_with_source

# 下面这句不加, 在debug模式下会出现'asm' operand has impossible constraints的错误
QMAKE_CFLAGS= -fomit-frame-pointer

# 其他抠出来的可以不用
#QMAKE_CXXFLAGS = -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1 -D__printf__=__gnu_printf__ -D_WIN32_WINNT=0x0600 -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DZLIB_CONST -D__STDC_CONSTANT_MACROS -std=c++11
#QMAKE_CFLAGS= -std=c11 -fomit-frame-pointer -g -Wdeclaration-after-statement\
# -Wall -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings\
# -Wtype-limits -Wundef -Wmissing-prototypes -Wstrict-prototypes -Wempty-body\
# -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign\
# -Wno-char-subscripts -O3 -fno-math-errno -fno-signed-zeros -fno-tree-vectorize\
# -Werror=format-security -Werror=implicit-function-declaration -Werror=missing-prototypes\
# -Werror=return-type -Werror=vla -Wformat -fdiagnostics-color=auto -Wno-maybe-uninitialized

LIBS += -liconv -lm -latomic -lmfuuid -lz -lbcrypt -lsecur32
win32:{
LIBS += -lole32 -lws2_32 -lgdi32 -lshell32 -lstrmiids -luser32 -lvfw32 -loleaut32 -lpsapi -lshlwapi -luuid
}

  1. 参考每个模块文件夹下的makefile文件编写pri文件
    写python脚本处理一下内容大致为以下步骤
  • makefile 文件中的OBJS中的各个.o替换成同名的.c
  • 遇到形如 OBJS-$(CONFIG_CUDA) 之类的查找config.h中CONFIG_CUDA的定义如果为1 则替换.o 为.c或者.asm,如果为0则注释掉
  • 遇到重名的.c 只保留一个(汇编只会警告,c文件重复会报错….)
  • 到每个模块目录如果存在架构文件夹(如x86)则找到 makefile 参照建立对应的.pri文件
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
NAME = avutil
DESC = FFmpeg utility library

HEADERS = adler32.h \
aes.h \
aes_ctr.h \
attributes.h \
audio_fifo.h \
avassert.h \
avstring.h \
avutil.h \
base64.h \
blowfish.h \
bprint.h \
bswap.h \
buffer.h \
cast5.h \
camellia.h \
channel_layout.h \
common.h \
cpu.h \
crc.h \
csp.h \
des.h \
detection_bbox.h \
dict.h \
display.h \
dovi_meta.h \
downmix_info.h \
encryption_info.h \
error.h \
eval.h \
fifo.h \
file.h \
frame.h \
hash.h \
hdr_dynamic_metadata.h \
hdr_dynamic_vivid_metadata.h \
hmac.h \
hwcontext.h \
hwcontext_cuda.h \
hwcontext_d3d11va.h \
hwcontext_drm.h \
hwcontext_dxva2.h \
hwcontext_qsv.h \
hwcontext_mediacodec.h \
hwcontext_opencl.h \
hwcontext_vaapi.h \
hwcontext_videotoolbox.h \
hwcontext_vdpau.h \
hwcontext_vulkan.h \
imgutils.h \
intfloat.h \
intreadwrite.h \
lfg.h \
log.h \
lzo.h \
macros.h \
mathematics.h \
mastering_display_metadata.h \
md5.h \
mem.h \
motion_vector.h \
murmur3.h \
opt.h \
parseutils.h \
pixdesc.h \
pixelutils.h \
pixfmt.h \
random_seed.h \
rc4.h \
rational.h \
replaygain.h \
ripemd.h \
samplefmt.h \
sha.h \
sha512.h \
spherical.h \
stereo3d.h \
threadmessage.h \
time.h \
timecode.h \
timestamp.h \
tree.h \
twofish.h \
uuid.h \
version.h \
video_enc_params.h \
xtea.h \
tea.h \
tx.h \
film_grain_params.h \

ARCH_HEADERS = bswap.h \
intmath.h \
intreadwrite.h \
timer.h \

BUILT_HEADERS = avconfig.h \
ffversion.h

OBJS = adler32.o \
aes.o \
aes_ctr.o \
audio_fifo.o \
avstring.o \
avsscanf.o \
base64.o \
blowfish.o \
bprint.o \
buffer.o \
cast5.o \
camellia.o \
channel_layout.o \
color_utils.o \
cpu.o \
crc.o \
csp.o \
des.o \
detection_bbox.o \
dict.o \
display.o \
dovi_meta.o \
downmix_info.o \
encryption_info.o \
error.o \
eval.o \
fifo.o \
file.o \
file_open.o \
float_dsp.o \
fixed_dsp.o \
frame.o \
hash.o \
hdr_dynamic_metadata.o \
hdr_dynamic_vivid_metadata.o \
hmac.o \
hwcontext.o \
imgutils.o \
integer.o \
intmath.o \
lfg.o \
lls.o \
log.o \
log2_tab.o \
lzo.o \
mathematics.o \
mastering_display_metadata.o \
md5.o \
mem.o \
murmur3.o \
opt.o \
parseutils.o \
pixdesc.o \
pixelutils.o \
random_seed.o \
rational.o \
reverse.o \
rc4.o \
ripemd.o \
samplefmt.o \
sha.o \
sha512.o \
slicethread.o \
spherical.o \
stereo3d.o \
threadmessage.o \
time.o \
timecode.o \
tree.o \
twofish.o \
utils.o \
xga_font_data.o \
xtea.o \
tea.o \
tx.o \
tx_float.o \
tx_double.o \
tx_int32.o \
uuid.o \
version.o \
video_enc_params.o \
film_grain_params.o \


OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o
OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o
OBJS-$(CONFIG_MACOS_KPERF) += macos_kperf.o
OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o
OBJS-$(CONFIG_OPENCL) += hwcontext_opencl.o
OBJS-$(CONFIG_QSV) += hwcontext_qsv.o
OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o
OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o
OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o
OBJS-$(CONFIG_VULKAN) += hwcontext_vulkan.o

OBJS += $(COMPAT_OBJS:%=../compat/%)

# Windows resource file
SLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o

SKIPHEADERS += objc.h
SKIPHEADERS-$(HAVE_CUDA_H) += hwcontext_cuda.h
SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h \
cuda_check.h
SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h
SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h
SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h
SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h
SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.h
SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h
SKIPHEADERS-$(CONFIG_VULKAN) += hwcontext_vulkan.h vulkan.h \
vulkan_functions.h \
vulkan_loader.h

TESTPROGS = adler32 \
aes \
aes_ctr \
audio_fifo \
avstring \
base64 \
blowfish \
bprint \
cast5 \
camellia \
channel_layout \
color_utils \
cpu \
crc \
des \
dict \
display \
encryption_info \
error \
eval \
file \
fifo \
hash \
hmac \
hwdevice \
integer \
imgutils \
lfg \
lls \
log \
md5 \
murmur3 \
opt \
pca \
parseutils \
pixdesc \
pixelutils \
pixfmt_best \
random_seed \
rational \
ripemd \
sha \
sha512 \
softfloat \
tree \
twofish \
utf8 \
uuid \
xtea \
tea \

TESTPROGS-$(HAVE_THREADS) += cpu_init
TESTPROGS-$(HAVE_LZO1X_999_COMPRESS) += lzo

TOOLS = crypto_bench ffhash ffeval ffescape

tools/crypto_bench$(EXESUF): ELIBS += $(if $(VERSUS),$(subst +, -l,+$(VERSUS)),)
tools/crypto_bench.o: CFLAGS += -DUSE_EXT_LIBS=0$(if $(VERSUS),$(subst +,+USE_,+$(VERSUS)),)

$(SUBDIR)tests/lzo$(EXESUF): ELIBS = -llzo2

如第一个libavutil.pri文件如下

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
include($$PWD/x86/x86.pri)

HEADERS+=\
$$PWD/adler32.h\
$$PWD/aes.h\
$$PWD/aes_ctr.h\
$$PWD/attributes.h\
$$PWD/audio_fifo.h\
$$PWD/avassert.h\
$$PWD/avstring.h\
$$PWD/avutil.h\
$$PWD/base64.h\
$$PWD/blowfish.h\
$$PWD/bprint.h\
$$PWD/bswap.h\
$$PWD/buffer.h\
$$PWD/cast5.h\
$$PWD/camellia.h\
$$PWD/channel_layout.h\
$$PWD/common.h\
$$PWD/cpu.h\
$$PWD/crc.h\
$$PWD/csp.h\
$$PWD/des.h\
$$PWD/detection_bbox.h\
$$PWD/dict.h\
$$PWD/display.h\
$$PWD/dovi_meta.h\
$$PWD/downmix_info.h\
$$PWD/encryption_info.h\
$$PWD/error.h\
$$PWD/eval.h\
$$PWD/fifo.h\
$$PWD/file.h\
$$PWD/frame.h\
$$PWD/hash.h\
$$PWD/hdr_dynamic_metadata.h\
$$PWD/hdr_dynamic_vivid_metadata.h\
$$PWD/hmac.h\
$$PWD/hwcontext.h

SOURCES+=\
$$PWD/adler32.c\
$$PWD/aes.c\
$$PWD/aes_ctr.c\
$$PWD/audio_fifo.c\
$$PWD/avstring.c\
$$PWD/avsscanf.c\
$$PWD/base64.c\
$$PWD/blowfish.c\
$$PWD/bprint.c\
$$PWD/buffer.c\
$$PWD/cast5.c\
$$PWD/camellia.c\
$$PWD/channel_layout.c\
$$PWD/color_utils.c\
$$PWD/cpu.c\
$$PWD/crc.c\
$$PWD/csp.c\
$$PWD/des.c\
$$PWD/detection_bbox.c\
$$PWD/dict.c\
$$PWD/display.c\
$$PWD/dovi_meta.c\
$$PWD/downmix_info.c\
$$PWD/encryption_info.c\
$$PWD/error.c\
$$PWD/eval.c\
$$PWD/fifo.c\
$$PWD/file.c\
$$PWD/file_open.c\
$$PWD/float_dsp.c\
$$PWD/fixed_dsp.c\
$$PWD/frame.c\
$$PWD/hash.c\
$$PWD/hdr_dynamic_metadata.c\
$$PWD/hdr_dynamic_vivid_metadata.c\
$$PWD/hmac.c\
$$PWD/hwcontext_dxva2.c\
$$PWD/hwcontext.c\
$$PWD/integer.c\
$$PWD/intmath.c\
$$PWD/lfg.c\
$$PWD/lls.c\
$$PWD/log.c\
$$PWD/log2_tab.c\
$$PWD/lzo.c\
$$PWD/mathematics.c\
$$PWD/mastering_display_metadata.c\
$$PWD/md5.c\
$$PWD/mem.c\
$$PWD/murmur3.c\
$$PWD/opt.c\
$$PWD/parseutils.c\
$$PWD/pixdesc.c\
$$PWD/pixelutils.c\
$$PWD/random_seed.c\
$$PWD/rational.c\
$$PWD/reverse.c\
$$PWD/rc4.c\
$$PWD/ripemd.c\
$$PWD/samplefmt.c\
$$PWD/sha.c\
$$PWD/sha512.c\
$$PWD/spherical.c\
$$PWD/stereo3d.c\
$$PWD/threadmessage.c\
$$PWD/time.c\
$$PWD/timecode.c\
$$PWD/tree.c\
$$PWD/twofish.c\
$$PWD/utils.c\
$$PWD/xga_font_data.c\
$$PWD/xtea.c\
$$PWD/tea.c\
$$PWD/uuid.c\
$$PWD/version.c\
$$PWD/video_enc_params.c\
$$PWD/film_grain_params.c\
$$PWD/tx.c\
$$PWD/tx_float.c\
$$PWD/tx_double.c\
$$PWD/tx_int32.c\
$$PWD/slicethread.c\
$$PWD/imgutils.c\

对应的x86.pri

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

SOURCES +=\
$$PWD/cpu.c\
$$PWD/fixed_dsp_init.c\
$$PWD/float_dsp_init.c\
$$PWD/imgutils_init.c\
$$PWD/lls_init.c\
$$PWD/tx_float_init.c\
$$PWD/pixelutils_init.c

ASM_SOURCE += \
$$PWD/cpuid.asm\
$$PWD/fixed_dsp.asm\
$$PWD/float_dsp.asm\
$$PWD/imgutils.asm\
$$PWD/lls.asm\
$$PWD/tx_float.asm\
$$PWD/pixelutils.asm\
$$PWD/x86util.asm\
$$PWD/x86inc.asm

编译 SDL(更新)

SDL官网下载代码
依然使用以下命令

1
./configure

新建sdl.pri内容如下(参考sdl的makefile)

编译过程会报错comdlg找不到LPUNKNOWN错误
解决方案:
根据错误提示定位到文件hid.c 在文件开头添加

1
#include <unknwnbase.h>

问题解决

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
CONFIG += -Wl,--no-undefined -Wc,-static-libgcc
QMAKE_CFLAGS= -DUSING_GENERATED_CONFIG_H -I./include -idirafter ./src/video/khronos -mmmx -m3dnow -msse -msse2 -msse3 -Wall -fno-strict-aliasing -Wdeclaration-after-statement -Werror=declaration-after-statement -mpreferred-stack-boundary=2

INCLUDEPATH += $$PWD/include
INCLUDEPATH += $$PWD/src/video/khronos

HEADERS += \
# $$PWD/include/SDL.h \
# $$PWD/include/SDL_assert.h \
# $$PWD/include/SDL_atomic.h \
# $$PWD/include/SDL_audio.h \
# $$PWD/include/SDL_bits.h \
# $$PWD/include/SDL_blendmode.h \
# $$PWD/include/SDL_clipboard.h \
# $$PWD/include/SDL_cpuinfo.h \
# $$PWD/include/SDL_egl.h \
# $$PWD/include/SDL_endian.h \
# $$PWD/include/SDL_error.h \
# $$PWD/include/SDL_events.h \
# $$PWD/include/SDL_filesystem.h \
# $$PWD/include/SDL_gamecontroller.h \
# $$PWD/include/SDL_gesture.h \
# $$PWD/include/SDL_haptic.h \
# $$PWD/include/SDL_hidapi.h \
# $$PWD/include/SDL_hints.h \
# $$PWD/include/SDL_joystick.h \
# $$PWD/include/SDL_keyboard.h \
# $$PWD/include/SDL_keycode.h \
# $$PWD/include/SDL_loadso.h \
# $$PWD/include/SDL_locale.h \
# $$PWD/include/SDL_log.h \
# $$PWD/include/SDL_main.h \
# $$PWD/include/SDL_messagebox.h \
# $$PWD/include/SDL_metal.h \
# $$PWD/include/SDL_misc.h \
# $$PWD/include/SDL_mouse.h \
# $$PWD/include/SDL_mutex.h \
# $$PWD/include/SDL_name.h \
# $$PWD/include/SDL_opengl.h \
# $$PWD/include/SDL_opengl_glext.h \
# $$PWD/include/SDL_opengles.h \
# $$PWD/include/SDL_opengles2_gl2ext.h \
# $$PWD/include/SDL_opengles2_gl2.h \
# $$PWD/include/SDL_opengles2_gl2platform.h \
# $$PWD/include/SDL_opengles2.h \
# $$PWD/include/SDL_opengles2_khrplatform.h \
# $$PWD/include/SDL_pixels.h \
# $$PWD/include/SDL_platform.h \
# $$PWD/include/SDL_power.h \
# $$PWD/include/SDL_quit.h \
# $$PWD/include/SDL_rect.h \
# $$PWD/include/SDL_render.h \
# $$PWD/include/SDL_rwops.h \
# $$PWD/include/SDL_scancode.h \
# $$PWD/include/SDL_sensor.h \
# $$PWD/include/SDL_shape.h \
# $$PWD/include/SDL_stdinc.h \
# $$PWD/include/SDL_surface.h \
# $$PWD/include/SDL_system.h \
# $$PWD/include/SDL_syswm.h \
# $$PWD/include/SDL_thread.h \
# $$PWD/include/SDL_timer.h \
# $$PWD/include/SDL_touch.h \
# $$PWD/include/SDL_types.h \
# $$PWD/include/SDL_version.h \
# $$PWD/include/SDL_video.h \
# $$PWD/include/SDL_vulkan.h \
# $$PWD/include/begin_code.h \
# $$PWD/include/close_code.h

SOURCES +=\
$$PWD/src/SDL.c\
$$PWD/src/SDL_assert.c\
$$PWD/src/SDL_dataqueue.c\
$$PWD/src/SDL_error.c\
$$PWD/src/SDL_hints.c\
$$PWD/src/SDL_list.c\
$$PWD/src/SDL_log.c\
$$PWD/src/atomic/SDL_atomic.c\
$$PWD/src/atomic/SDL_spinlock.c\
$$PWD/src/audio/SDL_audio.c\
$$PWD/src/audio/SDL_audiocvt.c\
$$PWD/src/audio/SDL_audiodev.c\
$$PWD/src/audio/SDL_audiotypecvt.c\
$$PWD/src/audio/SDL_mixer.c\
$$PWD/src/audio/SDL_wave.c\
$$PWD/src/cpuinfo/SDL_cpuinfo.c\
$$PWD/src/dynapi/SDL_dynapi.c\
$$PWD/src/events/SDL_clipboardevents.c\
$$PWD/src/events/SDL_displayevents.c\
$$PWD/src/events/SDL_dropevents.c\
$$PWD/src/events/SDL_events.c\
$$PWD/src/events/SDL_gesture.c\
$$PWD/src/events/SDL_keyboard.c\
$$PWD/src/events/SDL_mouse.c\
$$PWD/src/events/SDL_quit.c\
$$PWD/src/events/SDL_touch.c\
$$PWD/src/events/SDL_windowevents.c\
$$PWD/src/events/imKStoUCS.c\
$$PWD/src/file/SDL_rwops.c\
$$PWD/src/haptic/SDL_haptic.c\
$$PWD/src/hidapi/SDL_hidapi.c\
$$PWD/src/joystick/SDL_gamecontroller.c\
$$PWD/src/joystick/SDL_joystick.c\
$$PWD/src/libm/e_atan2.c\
$$PWD/src/libm/e_exp.c\
$$PWD/src/libm/e_fmod.c\
$$PWD/src/libm/e_log.c\
$$PWD/src/libm/e_log10.c\
$$PWD/src/libm/e_pow.c\
$$PWD/src/libm/e_rem_pio2.c\
$$PWD/src/libm/e_sqrt.c\
$$PWD/src/libm/k_cos.c\
$$PWD/src/libm/k_rem_pio2.c\
$$PWD/src/libm/k_sin.c\
$$PWD/src/libm/k_tan.c\
$$PWD/src/libm/s_atan.c\
$$PWD/src/libm/s_copysign.c\
$$PWD/src/libm/s_cos.c\
$$PWD/src/libm/s_fabs.c\
$$PWD/src/libm/s_floor.c\
$$PWD/src/libm/s_scalbn.c\
$$PWD/src/libm/s_sin.c\
$$PWD/src/libm/s_tan.c\
$$PWD/src/misc/SDL_url.c\
$$PWD/src/power/SDL_power.c\
$$PWD/src/render/SDL_d3dmath.c\
$$PWD/src/render/SDL_render.c\
$$PWD/src/render/SDL_yuv_sw.c\
$$PWD/src/render/direct3d/SDL_render_d3d.c\
$$PWD/src/render/direct3d/SDL_shaders_d3d.c\
$$PWD/src/render/direct3d11/SDL_render_d3d11.c\
$$PWD/src/render/direct3d11/SDL_shaders_d3d11.c\
$$PWD/src/render/opengl/SDL_render_gl.c\
$$PWD/src/render/opengl/SDL_shaders_gl.c\
$$PWD/src/render/opengles/SDL_render_gles.c\
$$PWD/src/render/opengles2/SDL_render_gles2.c\
$$PWD/src/render/opengles2/SDL_shaders_gles2.c\
$$PWD/src/render/psp/SDL_render_psp.c\
$$PWD/src/render/software/SDL_blendfillrect.c\
$$PWD/src/render/software/SDL_blendline.c\
$$PWD/src/render/software/SDL_blendpoint.c\
$$PWD/src/render/software/SDL_drawline.c\
$$PWD/src/render/software/SDL_drawpoint.c\
$$PWD/src/render/software/SDL_render_sw.c\
$$PWD/src/render/software/SDL_rotate.c\
$$PWD/src/render/software/SDL_triangle.c\
$$PWD/src/render/vitagxm/SDL_render_vita_gxm.c\
$$PWD/src/render/vitagxm/SDL_render_vita_gxm_memory.c\
$$PWD/src/render/vitagxm/SDL_render_vita_gxm_tools.c\
$$PWD/src/sensor/SDL_sensor.c\
$$PWD/src/stdlib/SDL_crc32.c\
$$PWD/src/stdlib/SDL_getenv.c\
$$PWD/src/stdlib/SDL_iconv.c\
$$PWD/src/stdlib/SDL_malloc.c\
$$PWD/src/stdlib/SDL_qsort.c\
$$PWD/src/stdlib/SDL_stdlib.c\
$$PWD/src/stdlib/SDL_string.c\
$$PWD/src/stdlib/SDL_strtokr.c\
$$PWD/src/thread/SDL_thread.c\
$$PWD/src/timer/SDL_timer.c\
$$PWD/src/video/SDL_RLEaccel.c\
$$PWD/src/video/SDL_blit.c\
$$PWD/src/video/SDL_blit_0.c\
$$PWD/src/video/SDL_blit_1.c\
$$PWD/src/video/SDL_blit_A.c\
$$PWD/src/video/SDL_blit_N.c\
$$PWD/src/video/SDL_blit_auto.c\
$$PWD/src/video/SDL_blit_copy.c\
$$PWD/src/video/SDL_blit_slow.c\
$$PWD/src/video/SDL_bmp.c\
$$PWD/src/video/SDL_clipboard.c\
$$PWD/src/video/SDL_egl.c\
$$PWD/src/video/SDL_fillrect.c\
$$PWD/src/video/SDL_pixels.c\
$$PWD/src/video/SDL_rect.c\
$$PWD/src/video/SDL_shape.c\
$$PWD/src/video/SDL_stretch.c\
$$PWD/src/video/SDL_surface.c\
$$PWD/src/video/SDL_video.c\
$$PWD/src/video/SDL_vulkan_utils.c\
$$PWD/src/video/SDL_yuv.c\
$$PWD/src/video/yuv2rgb/yuv_rgb.c\
$$PWD/src/locale/SDL_locale.c\
$$PWD/src/video/dummy/SDL_nullevents.c\
$$PWD/src/video/dummy/SDL_nullframebuffer.c\
$$PWD/src/video/dummy/SDL_nullvideo.c\
$$PWD/src/audio/disk/SDL_diskaudio.c\
$$PWD/src/audio/dummy/SDL_dummyaudio.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_gamecube.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_luna.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_ps4.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_ps5.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_rumble.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_stadia.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_steam.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_switch.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_xbox360.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_xbox360w.c\
$$PWD/src/joystick/hidapi/SDL_hidapi_xboxone.c\
$$PWD/src/joystick/hidapi/SDL_hidapijoystick.c\
$$PWD/src/core/windows/SDL_hid.c\
$$PWD/src/core/windows/SDL_windows.c\
$$PWD/src/core/windows/SDL_xinput.c\
$$PWD/src/misc/windows/SDL_sysurl.c\
$$PWD/src/locale/windows/SDL_syslocale.c\
$$PWD/src/video/windows/SDL_windowsclipboard.c\
$$PWD/src/video/windows/SDL_windowsevents.c\
$$PWD/src/video/windows/SDL_windowsframebuffer.c\
$$PWD/src/video/windows/SDL_windowskeyboard.c\
$$PWD/src/video/windows/SDL_windowsmessagebox.c\
$$PWD/src/video/windows/SDL_windowsmodes.c\
$$PWD/src/video/windows/SDL_windowsmouse.c\
$$PWD/src/video/windows/SDL_windowsopengl.c\
$$PWD/src/video/windows/SDL_windowsopengles.c\
$$PWD/src/video/windows/SDL_windowsshape.c\
$$PWD/src/video/windows/SDL_windowsvideo.c\
$$PWD/src/video/windows/SDL_windowsvulkan.c\
$$PWD/src/video/windows/SDL_windowswindow.c\
$$PWD/src/audio/winmm/SDL_winmm.c\
$$PWD/src/audio/directsound/SDL_directsound.c\
$$PWD/src/audio/wasapi/SDL_wasapi.c\
$$PWD/src/audio/wasapi/SDL_wasapi_win32.c\
$$PWD/src/joystick/windows/SDL_dinputjoystick.c\
$$PWD/src/joystick/windows/SDL_rawinputjoystick.c\
$$PWD/src/joystick/windows/SDL_windows_gaming_input.c\
$$PWD/src/joystick/windows/SDL_windowsjoystick.c\
$$PWD/src/joystick/windows/SDL_xinputjoystick.c\
$$PWD/src/haptic/windows/SDL_dinputhaptic.c\
$$PWD/src/haptic/windows/SDL_windowshaptic.c\
$$PWD/src/haptic/windows/SDL_xinputhaptic.c\
$$PWD/src/sensor/windows/SDL_windowssensor.c\
$$PWD/src/power/windows/SDL_syspower.c\
$$PWD/src/filesystem/windows/SDL_sysfilesystem.c\
$$PWD/src/thread/windows/SDL_syscond_cv.c\
$$PWD/src/thread/windows/SDL_sysmutex.c\
$$PWD/src/thread/windows/SDL_syssem.c\
$$PWD/src/thread/windows/SDL_systhread.c\
$$PWD/src/thread/windows/SDL_systls.c\
$$PWD/src/thread/generic/SDL_syscond.c\
$$PWD/src/timer/windows/SDL_systimer.c\
$$PWD/src/loadso/windows/SDL_sysloadso.c\
$$PWD/src/joystick/virtual/SDL_virtualjoystick.c\
#$$PWD/src/main/windows/SDL_windows_main.c

LIBS +=-lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid

测试

新建一个工程 将ffmpeg文件夹拷贝过去

1
2
3
4
5
6
7
8
TEMPLATE = app

include($$PWD/ffmpeg/ffmpeg.pri)

SOURCES +=\
$$PWD/main.cpp\

DESTDIR = $$PWD/../bin

工程1

mian.cpp文件如下

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include <stdio.h>

//如果是.cpp文件必须加上extern "C"
extern "C"
{
#include "libavcodec/avcodec.h"
}

//缓冲区大小(缓存5帧数据)
#define AUDIO_INBUF_SIZE 40960
/*
name depth
u8 8
s16 16
s32 32
flt 32
dbl 64
u8p 8
s16p 16
s32p 32
fltp 32
dblp 64
s64 64
s64p 64
//此代码解码的音频文件格式如下:
//AAC文件(一帧1024字节),双声道(2),FLTP(32位,4字节)
//AAC文件 frame_size 和 nb_samples 大小均为1024
//一帧音频所占字节大小
//1024*2*4=8192字节
*/
#define AUDIO_REFILL_THRESH 8192

#define INPUT_FILE_NAME "WavinFlag.aac"
#define OUTPUT_FILE_NAME "lh_online.pcm"


static int get_format_from_sample_fmt(const char** fmt,
enum AVSampleFormat sample_fmt)
{
int i;
struct sample_fmt_entry {
enum AVSampleFormat sample_fmt; const char* fmt_be, * fmt_le;
} sample_fmt_entries[] = {
{ AV_SAMPLE_FMT_U8, "u8", "u8" },
{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },
{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },
{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
};
*fmt = NULL;

for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
struct sample_fmt_entry* entry = &sample_fmt_entries[i];
if (sample_fmt == entry->sample_fmt) {
*fmt = AV_NE(entry->fmt_be, entry->fmt_le);
return 0;
}
}

av_log(NULL, AV_LOG_ERROR, "sample format %s is not supported as output format\n", av_get_sample_fmt_name(sample_fmt));
return -1;
}

static void decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt,
FILE* ofile)
{
int i, ch;
int ret, data_size;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "发送数据包到解码器出错。\n");
exit(1);
}

while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error sending a packet for decoding.\n");
exit(1);
}

printf("frame_number: %d \n", dec_ctx->frame_number);
//获取每个采样点当中每个声道的大小
data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
if (data_size < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to calculate data size.\n");
exit(1);
}
//遍历采样点
for (i = 0; i < frame->nb_samples; i++) {
//遍历声道
for (ch = 0; ch < dec_ctx->channels; ch++) {
fwrite(frame->data[ch] + data_size * i, 1, data_size, ofile);
}
}
}
}

int main(int argc, char* argv[])
{
const AVCodec* codec;
AVCodecParserContext* parser;
AVCodecContext* c = NULL;
FILE* ifile, * ofile;
AVFrame* frame;
AVPacket* pkt;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t* data;
size_t data_size;
int ret,len;
enum AVSampleFormat sfmt;
const char* fmt;

//初始化inbuf数字默认值
memset(inbuf + AUDIO_INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);

//获取解码器(此处需要读取的文件是AAC,故)
codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
if (!codec) {
av_log(NULL, AV_LOG_ERROR, "Codec not found.\n");
exit(1);
}

//注册解析器
parser = av_parser_init(codec->id);
if (!parser) {
av_log(NULL, AV_LOG_ERROR, "parser not found.\n");
exit(1);
}

//分配解析器上下文
c = avcodec_alloc_context3(codec);
if (!c) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate video codec context.\n");
exit(1);
}

//打开解码器
if (avcodec_open2(c, codec, NULL) < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open codec.\n");
exit(1);
}


//分配AVPacket
pkt = av_packet_alloc();
if (!pkt) {
exit(1);
}

//分配AVFrame
frame = av_frame_alloc();
if (!frame) {
exit(1);
}

//打开输入文件
ifile = fopen(INPUT_FILE_NAME, "rb");
if (!ifile) {
av_log(NULL, AV_LOG_ERROR, "Could not open \s.\n", INPUT_FILE_NAME);
exit(1);
}
//打开输入文件
ofile = fopen(OUTPUT_FILE_NAME, "wb+");
if (!ofile) {
av_log(NULL, AV_LOG_ERROR, "Could not open \s.\n", OUTPUT_FILE_NAME);
exit(1);
}

//从输入流 ifile 读取数据到 inbuf 所指向的数组中
data = inbuf;
data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, ifile);

while (data_size > 0) {
//使用注册的解析器 parser 把数据分割成帧
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
data, data_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0) {
fprintf(stderr, "Error while parsing\n");
exit(1);
}
//根据使用情况重置数据位置
data += ret;
data_size -= ret;
//送往解码
if (pkt->size)
decode(c, frame, pkt, ofile);

//判断缓存区剩余数据是否小于一帧音频大小
//小于的话从文件继续读取,之后在送往解码
if (data_size < AUDIO_REFILL_THRESH) {
memmove(inbuf, data, data_size);
data = inbuf;
len = fread(data + data_size, 1,
AUDIO_INBUF_SIZE - data_size, ifile);
if (len > 0)
data_size += len;
}
}

//flush 解码器
decode(c, frame, NULL, ofile);
//此时就已经解码完了,我们稍后使用ffplay播放下音频
//解码出来的pcm数据是没有这些基础数据的,我们需要从元数据获取
//打印下基本信息
//声道数
printf("channels: %d \n", c->channels);
//采样率
printf("sample_rate: %d \n", c->sample_rate);
//一帧音频所占字节代销
printf("buffer: %d \n", av_samples_get_buffer_size(NULL, c->channels, c->frame_size, c->sample_fmt, 1));
//采样格式
sfmt = c->sample_fmt;
printf("sample_fmt: %s \n", av_get_sample_fmt_name(sfmt));
//如果为planar,转换为packed格式
if (av_sample_fmt_is_planar(sfmt)) {
const char* packed = av_get_sample_fmt_name(sfmt);
sfmt = av_get_packed_sample_fmt(sfmt);
}
if (get_format_from_sample_fmt(&fmt, sfmt) < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not get forma \s.\n", av_get_sample_fmt_name(sfmt));
exit(1);
}

//打印播放命令
printf("Play the output audio file with the command:\n"
"ffplay -f %s -ac %d -ar %d %s\n",
fmt, c->channels, c->sample_rate,OUTPUT_FILE_NAME);

//资源释放
fclose(ifile);
fclose(ofile);

av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);

return 0;
}

工程2(ffmpeg.exe)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
TEMPLATE = app

include($$PWD/sdl/sdl.pri)
include($$PWD/ffmpeg/ffmpeg.pri)


TARGET = ffmpeg

HEADERS += \
$$PWD/ffmpeg/fftools/cmdutils.h \
$$PWD/ffmpeg/fftools/ffmpeg.h \
$$PWD/ffmpeg/fftools/fopen_utf8.h \
$$PWD/ffmpeg/fftools/opt_common.h

SOURCES += \
$$PWD/ffmpeg/fftools/cmdutils.c \
$$PWD/ffmpeg/fftools/ffmpeg.c \
$$PWD/ffmpeg/fftools/ffmpeg_filter.c \
$$PWD/ffmpeg/fftools/ffmpeg_hw.c \
$$PWD/ffmpeg/fftools/ffmpeg_mux.c \
$$PWD/ffmpeg/fftools/ffmpeg_opt.c \
$$PWD/ffmpeg/fftools/opt_common.c

DESTDIR = $$PWD/../bin

工程3(ffplay)

好久没发图了,来一张吧… ffplay播放(魔鬼中的天使)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TEMPLATE = app

include($$PWD/sdl/sdl.pri)
include($$PWD/ffmpeg/ffmpeg.pri)


TARGET = ffplay

HEADERS += \
$$PWD/ffmpeg/fftools/cmdutils.h \
$$PWD/ffmpeg/fftools/ffmpeg.h \
$$PWD/ffmpeg/fftools/fopen_utf8.h \
$$PWD/ffmpeg/fftools/opt_common.h

SOURCES += \
$$PWD/ffmpeg/fftools/cmdutils.c \
$$PWD/ffmpeg/fftools/ffplay.c\

DESTDIR = $$PWD/../bin

附件下载

配置参考附件

参考链接

  1. Undocumented_QMake
  2. adding-compilers
  3. Avoiding name clashes with Qmake
支付宝打赏 微信打赏

您的支持是我前行的动力!