• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kivy / python-for-android / 20643376296

01 Jan 2026 06:24PM UTC coverage: 63.818%. First build
20643376296

Pull #3276

github

web-flow
Merge 504985464 into 6494ac165
Pull Request #3276: `ffmpeg`: include executable

1781 of 3051 branches covered (58.37%)

Branch coverage included in aggregate %.

4 of 6 new or added lines in 1 file covered. (66.67%)

5216 of 7913 relevant lines covered (65.92%)

5.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

19.75
/pythonforandroid/recipes/ffmpeg/__init__.py
1
from pythonforandroid.toolchain import Recipe, current_directory, shprint
8✔
2
from os.path import exists, join, realpath
8✔
3
import sh
8✔
4
from multiprocessing import cpu_count
8✔
5

6

7
class FFMpegRecipe(Recipe):
8✔
8
    version = 'n6.1.2'
8✔
9
    # Moved to github.com instead of ffmpeg.org to improve download speed
10
    url = 'https://github.com/FFmpeg/FFmpeg/archive/{version}.zip'
8✔
11
    depends = [('sdl2', 'sdl3')]  # Need this to build correct recipe order
8✔
12
    opts_depends = ['openssl', 'ffpyplayer_codecs', 'av_codecs']
8✔
13
    patches = ['patches/configure.patch']
8✔
14
    _libs = [
8✔
15
        "libavcodec.so",
16
        "libavfilter.so",
17
        "libavutil.so",
18
        "libswscale.so",
19
        "libavdevice.so",
20
        "libavformat.so",
21
        "libswresample.so",
22
        "libffmpegbin.so",
23
    ]
24
    built_libraries = dict.fromkeys(_libs, "./lib")
8✔
25

26
    def should_build(self, arch):
8✔
27
        build_dir = self.get_build_dir(arch.arch)
×
28
        return not exists(join(build_dir, 'lib', 'libavcodec.so'))
×
29

30
    def get_recipe_env(self, arch):
8✔
31
        env = super().get_recipe_env(arch)
×
32
        env['NDK'] = self.ctx.ndk_dir
×
33
        return env
×
34

35
    def build_arch(self, arch):
8✔
36
        with current_directory(self.get_build_dir(arch.arch)):
×
37
            env = arch.get_env()
×
38

39
            flags = ['--disable-everything']
×
40
            cflags = []
×
41
            ldflags = []
×
42

43
            # enable hardware acceleration codecs
44
            flags = [
×
45
                '--enable-jni',
46
                '--enable-mediacodec'
47
            ]
48

49
            if 'openssl' in self.ctx.recipe_build_order:
×
50
                flags += [
×
51
                    '--enable-openssl',
52
                    '--enable-nonfree',
53
                    '--enable-protocol=https,tls_openssl',
54
                ]
55
                build_dir = Recipe.get_recipe(
×
56
                    'openssl', self.ctx).get_build_dir(arch.arch)
57
                cflags += ['-I' + build_dir + '/include/',
×
58
                           '-DOPENSSL_API_COMPAT=0x10002000L']
59
                ldflags += ['-L' + build_dir]
×
60

61
            codecs_opts = {"ffpyplayer_codecs", "av_codecs"}
×
62
            if codecs_opts.intersection(self.ctx.recipe_build_order):
×
63

64
                # Enable GPL
65
                flags += ['--enable-gpl']
×
66

67
                # libx264
68
                flags += ['--enable-libx264']
×
69
                build_dir = Recipe.get_recipe(
×
70
                    'libx264', self.ctx).get_build_dir(arch.arch)
71
                cflags += ['-I' + build_dir + '/include/']
×
72
                # Newer versions of FFmpeg prioritize the dynamic library and ignore
73
                # the static one, unless the static library path is explicitly set.
74
                ldflags += [build_dir + '/lib/' + 'libx264.a']
×
75

76
                # libshine
77
                flags += ['--enable-libshine']
×
78
                build_dir = Recipe.get_recipe('libshine', self.ctx).get_build_dir(arch.arch)
×
79
                cflags += ['-I' + build_dir + '/include/']
×
80
                ldflags += ['-lshine', '-L' + build_dir + '/lib/']
×
81
                ldflags += ['-lm']
×
82

83
                # libvpx
84
                flags += ['--enable-libvpx']
×
85
                build_dir = Recipe.get_recipe(
×
86
                    'libvpx', self.ctx).get_build_dir(arch.arch)
87
                cflags += ['-I' + build_dir + '/include/']
×
88
                ldflags += ['-lvpx', '-L' + build_dir + '/lib/']
×
89

90
                # Enable all codecs:
91
                flags += [
×
92
                    '--enable-parsers',
93
                    '--enable-decoders',
94
                    '--enable-encoders',
95
                    '--enable-muxers',
96
                    '--enable-demuxers',
97
                ]
98
            else:
99
                # Enable codecs only for .mp4:
100
                flags += [
×
101
                    '--enable-parser=aac,ac3,h261,h264,mpegaudio,mpeg4video,mpegvideo,vc1',
102
                    '--enable-decoder=aac,h264,mpeg4,mpegvideo',
103
                    '--enable-muxer=h264,mov,mp4,mpeg2video',
104
                    '--enable-demuxer=aac,h264,m4v,mov,mpegvideo,vc1,rtsp',
105
                ]
106

107
            # needed to prevent _ffmpeg.so: version node not found for symbol av_init_packet@LIBAVFORMAT_52
108
            # /usr/bin/ld: failed to set dynamic section sizes: Bad value
109
            flags += [
×
110
                '--disable-symver',
111
            ]
112

113
            # disable doc
114
            flags += [
×
115
                '--disable-doc',
116
            ]
117

118
            # other flags:
119
            flags += [
×
120
                '--enable-filter=aresample,resample,crop,adelay,volume,scale',
121
                '--enable-protocol=file,http,hls,udp,tcp',
122
                '--enable-small',
123
                '--enable-hwaccels',
124
                '--enable-pic',
125
                '--disable-static',
126
                '--disable-debug',
127
                '--enable-shared',
128
            ]
129

130
            if 'arm64' in arch.arch:
×
131
                arch_flag = 'aarch64'
×
132
            elif 'x86' in arch.arch:
×
133
                arch_flag = 'x86'
×
134
                flags += ['--disable-asm']
×
135
            else:
136
                arch_flag = 'arm'
×
137

138
            # android:
139
            flags += [
×
140
                '--target-os=android',
141
                '--enable-cross-compile',
142
                '--cross-prefix={}-'.format(arch.target),
143
                '--arch={}'.format(arch_flag),
144
                '--strip={}'.format(self.ctx.ndk.llvm_strip),
145
                '--sysroot={}'.format(self.ctx.ndk.sysroot),
146
                '--enable-neon',
147
                '--prefix={}'.format(realpath('.')),
148
            ]
149

150
            if arch_flag == 'arm':
×
151
                cflags += [
×
152
                    '-mfpu=vfpv3-d16',
153
                    '-mfloat-abi=softfp',
154
                    '-fPIC',
155
                ]
156

157
            env['CFLAGS'] += ' ' + ' '.join(cflags)
×
158
            env['LDFLAGS'] += ' ' + ' '.join(ldflags)
×
159

160
            configure = sh.Command('./configure')
×
161
            shprint(configure, *flags, _env=env)
×
NEW
162
            shprint(sh.make, '-j', f"{cpu_count()}", _env=env)
×
163
            shprint(sh.make, 'install', _env=env)
×
NEW
164
            shprint(sh.cp, "ffmpeg", "./lib/libffmpegbin.so")
×
165

166

167
recipe = FFMpegRecipe()
8✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc