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