tor-browser

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

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