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 #include "FFmpegLibWrapper.h"
9 #include "mozilla/ArrayUtils.h"
10 #include "FFmpegLog.h"
11 #include "prlink.h"
12 
13 namespace mozilla
14 {
15 
16 FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus =
17   LinkStatus_INIT;
18 const char* FFmpegRuntimeLinker::sLinkStatusLibraryName = "";
19 
20 template <int V> class FFmpegDecoderModule
21 {
22 public:
23   static already_AddRefed<PlatformDecoderModule> Create(FFmpegLibWrapper*);
24 };
25 
26 static FFmpegLibWrapper sLibAV;
27 
28 static const char* sLibs[] = {
29 #if defined(XP_DARWIN)
30   "libavcodec.58.dylib",
31   "libavcodec.57.dylib",
32   "libavcodec.56.dylib",
33   "libavcodec.55.dylib",
34   "libavcodec.54.dylib",
35   "libavcodec.53.dylib",
36 #else
37   "libavcodec.so.58",
38   "libavcodec-ffmpeg.so.58",
39   "libavcodec-ffmpeg.so.57",
40   "libavcodec-ffmpeg.so.56",
41   "libavcodec.so.57",
42   "libavcodec.so.56",
43   "libavcodec.so.55",
44   "libavcodec.so.54",
45   "libavcodec.so.53",
46 #endif
47 };
48 
49 /* static */ bool
Init()50 FFmpegRuntimeLinker::Init()
51 {
52   if (sLinkStatus != LinkStatus_INIT) {
53     return sLinkStatus == LinkStatus_SUCCEEDED;
54   }
55 
56   // While going through all possible libs, this status will be updated with a
57   // more precise error if possible.
58   sLinkStatus = LinkStatus_NOT_FOUND;
59 
60   for (size_t i = 0; i < ArrayLength(sLibs); i++) {
61     const char* lib = sLibs[i];
62     PRLibSpec lspec;
63     lspec.type = PR_LibSpec_Pathname;
64     lspec.value.pathname = lib;
65     sLibAV.mAVCodecLib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
66     if (sLibAV.mAVCodecLib) {
67       sLibAV.mAVUtilLib = sLibAV.mAVCodecLib;
68       switch (sLibAV.Link()) {
69         case FFmpegLibWrapper::LinkResult::Success:
70           sLinkStatus = LinkStatus_SUCCEEDED;
71           sLinkStatusLibraryName = lib;
72           return true;
73         case FFmpegLibWrapper::LinkResult::NoProvidedLib:
74           MOZ_ASSERT_UNREACHABLE("Incorrectly-setup sLibAV");
75           break;
76         case FFmpegLibWrapper::LinkResult::NoAVCodecVersion:
77           if (sLinkStatus > LinkStatus_INVALID_CANDIDATE) {
78             sLinkStatus = LinkStatus_INVALID_CANDIDATE;
79             sLinkStatusLibraryName = lib;
80           }
81           break;
82         case FFmpegLibWrapper::LinkResult::CannotUseLibAV57:
83           if (sLinkStatus > LinkStatus_UNUSABLE_LIBAV57) {
84             sLinkStatus = LinkStatus_UNUSABLE_LIBAV57;
85             sLinkStatusLibraryName = lib;
86           }
87           break;
88         case FFmpegLibWrapper::LinkResult::BlockedOldLibAVVersion:
89           if (sLinkStatus > LinkStatus_OBSOLETE_LIBAV) {
90             sLinkStatus = LinkStatus_OBSOLETE_LIBAV;
91             sLinkStatusLibraryName = lib;
92           }
93           break;
94         case FFmpegLibWrapper::LinkResult::UnknownFutureLibAVVersion:
95         case FFmpegLibWrapper::LinkResult::MissingLibAVFunction:
96           if (sLinkStatus > LinkStatus_INVALID_LIBAV_CANDIDATE) {
97             sLinkStatus = LinkStatus_INVALID_LIBAV_CANDIDATE;
98             sLinkStatusLibraryName = lib;
99           }
100           break;
101         case FFmpegLibWrapper::LinkResult::UnknownFutureFFMpegVersion:
102         case FFmpegLibWrapper::LinkResult::MissingFFMpegFunction:
103           if (sLinkStatus > LinkStatus_INVALID_FFMPEG_CANDIDATE) {
104             sLinkStatus = LinkStatus_INVALID_FFMPEG_CANDIDATE;
105             sLinkStatusLibraryName = lib;
106           }
107           break;
108         case FFmpegLibWrapper::LinkResult::UnknownOlderFFMpegVersion:
109           if (sLinkStatus > LinkStatus_OBSOLETE_FFMPEG) {
110             sLinkStatus = LinkStatus_OBSOLETE_FFMPEG;
111             sLinkStatusLibraryName = lib;
112           }
113           break;
114       }
115     }
116   }
117 
118   FFMPEG_LOG("H264/AAC codecs unsupported without [");
119   for (size_t i = 0; i < ArrayLength(sLibs); i++) {
120     FFMPEG_LOG("%s %s", i ? "," : " ", sLibs[i]);
121   }
122   FFMPEG_LOG(" ]\n");
123 
124   return false;
125 }
126 
127 /* static */ already_AddRefed<PlatformDecoderModule>
CreateDecoderModule()128 FFmpegRuntimeLinker::CreateDecoderModule()
129 {
130   if (!Init()) {
131     return nullptr;
132   }
133   RefPtr<PlatformDecoderModule> module;
134   switch (sLibAV.mVersion) {
135     case 53: module = FFmpegDecoderModule<53>::Create(&sLibAV); break;
136     case 54: module = FFmpegDecoderModule<54>::Create(&sLibAV); break;
137     case 55:
138     case 56: module = FFmpegDecoderModule<55>::Create(&sLibAV); break;
139     case 57: module = FFmpegDecoderModule<57>::Create(&sLibAV); break;
140     case 58: module = FFmpegDecoderModule<58>::Create(&sLibAV); break;
141     default: module = nullptr;
142   }
143   return module.forget();
144 }
145 
146 /* static */ const char*
LinkStatusString()147 FFmpegRuntimeLinker::LinkStatusString()
148 {
149   switch (sLinkStatus) {
150     case LinkStatus_INIT:
151       return "Libavcodec not initialized yet";
152     case LinkStatus_SUCCEEDED:
153       return "Libavcodec linking succeeded";
154     case LinkStatus_INVALID_FFMPEG_CANDIDATE:
155       return "Invalid FFMpeg libavcodec candidate";
156     case LinkStatus_UNUSABLE_LIBAV57:
157       return "Unusable LibAV's libavcodec 57";
158     case LinkStatus_INVALID_LIBAV_CANDIDATE:
159       return "Invalid LibAV libavcodec candidate";
160     case LinkStatus_OBSOLETE_FFMPEG:
161       return "Obsolete FFMpeg libavcodec candidate";
162     case LinkStatus_OBSOLETE_LIBAV:
163       return "Obsolete LibAV libavcodec candidate";
164     case LinkStatus_INVALID_CANDIDATE:
165       return "Invalid libavcodec candidate";
166     case LinkStatus_NOT_FOUND:
167       return "Libavcodec not found";
168   }
169   MOZ_ASSERT_UNREACHABLE("Unknown sLinkStatus value");
170   return "?";
171 }
172 
173 } // namespace mozilla
174