tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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