From 0911f86c4467c8be53d501fcb13f0751bf836b8f Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Thu, 12 Nov 2015 12:06:18 +1100 Subject: [PATCH] Bug 1223333: [ffmpeg] Do not rely on library name to determine the libavcodec's version. r=kentuckyfriedtakahe Also uses portable way to dynamically open libraries. --- .../platforms/ffmpeg/FFmpegDataDecoder.cpp | 4 +- .../platforms/ffmpeg/FFmpegDecoderModule.h | 9 -- .../platforms/ffmpeg/FFmpegFunctionList.h | 2 - .../platforms/ffmpeg/FFmpegRuntimeLinker.cpp | 96 ++++++++++++------- .../platforms/ffmpeg/FFmpegRuntimeLinker.h | 11 ++- 5 files changed, 72 insertions(+), 50 deletions(-) diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index c1542bc32fa4..7f154e8b666d 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -13,7 +13,7 @@ #include "FFmpegLog.h" #include "FFmpegDataDecoder.h" #include "prsystem.h" -#include "FFmpegDecoderModule.h" +#include "FFmpegRuntimeLinker.h" namespace mozilla { @@ -89,7 +89,7 @@ FFmpegDataDecoder::InitDecoder() // FFmpeg takes this as a suggestion for what format to use for audio samples. uint32_t major, minor; - FFmpegDecoderModule::GetVersion(major, minor); + FFmpegRuntimeLinker::GetVersion(major, minor); // LibAV 0.8 produces rubbish float interlaved samples, request 16 bits audio. mCodecContext->request_sample_fmt = major == 53 && minor <= 34 ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLT; diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index dbda9e7c8b14..f81f150e56c7 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -26,15 +26,6 @@ public: return pdm.forget(); } - static bool - GetVersion(uint32_t& aMajor, uint32_t& aMinor) - { - uint32_t version = avcodec_version(); - aMajor = (version >> 16) & 0xff; - aMinor = (version >> 8) & 0xff; - return true; - } - FFmpegDecoderModule() {} virtual ~FFmpegDecoderModule() {} diff --git a/dom/media/platforms/ffmpeg/FFmpegFunctionList.h b/dom/media/platforms/ffmpeg/FFmpegFunctionList.h index 94f734a49773..2e9728831beb 100644 --- a/dom/media/platforms/ffmpeg/FFmpegFunctionList.h +++ b/dom/media/platforms/ffmpeg/FFmpegFunctionList.h @@ -16,11 +16,9 @@ AV_FUNC(avcodec_alloc_context3, 0) AV_FUNC(avcodec_get_edge_width, 0) AV_FUNC(avcodec_open2, 0) AV_FUNC(av_init_packet, 0) -AV_FUNC(av_dict_get, 0) AV_FUNC(av_parser_init, 0) AV_FUNC(av_parser_close, 0) AV_FUNC(av_parser_parse2, 0) -AV_FUNC(avcodec_version, 0) AV_FUNC(avcodec_register_all, 0) /* libavutil */ diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp index 0d712f929ce5..d0e0131606e8 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp @@ -4,14 +4,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include - #include "FFmpegRuntimeLinker.h" #include "mozilla/ArrayUtils.h" #include "FFmpegLog.h" #include "mozilla/Preferences.h" - -#define NUM_ELEMENTS(X) (sizeof(X) / sizeof((X)[0])) +#include "prlink.h" namespace mozilla { @@ -19,35 +16,33 @@ namespace mozilla FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus = LinkStatus_INIT; -struct AvCodecLib -{ - const char* Name; - already_AddRefed (*Factory)(); - uint32_t Version; -}; - template class FFmpegDecoderModule { public: static already_AddRefed Create(); }; -static const AvCodecLib sLibs[] = { - { "libavcodec-ffmpeg.so.56", FFmpegDecoderModule<55>::Create, 55 }, - { "libavcodec.so.56", FFmpegDecoderModule<55>::Create, 55 }, - { "libavcodec.so.55", FFmpegDecoderModule<55>::Create, 55 }, - { "libavcodec.so.54", FFmpegDecoderModule<54>::Create, 54 }, - { "libavcodec.so.53", FFmpegDecoderModule<53>::Create, 53 }, - { "libavcodec.56.dylib", FFmpegDecoderModule<55>::Create, 55 }, - { "libavcodec.55.dylib", FFmpegDecoderModule<55>::Create, 55 }, - { "libavcodec.54.dylib", FFmpegDecoderModule<54>::Create, 54 }, - { "libavcodec.53.dylib", FFmpegDecoderModule<53>::Create, 53 }, +static const char* sLibs[] = { +#if defined(XP_DARWIN) + "libavcodec.56.dylib", + "libavcodec.55.dylib", + "libavcodec.54.dylib", + "libavcodec.53.dylib", +#else + "libavcodec-ffmpeg.so.56", + "libavcodec.so.56", + "libavcodec.so.55", + "libavcodec.so.54", + "libavcodec.so.53", +#endif }; -void* FFmpegRuntimeLinker::sLinkedLib = nullptr; -const AvCodecLib* FFmpegRuntimeLinker::sLib = nullptr; +PRLibrary* FFmpegRuntimeLinker::sLinkedLib = nullptr; +const char* FFmpegRuntimeLinker::sLib = nullptr; +static unsigned (*avcodec_version)() = nullptr; #define AV_FUNC(func, ver) void (*func)(); + #define LIBAVCODEC_ALLVERSION #include "FFmpegFunctionList.h" #undef LIBAVCODEC_ALLVERSION @@ -63,10 +58,13 @@ FFmpegRuntimeLinker::Link() MOZ_ASSERT(NS_IsMainThread()); for (size_t i = 0; i < ArrayLength(sLibs); i++) { - const AvCodecLib* lib = &sLibs[i]; - sLinkedLib = dlopen(lib->Name, RTLD_NOW | RTLD_LOCAL); + const char* lib = sLibs[i]; + PRLibSpec lspec; + lspec.type = PR_LibSpec_Pathname; + lspec.value.pathname = lib; + sLinkedLib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL); if (sLinkedLib) { - if (Bind(lib->Name, lib->Version)) { + if (Bind(lib)) { sLib = lib; sLinkStatus = LinkStatus_SUCCEEDED; return true; @@ -78,7 +76,7 @@ FFmpegRuntimeLinker::Link() FFMPEG_LOG("H264/AAC codecs unsupported without ["); for (size_t i = 0; i < ArrayLength(sLibs); i++) { - FFMPEG_LOG("%s %s", i ? "," : "", sLibs[i].Name); + FFMPEG_LOG("%s %s", i ? "," : "", sLibs[i]); } FFMPEG_LOG(" ]\n"); @@ -89,12 +87,23 @@ FFmpegRuntimeLinker::Link() } /* static */ bool -FFmpegRuntimeLinker::Bind(const char* aLibName, uint32_t Version) +FFmpegRuntimeLinker::Bind(const char* aLibName) { + avcodec_version = (typeof(avcodec_version))PR_FindSymbol(sLinkedLib, + "avcodec_version"); + uint32_t major, minor; + if (!GetVersion(major, minor)) { + return false; + } + if (major > 55) { + // All major greater than 56 currently use the same ABI as 55. + major = 55; + } + #define LIBAVCODEC_ALLVERSION #define AV_FUNC(func, ver) \ - if (ver == 0 || ver == Version) { \ - if (!(func = (typeof(func))dlsym(sLinkedLib, #func))) { \ + if (ver == 0 || ver == major) { \ + if (!(func = (typeof(func))PR_FindSymbol(sLinkedLib, #func))) { \ FFMPEG_LOG("Couldn't load function " #func " from %s.", aLibName); \ return false; \ } \ @@ -111,7 +120,17 @@ FFmpegRuntimeLinker::CreateDecoderModule() if (!Link()) { return nullptr; } - RefPtr module = sLib->Factory(); + uint32_t major, minor; + if (!GetVersion(major, minor)) { + return nullptr; + } + + RefPtr module; + switch (major) { + case 53: module = FFmpegDecoderModule<53>::Create(); break; + case 54: module = FFmpegDecoderModule<54>::Create(); break; + default: module = FFmpegDecoderModule<55>::Create(); break; + } return module.forget(); } @@ -119,11 +138,24 @@ FFmpegRuntimeLinker::CreateDecoderModule() FFmpegRuntimeLinker::Unlink() { if (sLinkedLib) { - dlclose(sLinkedLib); + PR_UnloadLibrary(sLinkedLib); sLinkedLib = nullptr; sLib = nullptr; sLinkStatus = LinkStatus_INIT; + avcodec_version = nullptr; } } +/* static */ bool +FFmpegRuntimeLinker::GetVersion(uint32_t& aMajor, uint32_t& aMinor) +{ + if (!avcodec_version) { + return false; + } + uint32_t version = avcodec_version(); + aMajor = (version >> 16) & 0xff; + aMinor = (version >> 8) & 0xff; + return true; +} + } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h index 68e42f15ce64..435849b38490 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h @@ -10,23 +10,24 @@ #include "PlatformDecoderModule.h" #include +struct PRLibrary; + namespace mozilla { -struct AvCodecLib; - class FFmpegRuntimeLinker { public: static bool Link(); static void Unlink(); static already_AddRefed CreateDecoderModule(); + static bool GetVersion(uint32_t& aMajor, uint32_t& aMinor); private: - static void* sLinkedLib; - static const AvCodecLib* sLib; + static PRLibrary* sLinkedLib; + static const char* sLib; - static bool Bind(const char* aLibName, uint32_t Version); + static bool Bind(const char* aLibName); static enum LinkStatus { LinkStatus_INIT = 0,