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