/src/mozilla-central/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #include "FFmpegLibWrapper.h" |
6 | | #include "FFmpegLog.h" |
7 | | #include "mozilla/PodOperations.h" |
8 | | #ifdef MOZ_FFMPEG |
9 | | #include "mozilla/StaticPrefs.h" |
10 | | #endif |
11 | | #include "mozilla/Types.h" |
12 | | #include "PlatformDecoderModule.h" |
13 | | #include "prlink.h" |
14 | | |
15 | 0 | #define AV_LOG_DEBUG 48 |
16 | 0 | #define AV_LOG_INFO 32 |
17 | | |
18 | | namespace mozilla |
19 | | { |
20 | | |
21 | | FFmpegLibWrapper::LinkResult |
22 | | FFmpegLibWrapper::Link() |
23 | 0 | { |
24 | 0 | if (!mAVCodecLib || !mAVUtilLib) { |
25 | 0 | Unlink(); |
26 | 0 | return LinkResult::NoProvidedLib; |
27 | 0 | } |
28 | 0 | |
29 | 0 | avcodec_version = |
30 | 0 | (decltype(avcodec_version))PR_FindSymbol(mAVCodecLib, "avcodec_version"); |
31 | 0 | if (!avcodec_version) { |
32 | 0 | Unlink(); |
33 | 0 | return LinkResult::NoAVCodecVersion; |
34 | 0 | } |
35 | 0 | uint32_t version = avcodec_version(); |
36 | 0 | uint32_t macro = (version >> 16) & 0xFFu; |
37 | 0 | mVersion = static_cast<int>(macro); |
38 | 0 | uint32_t micro = version & 0xFFu; |
39 | 0 | // A micro version >= 100 indicates that it's FFmpeg (as opposed to LibAV). |
40 | 0 | bool isFFMpeg = micro >= 100; |
41 | 0 | if (!isFFMpeg) { |
42 | 0 | if (macro == 57) { |
43 | 0 | // Due to current AVCodecContext binary incompatibility we can only |
44 | 0 | // support FFmpeg 57 at this stage. |
45 | 0 | Unlink(); |
46 | 0 | return LinkResult::CannotUseLibAV57; |
47 | 0 | } |
48 | 0 | #ifdef MOZ_FFMPEG |
49 | 0 | if (version < (54u << 16 | 35u << 8 | 1u) && |
50 | 0 | !StaticPrefs::MediaLibavcodecAllowObsolete()) { |
51 | 0 | // Refuse any libavcodec version prior to 54.35.1. |
52 | 0 | // (Unless media.libavcodec.allow-obsolete==true) |
53 | 0 | Unlink(); |
54 | 0 | return LinkResult::BlockedOldLibAVVersion; |
55 | 0 | } |
56 | 0 | #endif |
57 | 0 | } |
58 | 0 | |
59 | 0 | enum { |
60 | 0 | AV_FUNC_AVUTIL_MASK = 1 << 8, |
61 | 0 | AV_FUNC_53 = 1 << 0, |
62 | 0 | AV_FUNC_54 = 1 << 1, |
63 | 0 | AV_FUNC_55 = 1 << 2, |
64 | 0 | AV_FUNC_56 = 1 << 3, |
65 | 0 | AV_FUNC_57 = 1 << 4, |
66 | 0 | AV_FUNC_58 = 1 << 5, |
67 | 0 | AV_FUNC_AVUTIL_53 = AV_FUNC_53 | AV_FUNC_AVUTIL_MASK, |
68 | 0 | AV_FUNC_AVUTIL_54 = AV_FUNC_54 | AV_FUNC_AVUTIL_MASK, |
69 | 0 | AV_FUNC_AVUTIL_55 = AV_FUNC_55 | AV_FUNC_AVUTIL_MASK, |
70 | 0 | AV_FUNC_AVUTIL_56 = AV_FUNC_56 | AV_FUNC_AVUTIL_MASK, |
71 | 0 | AV_FUNC_AVUTIL_57 = AV_FUNC_57 | AV_FUNC_AVUTIL_MASK, |
72 | 0 | AV_FUNC_AVUTIL_58 = AV_FUNC_58 | AV_FUNC_AVUTIL_MASK, |
73 | 0 | AV_FUNC_AVCODEC_ALL = AV_FUNC_53 | AV_FUNC_54 | AV_FUNC_55 | AV_FUNC_56 | AV_FUNC_57 | AV_FUNC_58, |
74 | 0 | AV_FUNC_AVUTIL_ALL = AV_FUNC_AVCODEC_ALL | AV_FUNC_AVUTIL_MASK |
75 | 0 | }; |
76 | 0 |
|
77 | 0 | switch (macro) { |
78 | 0 | case 53: |
79 | 0 | version = AV_FUNC_53; |
80 | 0 | break; |
81 | 0 | case 54: |
82 | 0 | version = AV_FUNC_54; |
83 | 0 | break; |
84 | 0 | case 55: |
85 | 0 | version = AV_FUNC_55; |
86 | 0 | break; |
87 | 0 | case 56: |
88 | 0 | version = AV_FUNC_56; |
89 | 0 | break; |
90 | 0 | case 57: |
91 | 0 | version = AV_FUNC_57; |
92 | 0 | break; |
93 | 0 | case 58: |
94 | 0 | version = AV_FUNC_58; |
95 | 0 | break; |
96 | 0 | default: |
97 | 0 | FFMPEG_LOG("Unknown avcodec version"); |
98 | 0 | Unlink(); |
99 | 0 | return isFFMpeg |
100 | 0 | ? ((macro > 57) |
101 | 0 | ? LinkResult::UnknownFutureFFMpegVersion |
102 | 0 | : LinkResult::UnknownOlderFFMpegVersion) |
103 | 0 | // All LibAV versions<54.35.1 are blocked, therefore we must be |
104 | 0 | // dealing with a later one. |
105 | 0 | : LinkResult::UnknownFutureLibAVVersion; |
106 | 0 | } |
107 | 0 | |
108 | 0 | #define AV_FUNC_OPTION(func, ver) \ |
109 | 0 | if ((ver) & version) { \ |
110 | 0 | if (!(func = (decltype(func))PR_FindSymbol(((ver) & AV_FUNC_AVUTIL_MASK) ? mAVUtilLib : mAVCodecLib, #func))) { \ |
111 | 0 | FFMPEG_LOG("Couldn't load function " # func); \ |
112 | 0 | } \ |
113 | 0 | } else { \ |
114 | 0 | func = (decltype(func))nullptr; \ |
115 | 0 | } |
116 | 0 | |
117 | 0 | #define AV_FUNC(func, ver) \ |
118 | 0 | AV_FUNC_OPTION(func, ver) \ |
119 | 0 | if ((ver) & version && !func) { \ |
120 | 0 | Unlink(); \ |
121 | 0 | return isFFMpeg ? LinkResult::MissingFFMpegFunction \ |
122 | 0 | : LinkResult::MissingLibAVFunction; \ |
123 | 0 | } |
124 | 0 |
|
125 | 0 | AV_FUNC(av_lockmgr_register, AV_FUNC_AVCODEC_ALL) |
126 | 0 | AV_FUNC(avcodec_alloc_context3, AV_FUNC_AVCODEC_ALL) |
127 | 0 | AV_FUNC(avcodec_close, AV_FUNC_AVCODEC_ALL) |
128 | 0 | AV_FUNC(avcodec_decode_audio4, AV_FUNC_AVCODEC_ALL) |
129 | 0 | AV_FUNC(avcodec_decode_video2, AV_FUNC_AVCODEC_ALL) |
130 | 0 | AV_FUNC(avcodec_find_decoder, AV_FUNC_AVCODEC_ALL) |
131 | 0 | AV_FUNC(avcodec_flush_buffers, AV_FUNC_AVCODEC_ALL) |
132 | 0 | AV_FUNC(avcodec_open2, AV_FUNC_AVCODEC_ALL) |
133 | 0 | AV_FUNC(avcodec_register_all, AV_FUNC_AVCODEC_ALL) |
134 | 0 | AV_FUNC(av_init_packet, AV_FUNC_AVCODEC_ALL) |
135 | 0 | AV_FUNC(av_parser_init, AV_FUNC_AVCODEC_ALL) |
136 | 0 | AV_FUNC(av_parser_close, AV_FUNC_AVCODEC_ALL) |
137 | 0 | AV_FUNC(av_parser_parse2, AV_FUNC_AVCODEC_ALL) |
138 | 0 | AV_FUNC(avcodec_alloc_frame, (AV_FUNC_53 | AV_FUNC_54)) |
139 | 0 | AV_FUNC(avcodec_get_frame_defaults, (AV_FUNC_53 | AV_FUNC_54)) |
140 | 0 | AV_FUNC(avcodec_free_frame, AV_FUNC_54) |
141 | 0 | AV_FUNC_OPTION(av_rdft_init, AV_FUNC_AVCODEC_ALL) |
142 | 0 | AV_FUNC_OPTION(av_rdft_calc, AV_FUNC_AVCODEC_ALL) |
143 | 0 | AV_FUNC_OPTION(av_rdft_end, AV_FUNC_AVCODEC_ALL) |
144 | 0 | AV_FUNC(av_log_set_level, AV_FUNC_AVUTIL_ALL) |
145 | 0 | AV_FUNC(av_malloc, AV_FUNC_AVUTIL_ALL) |
146 | 0 | AV_FUNC(av_freep, AV_FUNC_AVUTIL_ALL) |
147 | 0 | AV_FUNC(av_frame_alloc, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 | AV_FUNC_AVUTIL_58)) |
148 | 0 | AV_FUNC(av_frame_free, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 | AV_FUNC_AVUTIL_58)) |
149 | 0 | AV_FUNC(av_frame_unref, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57 | AV_FUNC_AVUTIL_58)) |
150 | 0 | AV_FUNC_OPTION(av_frame_get_colorspace, AV_FUNC_AVUTIL_ALL) |
151 | 0 | #undef AV_FUNC |
152 | 0 | #undef AV_FUNC_OPTION |
153 | 0 |
|
154 | 0 | avcodec_register_all(); |
155 | 0 | if (MOZ_LOG_TEST(sPDMLog, LogLevel::Debug)) { |
156 | 0 | av_log_set_level(AV_LOG_DEBUG); |
157 | 0 | } else if (MOZ_LOG_TEST(sPDMLog, LogLevel::Info)) { |
158 | 0 | av_log_set_level(AV_LOG_INFO); |
159 | 0 | } else { |
160 | 0 | av_log_set_level(0); |
161 | 0 | } |
162 | 0 | return LinkResult::Success; |
163 | 0 | } |
164 | | |
165 | | void |
166 | | FFmpegLibWrapper::Unlink() |
167 | 0 | { |
168 | 0 | if (av_lockmgr_register) { |
169 | 0 | // Registering a null lockmgr cause the destruction of libav* global mutexes |
170 | 0 | // as the default lockmgr that allocated them will be deregistered. |
171 | 0 | // This prevents ASAN and valgrind to report sizeof(pthread_mutex_t) leaks. |
172 | 0 | av_lockmgr_register(nullptr); |
173 | 0 | } |
174 | 0 | if (mAVUtilLib && mAVUtilLib != mAVCodecLib) { |
175 | 0 | PR_UnloadLibrary(mAVUtilLib); |
176 | 0 | } |
177 | 0 | if (mAVCodecLib) { |
178 | 0 | PR_UnloadLibrary(mAVCodecLib); |
179 | 0 | } |
180 | 0 | PodZero(this); |
181 | 0 | } |
182 | | |
183 | | } // namespace mozilla |