FFmpegRuntimeLinker.cpp (9504B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "FFmpegRuntimeLinker.h" 8 9 #include "FFmpegLibWrapper.h" 10 #include "FFmpegLog.h" 11 #include "prlink.h" 12 13 namespace mozilla { 14 15 FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus = 16 LinkStatus_INIT; 17 const char* FFmpegRuntimeLinker::sLinkStatusLibraryName = ""; 18 19 template <int V> 20 class FFmpegDecoderModule { 21 public: 22 static void Init(const FFmpegLibWrapper*); 23 static already_AddRefed<PlatformDecoderModule> Create( 24 const FFmpegLibWrapper*); 25 }; 26 27 template <int V> 28 class FFmpegEncoderModule { 29 public: 30 static void Init(const FFmpegLibWrapper*); 31 static already_AddRefed<PlatformEncoderModule> Create( 32 const FFmpegLibWrapper*); 33 }; 34 35 static FFmpegLibWrapper sLibAV; 36 37 static const char* sLibs[] = { 38 // clang-format off 39 #if defined(XP_DARWIN) 40 "libavcodec.62.dylib", 41 "libavcodec.61.dylib", 42 "libavcodec.60.dylib", 43 "libavcodec.59.dylib", 44 "libavcodec.58.dylib", 45 "libavcodec.57.dylib", 46 "libavcodec.56.dylib", 47 "libavcodec.55.dylib", 48 "libavcodec.54.dylib", 49 "libavcodec.53.dylib", 50 #elif defined(XP_OPENBSD) 51 "libavcodec.so", // OpenBSD port controls the major/minor library version 52 // of ffmpeg and update it regulary on ABI/API changes 53 #else 54 "libavcodec.so.62", 55 "libavcodec.so.61", 56 "libavcodec.so.60", 57 "libavcodec.so.59", 58 "libavcodec.so.58", 59 "libavcodec-ffmpeg.so.58", 60 "libavcodec-ffmpeg.so.57", 61 "libavcodec-ffmpeg.so.56", 62 "libavcodec.so.57", 63 "libavcodec.so.56", 64 "libavcodec.so.55", 65 "libavcodec.so.54", 66 "libavcodec.so.53", 67 #endif 68 // clang-format on 69 }; 70 71 /* static */ 72 void FFmpegRuntimeLinker::PrefCallbackLogLevel(const char* aPref, void* aData) { 73 sLibAV.UpdateLogLevel(); 74 } 75 76 /* static */ 77 bool FFmpegRuntimeLinker::Init() { 78 if (sLinkStatus != LinkStatus_INIT) { 79 return sLinkStatus == LinkStatus_SUCCEEDED; 80 } 81 82 // While going through all possible libs, this status will be updated with a 83 // more precise error if possible. 84 sLinkStatus = LinkStatus_NOT_FOUND; 85 86 for (size_t i = 0; i < std::size(sLibs); i++) { 87 const char* lib = sLibs[i]; 88 PRLibSpec lspec; 89 lspec.type = PR_LibSpec_Pathname; 90 lspec.value.pathname = lib; 91 sLibAV.mAVCodecLib = 92 PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL); 93 if (sLibAV.mAVCodecLib) { 94 sLibAV.mAVUtilLib = sLibAV.mAVCodecLib; 95 FFmpegLibWrapper::LinkResult res = sLibAV.Link(); 96 switch (res) { 97 case FFmpegLibWrapper::LinkResult::Success: 98 sLibAV.RegisterCallbackLogLevel(PrefCallbackLogLevel); 99 sLinkStatus = LinkStatus_SUCCEEDED; 100 sLinkStatusLibraryName = lib; 101 switch (sLibAV.mVersion) { 102 case 53: 103 FFmpegDecoderModule<53>::Init(&sLibAV); 104 FFmpegEncoderModule<53>::Init(&sLibAV); 105 break; 106 case 54: 107 FFmpegDecoderModule<54>::Init(&sLibAV); 108 FFmpegEncoderModule<54>::Init(&sLibAV); 109 break; 110 case 55: 111 case 56: 112 FFmpegDecoderModule<55>::Init(&sLibAV); 113 FFmpegEncoderModule<55>::Init(&sLibAV); 114 break; 115 case 57: 116 FFmpegDecoderModule<57>::Init(&sLibAV); 117 FFmpegEncoderModule<57>::Init(&sLibAV); 118 break; 119 case 58: 120 FFmpegDecoderModule<58>::Init(&sLibAV); 121 FFmpegEncoderModule<58>::Init(&sLibAV); 122 break; 123 case 59: 124 FFmpegDecoderModule<59>::Init(&sLibAV); 125 FFmpegEncoderModule<59>::Init(&sLibAV); 126 break; 127 case 60: 128 FFmpegDecoderModule<60>::Init(&sLibAV); 129 FFmpegEncoderModule<60>::Init(&sLibAV); 130 break; 131 case 61: 132 FFmpegDecoderModule<61>::Init(&sLibAV); 133 FFmpegEncoderModule<61>::Init(&sLibAV); 134 break; 135 case 62: 136 FFmpegDecoderModule<62>::Init(&sLibAV); 137 FFmpegEncoderModule<62>::Init(&sLibAV); 138 break; 139 } 140 return true; 141 case FFmpegLibWrapper::LinkResult::NoProvidedLib: 142 MOZ_ASSERT_UNREACHABLE("Incorrectly-setup sLibAV"); 143 break; 144 case FFmpegLibWrapper::LinkResult::NoAVCodecVersion: 145 if (sLinkStatus > LinkStatus_INVALID_CANDIDATE) { 146 sLinkStatus = LinkStatus_INVALID_CANDIDATE; 147 sLinkStatusLibraryName = lib; 148 } 149 break; 150 case FFmpegLibWrapper::LinkResult::CannotUseLibAV57: 151 if (sLinkStatus > LinkStatus_UNUSABLE_LIBAV57) { 152 sLinkStatus = LinkStatus_UNUSABLE_LIBAV57; 153 sLinkStatusLibraryName = lib; 154 } 155 break; 156 case FFmpegLibWrapper::LinkResult::BlockedOldLibAVVersion: 157 if (sLinkStatus > LinkStatus_OBSOLETE_LIBAV) { 158 sLinkStatus = LinkStatus_OBSOLETE_LIBAV; 159 sLinkStatusLibraryName = lib; 160 } 161 break; 162 case FFmpegLibWrapper::LinkResult::UnknownFutureLibAVVersion: 163 case FFmpegLibWrapper::LinkResult::MissingLibAVFunction: 164 if (sLinkStatus > LinkStatus_INVALID_LIBAV_CANDIDATE) { 165 sLinkStatus = LinkStatus_INVALID_LIBAV_CANDIDATE; 166 sLinkStatusLibraryName = lib; 167 } 168 break; 169 case FFmpegLibWrapper::LinkResult::UnknownFutureFFMpegVersion: 170 case FFmpegLibWrapper::LinkResult::MissingFFMpegFunction: 171 if (sLinkStatus > LinkStatus_INVALID_FFMPEG_CANDIDATE) { 172 sLinkStatus = LinkStatus_INVALID_FFMPEG_CANDIDATE; 173 sLinkStatusLibraryName = lib; 174 } 175 break; 176 case FFmpegLibWrapper::LinkResult::UnknownOlderFFMpegVersion: 177 if (sLinkStatus > LinkStatus_OBSOLETE_FFMPEG) { 178 sLinkStatus = LinkStatus_OBSOLETE_FFMPEG; 179 sLinkStatusLibraryName = lib; 180 } 181 break; 182 } 183 FFMPEGP_LOG("Failed to link %s: %s", lib, 184 FFmpegLibWrapper::EnumValueToString(res)); 185 } 186 } 187 188 FFMPEGV_LOG("H264/AAC codecs unsupported without ["); 189 for (size_t i = 0; i < std::size(sLibs); i++) { 190 FFMPEGV_LOG("%s %s", i ? "," : " ", sLibs[i]); 191 } 192 FFMPEGV_LOG(" ]\n"); 193 194 return false; 195 } 196 197 /* static */ 198 already_AddRefed<PlatformDecoderModule> FFmpegRuntimeLinker::CreateDecoder() { 199 if (!Init()) { 200 return nullptr; 201 } 202 RefPtr<PlatformDecoderModule> module; 203 switch (sLibAV.mVersion) { 204 case 53: 205 module = FFmpegDecoderModule<53>::Create(&sLibAV); 206 break; 207 case 54: 208 module = FFmpegDecoderModule<54>::Create(&sLibAV); 209 break; 210 case 55: 211 case 56: 212 module = FFmpegDecoderModule<55>::Create(&sLibAV); 213 break; 214 case 57: 215 module = FFmpegDecoderModule<57>::Create(&sLibAV); 216 break; 217 case 58: 218 module = FFmpegDecoderModule<58>::Create(&sLibAV); 219 break; 220 case 59: 221 module = FFmpegDecoderModule<59>::Create(&sLibAV); 222 break; 223 case 60: 224 module = FFmpegDecoderModule<60>::Create(&sLibAV); 225 break; 226 case 61: 227 module = FFmpegDecoderModule<61>::Create(&sLibAV); 228 break; 229 case 62: 230 module = FFmpegDecoderModule<62>::Create(&sLibAV); 231 break; 232 default: 233 module = nullptr; 234 } 235 return module.forget(); 236 } 237 238 /* static */ 239 already_AddRefed<PlatformEncoderModule> FFmpegRuntimeLinker::CreateEncoder() { 240 if (!Init()) { 241 return nullptr; 242 } 243 RefPtr<PlatformEncoderModule> module; 244 switch (sLibAV.mVersion) { 245 case 53: 246 module = FFmpegEncoderModule<53>::Create(&sLibAV); 247 break; 248 case 54: 249 module = FFmpegEncoderModule<54>::Create(&sLibAV); 250 break; 251 case 55: 252 case 56: 253 module = FFmpegEncoderModule<55>::Create(&sLibAV); 254 break; 255 case 57: 256 module = FFmpegEncoderModule<57>::Create(&sLibAV); 257 break; 258 case 58: 259 module = FFmpegEncoderModule<58>::Create(&sLibAV); 260 break; 261 case 59: 262 module = FFmpegEncoderModule<59>::Create(&sLibAV); 263 break; 264 case 60: 265 module = FFmpegEncoderModule<60>::Create(&sLibAV); 266 break; 267 case 61: 268 module = FFmpegEncoderModule<61>::Create(&sLibAV); 269 break; 270 case 62: 271 module = FFmpegEncoderModule<62>::Create(&sLibAV); 272 break; 273 default: 274 module = nullptr; 275 } 276 return module.forget(); 277 } 278 279 /* static */ const char* FFmpegRuntimeLinker::LinkStatusString() { 280 switch (sLinkStatus) { 281 case LinkStatus_INIT: 282 return "Libavcodec not initialized yet"; 283 case LinkStatus_SUCCEEDED: 284 return "Libavcodec linking succeeded"; 285 case LinkStatus_INVALID_FFMPEG_CANDIDATE: 286 return "Invalid FFMpeg libavcodec candidate"; 287 case LinkStatus_UNUSABLE_LIBAV57: 288 return "Unusable LibAV's libavcodec 57"; 289 case LinkStatus_INVALID_LIBAV_CANDIDATE: 290 return "Invalid LibAV libavcodec candidate"; 291 case LinkStatus_OBSOLETE_FFMPEG: 292 return "Obsolete FFMpeg libavcodec candidate"; 293 case LinkStatus_OBSOLETE_LIBAV: 294 return "Obsolete LibAV libavcodec candidate"; 295 case LinkStatus_INVALID_CANDIDATE: 296 return "Invalid libavcodec candidate"; 297 case LinkStatus_NOT_FOUND: 298 return "Libavcodec not found"; 299 } 300 MOZ_ASSERT_UNREACHABLE("Unknown sLinkStatus value"); 301 return "?"; 302 } 303 304 } // namespace mozilla