FFVPXRuntimeLinker.cpp (5521B)
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 "FFVPXRuntimeLinker.h" 8 9 #include "FFmpegLibWrapper.h" 10 #include "FFmpegLog.h" 11 #include "mozilla/FileUtils.h" 12 #include "mozilla/ToString.h" 13 #include "nsLocalFile.h" 14 #include "nsXPCOMPrivate.h" 15 #include "prlink.h" 16 17 namespace mozilla { 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 sFFVPXLib; 36 37 StaticMutex FFVPXRuntimeLinker::sMutex; 38 39 FFVPXRuntimeLinker::LinkStatus FFVPXRuntimeLinker::sLinkStatus = 40 LinkStatus_INIT; 41 42 static PRLibrary* MozAVLink(nsIFile* aFile) { 43 PRLibSpec lspec; 44 PathString path = aFile->NativePath(); 45 #ifdef XP_WIN 46 lspec.type = PR_LibSpec_PathnameU; 47 lspec.value.pathname_u = path.get(); 48 #else 49 # if defined(XP_OPENBSD) 50 /* on OpenBSD, libmozavcodec.so and libmozavutil.so are preloaded before 51 * sandboxing so make sure only the filename is passed to 52 * PR_LoadLibraryWithFlags(), dlopen() will return the preloaded library 53 * handle instead of failing to find it due to sandboxing */ 54 nsAutoCString leaf; 55 nsresult rv = aFile->GetNativeLeafName(leaf); 56 if (NS_SUCCEEDED(rv)) { 57 path = PathString(leaf); 58 } 59 # endif // defined(XP_OPENBSD) 60 lspec.type = PR_LibSpec_Pathname; 61 lspec.value.pathname = path.get(); 62 #endif 63 #ifdef MOZ_WIDGET_ANDROID 64 PRLibrary* lib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_GLOBAL); 65 #else 66 PRLibrary* lib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL); 67 #endif 68 if (!lib) { 69 FFMPEGV_LOG("unable to load library %s", aFile->HumanReadablePath().get()); 70 } 71 return lib; 72 } 73 74 /* static */ 75 void FFVPXRuntimeLinker::PrefCallbackLogLevel(const char* aPref, void* aData) { 76 sFFVPXLib.UpdateLogLevel(); 77 } 78 79 /* static */ 80 bool FFVPXRuntimeLinker::Init() { 81 // Enter critical section to set up ffvpx. 82 StaticMutexAutoLock lock(sMutex); 83 84 if (sLinkStatus) { 85 if (sLinkStatus == LinkStatus_SUCCEEDED) { 86 FFmpegDecoderModule<FFVPX_VERSION>::Init(&sFFVPXLib); 87 FFmpegEncoderModule<FFVPX_VERSION>::Init(&sFFVPXLib); 88 } 89 return sLinkStatus == LinkStatus_SUCCEEDED; 90 } 91 92 sLinkStatus = LinkStatus_FAILED; 93 94 #ifdef XP_WIN 95 PathString path = 96 GetLibraryFilePathname(LXUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Init); 97 #elif defined(ANDROID) 98 // On Android, libxul is either pulled from the APK or from a temporary folder 99 // for gtests/fuzzing. libmozavutil and libmozavcodec are always in the APK, 100 // so let's use libmozglue instead to find the base pathname. 101 PathString path = GetLibraryFilePathname( 102 MOZ_DLL_PREFIX "mozglue" MOZ_DLL_SUFFIX, (PRFuncPtr)&malloc); 103 #else 104 PathString path = 105 GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Init); 106 #endif 107 if (path.IsEmpty()) { 108 return false; 109 } 110 nsCOMPtr<nsIFile> libFile; 111 if (NS_FAILED(NS_NewPathStringLocalFile(path, getter_AddRefs(libFile)))) { 112 return false; 113 } 114 115 #ifndef ANDROID 116 if (getenv("MOZ_RUN_GTEST") 117 # ifdef FUZZING 118 || getenv("FUZZER") 119 # endif 120 ) { 121 // The condition above is the same as in 122 // xpcom/glue/standalone/nsXPCOMGlue.cpp. This means we can't reach here 123 // without the gtest libxul being loaded. In turn, that means the path to 124 // libxul leads to a subdirectory of where the libmozav* libraries are, so 125 // we get the parent. 126 nsCOMPtr<nsIFile> parent; 127 if (NS_FAILED(libFile->GetParent(getter_AddRefs(parent)))) { 128 return false; 129 } 130 libFile = parent; 131 } 132 #endif 133 134 if (NS_FAILED(libFile->SetNativeLeafName(MOZ_DLL_PREFIX 135 "mozavutil" MOZ_DLL_SUFFIX ""_ns))) { 136 return false; 137 } 138 sFFVPXLib.mAVUtilLib = MozAVLink(libFile); 139 140 if (NS_FAILED(libFile->SetNativeLeafName( 141 MOZ_DLL_PREFIX "mozavcodec" MOZ_DLL_SUFFIX ""_ns))) { 142 return false; 143 } 144 sFFVPXLib.mAVCodecLib = MozAVLink(libFile); 145 FFmpegLibWrapper::LinkResult res = sFFVPXLib.Link(); 146 FFMPEGP_LOG("Link result: %s", ToString(res).c_str()); 147 if (res == FFmpegLibWrapper::LinkResult::Success) { 148 sLinkStatus = LinkStatus_SUCCEEDED; 149 FFmpegDecoderModule<FFVPX_VERSION>::Init(&sFFVPXLib); 150 FFmpegEncoderModule<FFVPX_VERSION>::Init(&sFFVPXLib); 151 return true; 152 } 153 return false; 154 } 155 156 /* static */ 157 already_AddRefed<PlatformDecoderModule> FFVPXRuntimeLinker::CreateDecoder() { 158 if (!Init()) { 159 return nullptr; 160 } 161 return FFmpegDecoderModule<FFVPX_VERSION>::Create(&sFFVPXLib); 162 } 163 164 /* static */ 165 already_AddRefed<PlatformEncoderModule> FFVPXRuntimeLinker::CreateEncoder() { 166 if (!Init()) { 167 return nullptr; 168 } 169 return FFmpegEncoderModule<FFVPX_VERSION>::Create(&sFFVPXLib); 170 } 171 172 /* static */ 173 void FFVPXRuntimeLinker::GetFFTFuncs(FFmpegFFTFuncs* aOutFuncs) { 174 []() MOZ_NO_THREAD_SAFETY_ANALYSIS { 175 MOZ_ASSERT(sLinkStatus != LinkStatus_INIT); 176 }(); 177 MOZ_ASSERT(sFFVPXLib.av_tx_init && sFFVPXLib.av_tx_uninit); 178 aOutFuncs->init = sFFVPXLib.av_tx_init; 179 aOutFuncs->uninit = sFFVPXLib.av_tx_uninit; 180 } 181 182 } // namespace mozilla