Backed out changeset 4ab338518d02 (bug 1240995)
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 20 Jan 2016 16:10:46 +0100
changeset 280799 82dffdf91ce615d67a82f5097fc128e25476c0ba
parent 280798 655280c526b76cb70b7b7c2f64acd10348401a54
child 280800 1f7787efce874c9b735ce0d225498c8fd2beaf12
push id29922
push usercbook@mozilla.com
push dateThu, 21 Jan 2016 10:51:00 +0000
treeherdermozilla-central@977d78a8dd78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1240995
milestone46.0a1
backs out4ab338518d021d46de2198ef499d74a1bc77617b
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 4ab338518d02 (bug 1240995)
dom/media/platforms/PDMFactory.cpp
dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h
dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
dom/media/platforms/ffmpeg/FFmpegFunctionList.h
dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
dom/media/platforms/ffmpeg/FFmpegLibs.h
dom/media/platforms/ffmpeg/FFmpegLog.h
dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.h
dom/media/platforms/ffmpeg/moz.build
dom/media/platforms/moz.build
layout/build/nsLayoutStatics.cpp
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -53,16 +53,17 @@ bool PDMFactory::sGonkDecoderEnabled = f
 #endif
 #ifdef MOZ_WIDGET_ANDROID
 bool PDMFactory::sAndroidMCDecoderEnabled = false;
 bool PDMFactory::sAndroidMCDecoderPreferred = false;
 #endif
 bool PDMFactory::sGMPDecoderEnabled = false;
 #ifdef MOZ_FFVPX
 bool PDMFactory::sFFVPXDecoderEnabled = false;
+using namespace ffvpx;
 #endif
 #ifdef MOZ_FFMPEG
 bool PDMFactory::sFFmpegDecoderEnabled = false;
 #endif
 #ifdef XP_WIN
 bool PDMFactory::sWMFDecoderEnabled = false;
 #endif
 
@@ -118,20 +119,20 @@ PDMFactory::Init()
 
 #ifdef XP_WIN
   WMFDecoderModule::Init();
 #endif
 #ifdef MOZ_APPLEMEDIA
   AppleDecoderModule::Init();
 #endif
 #ifdef MOZ_FFVPX
-  FFVPXRuntimeLinker::Init();
+  FFVPXRuntimeLinker::Link();
 #endif
 #ifdef MOZ_FFMPEG
-  FFmpegRuntimeLinker::Init();
+  FFmpegRuntimeLinker::Link();
 #endif
   GMPDecoderModule::Init();
 }
 
 PDMFactory::PDMFactory()
 {
   CreatePDMs();
 }
--- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
@@ -1,28 +1,29 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "mozilla/TaskQueue.h"
 
+#include "FFmpegRuntimeLinker.h"
 #include "FFmpegAudioDecoder.h"
 #include "TimeUnits.h"
 
 #define MAX_CHANNELS 16
 
 namespace mozilla
 {
 
-FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(FFmpegLibWrapper* aLib,
+FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
   FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const AudioInfo& aConfig)
-  : FFmpegDataDecoder(aLib, aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
+  : FFmpegDataDecoder(aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
 {
   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
   // Use a new MediaByteBuffer as the object will be modified during initialization.
   mExtraData = new MediaByteBuffer;
   mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
@@ -38,19 +39,21 @@ void
 FFmpegAudioDecoder<LIBAV_VER>::InitCodecContext()
 {
   MOZ_ASSERT(mCodecContext);
   // We do not want to set this value to 0 as FFmpeg by default will
   // use the number of cores, which with our mozlibavutil get_cpu_count
   // isn't implemented.
   mCodecContext->thread_count = 1;
   // FFmpeg takes this as a suggestion for what format to use for audio samples.
+  uint32_t major, minor, micro;
+  FFmpegRuntimeLinker::GetVersion(major, minor, micro);
   // LibAV 0.8 produces rubbish float interleaved samples, request 16 bits audio.
   mCodecContext->request_sample_fmt =
-    (mLib->mVersion == 53) ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLT;
+    (major == 53) ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLT;
 }
 
 static UniquePtr<AudioDataValue[]>
 CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames)
 {
   MOZ_ASSERT(aNumChannels <= MAX_CHANNELS);
 
   auto audio = MakeUnique<AudioDataValue[]>(aNumChannels * aNumAFrames);
@@ -93,34 +96,34 @@ CopyAndPackAudio(AVFrame* aFrame, uint32
   return audio;
 }
 
 void
 FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   AVPacket packet;
-  mLib->av_init_packet(&packet);
+  AV_CALL(av_init_packet(&packet));
 
   packet.data = const_cast<uint8_t*>(aSample->Data());
   packet.size = aSample->Size();
 
   if (!PrepareFrame()) {
     NS_WARNING("FFmpeg audio decoder failed to allocate frame.");
     mCallback->Error();
     return;
   }
 
   int64_t samplePosition = aSample->mOffset;
   media::TimeUnit pts = media::TimeUnit::FromMicroseconds(aSample->mTime);
 
   while (packet.size > 0) {
     int decoded;
     int bytesConsumed =
-      mLib->avcodec_decode_audio4(mCodecContext, mFrame, &decoded, &packet);
+      AV_CALL(avcodec_decode_audio4(mCodecContext, mFrame, &decoded, &packet));
 
     if (bytesConsumed < 0) {
       NS_WARNING("FFmpeg audio decoder error.");
       mCallback->Error();
       return;
     }
 
     if (decoded) {
--- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h
@@ -2,31 +2,30 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __FFmpegAACDecoder_h__
 #define __FFmpegAACDecoder_h__
 
-#include "FFmpegLibWrapper.h"
 #include "FFmpegDataDecoder.h"
 
 namespace mozilla
 {
 
 template <int V> class FFmpegAudioDecoder
 {
 };
 
 template <>
 class FFmpegAudioDecoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
 {
 public:
-  FFmpegAudioDecoder(FFmpegLibWrapper* aLib, FlushableTaskQueue* aTaskQueue,
+  FFmpegAudioDecoder(FlushableTaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      const AudioInfo& aConfig);
   virtual ~FFmpegAudioDecoder();
 
   RefPtr<InitPromise> Init() override;
   nsresult Input(MediaRawData* aSample) override;
   void ProcessDrain() override;
   void InitCodecContext() override;
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
@@ -16,53 +16,50 @@
 #include "prsystem.h"
 
 namespace mozilla
 {
 
 bool FFmpegDataDecoder<LIBAV_VER>::sFFmpegInitDone = false;
 StaticMutex FFmpegDataDecoder<LIBAV_VER>::sMonitor;
 
-  FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(FFmpegLibWrapper* aLib,
-                                                  FlushableTaskQueue* aTaskQueue,
-                                                  MediaDataDecoderCallback* aCallback,
-                                                  AVCodecID aCodecID)
-  : mLib(aLib)
-  , mTaskQueue(aTaskQueue)
+FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(FlushableTaskQueue* aTaskQueue,
+                                                MediaDataDecoderCallback* aCallback,
+                                                AVCodecID aCodecID)
+  : mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
   , mCodecContext(nullptr)
   , mFrame(NULL)
   , mExtraData(nullptr)
   , mCodecID(aCodecID)
   , mMonitor("FFMpegaDataDecoder")
   , mIsFlushing(false)
 {
-  MOZ_ASSERT(aLib);
   MOZ_COUNT_CTOR(FFmpegDataDecoder);
 }
 
 FFmpegDataDecoder<LIBAV_VER>::~FFmpegDataDecoder()
 {
   MOZ_COUNT_DTOR(FFmpegDataDecoder);
 }
 
 nsresult
 FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
 {
   FFMPEG_LOG("Initialising FFmpeg decoder.");
 
-  AVCodec* codec = FindAVCodec(mLib, mCodecID);
+  AVCodec* codec = FindAVCodec(mCodecID);
   if (!codec) {
     NS_WARNING("Couldn't find ffmpeg decoder");
     return NS_ERROR_FAILURE;
   }
 
   StaticMutexAutoLock mon(sMonitor);
 
-  if (!(mCodecContext = mLib->avcodec_alloc_context3(codec))) {
+  if (!(mCodecContext = AV_CALL(avcodec_alloc_context3(codec)))) {
     NS_WARNING("Couldn't init ffmpeg context");
     return NS_ERROR_FAILURE;
   }
 
   mCodecContext->opaque = this;
 
   InitCodecContext();
 
@@ -75,20 +72,20 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecode
   } else {
     mCodecContext->extradata_size = 0;
   }
 
   if (codec->capabilities & CODEC_CAP_DR1) {
     mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
   }
 
-  if (mLib->avcodec_open2(mCodecContext, codec, nullptr) < 0) {
+  if (AV_CALL(avcodec_open2(mCodecContext, codec, nullptr)) < 0) {
     NS_WARNING("Couldn't initialise ffmpeg decoder");
-    mLib->avcodec_close(mCodecContext);
-    mLib->av_freep(&mCodecContext);
+    AV_CALL(avcodec_close(mCodecContext));
+    AV_CALL(av_freep(&mCodecContext));
     return NS_ERROR_FAILURE;
   }
 
   if (mCodecContext->codec_type == AVMEDIA_TYPE_AUDIO &&
       mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT &&
       mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLTP &&
       mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16 &&
       mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16P) {
@@ -139,66 +136,73 @@ FFmpegDataDecoder<LIBAV_VER>::Drain()
   return NS_OK;
 }
 
 void
 FFmpegDataDecoder<LIBAV_VER>::ProcessFlush()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   if (mCodecContext) {
-    mLib->avcodec_flush_buffers(mCodecContext);
+    AV_CALL(avcodec_flush_buffers(mCodecContext));
   }
   MonitorAutoLock mon(mMonitor);
   mIsFlushing = false;
   mon.NotifyAll();
 }
 
 void
 FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown()
 {
   StaticMutexAutoLock mon(sMonitor);
 
   if (sFFmpegInitDone && mCodecContext) {
-    mLib->avcodec_close(mCodecContext);
-    mLib->av_freep(&mCodecContext);
+    AV_CALL(avcodec_close(mCodecContext));
+    AV_CALL(av_freep(&mCodecContext));
 #if LIBAVCODEC_VERSION_MAJOR >= 55
-    mLib->av_frame_free(&mFrame);
+    AV_CALL(av_frame_free(&mFrame));
 #elif LIBAVCODEC_VERSION_MAJOR == 54
-    mLib->avcodec_free_frame(&mFrame);
+    AV_CALL(avcodec_free_frame(&mFrame));
 #else
     delete mFrame;
     mFrame = nullptr;
 #endif
   }
 }
 
 AVFrame*
 FFmpegDataDecoder<LIBAV_VER>::PrepareFrame()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
 #if LIBAVCODEC_VERSION_MAJOR >= 55
   if (mFrame) {
-    mLib->av_frame_unref(mFrame);
+    AV_CALL(av_frame_unref(mFrame));
   } else {
-    mFrame = mLib->av_frame_alloc();
+    mFrame = AV_CALL(av_frame_alloc());
   }
 #elif LIBAVCODEC_VERSION_MAJOR == 54
   if (mFrame) {
-    mLib->avcodec_get_frame_defaults(mFrame);
+    AV_CALL(avcodec_get_frame_defaults(mFrame));
   } else {
-    mFrame = mLib->avcodec_alloc_frame();
+    mFrame = AV_CALL(avcodec_alloc_frame());
   }
 #else
   delete mFrame;
   mFrame = new AVFrame;
-  mLib->avcodec_get_frame_defaults(mFrame);
+  AV_CALL(avcodec_get_frame_defaults(mFrame));
 #endif
   return mFrame;
 }
 
 /* static */ AVCodec*
-FFmpegDataDecoder<LIBAV_VER>::FindAVCodec(FFmpegLibWrapper* aLib,
-                                          AVCodecID aCodec)
+FFmpegDataDecoder<LIBAV_VER>::FindAVCodec(AVCodecID aCodec)
 {
-  return aLib->avcodec_find_decoder(aCodec);
+  StaticMutexAutoLock mon(sMonitor);
+  if (!sFFmpegInitDone) {
+    AV_CALL(avcodec_register_all());
+#ifdef DEBUG
+    AV_CALL(av_log_set_level(AV_LOG_DEBUG));
+#endif
+    sFFmpegInitDone = true;
+  }
+  return AV_CALL(avcodec_find_decoder(aCodec));
 }
-
+  
 } // namespace mozilla
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
@@ -3,57 +3,56 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __FFmpegDataDecoder_h__
 #define __FFmpegDataDecoder_h__
 
 #include "PlatformDecoderModule.h"
-#include "FFmpegLibWrapper.h"
+#include "FFmpegLibs.h"
+#include "FFmpegRuntimeLinker.h"
 #include "mozilla/StaticMutex.h"
-#include "FFmpegLibs.h"
 
 namespace mozilla
 {
 
 template <int V>
 class FFmpegDataDecoder : public MediaDataDecoder
 {
 };
 
 template <>
 class FFmpegDataDecoder<LIBAV_VER> : public MediaDataDecoder
 {
 public:
-  FFmpegDataDecoder(FFmpegLibWrapper* aLib, FlushableTaskQueue* aTaskQueue,
+  FFmpegDataDecoder(FlushableTaskQueue* aTaskQueue,
                     MediaDataDecoderCallback* aCallback,
                     AVCodecID aCodecID);
   virtual ~FFmpegDataDecoder();
 
   static bool Link();
 
   RefPtr<InitPromise> Init() override = 0;
   nsresult Input(MediaRawData* aSample) override = 0;
   nsresult Flush() override;
   nsresult Drain() override;
   nsresult Shutdown() override;
 
-  static AVCodec* FindAVCodec(FFmpegLibWrapper* aLib, AVCodecID aCodec);
+  static AVCodec* FindAVCodec(AVCodecID aCodec);
 
 protected:
   // Flush and Drain operation, always run
   virtual void ProcessFlush();
   virtual void ProcessDrain() = 0;
   virtual void ProcessShutdown();
   virtual void InitCodecContext() {}
   AVFrame*        PrepareFrame();
   nsresult        InitDecoder();
 
-  FFmpegLibWrapper* mLib;
   RefPtr<FlushableTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 
   AVCodecContext* mCodecContext;
   AVFrame*        mFrame;
   RefPtr<MediaByteBuffer> mExtraData;
   AVCodecID mCodecID;
 
--- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
+++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
@@ -3,91 +3,88 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __FFmpegDecoderModule_h__
 #define __FFmpegDecoderModule_h__
 
 #include "PlatformDecoderModule.h"
-#include "FFmpegLibWrapper.h"
 #include "FFmpegAudioDecoder.h"
 #include "FFmpegVideoDecoder.h"
 
 namespace mozilla
 {
 
 template <int V>
 class FFmpegDecoderModule : public PlatformDecoderModule
 {
 public:
   static already_AddRefed<PlatformDecoderModule>
-  Create(FFmpegLibWrapper* aLib)
+  Create()
   {
-    RefPtr<PlatformDecoderModule> pdm = new FFmpegDecoderModule(aLib);
+    RefPtr<PlatformDecoderModule> pdm = new FFmpegDecoderModule();
 
     return pdm.forget();
   }
 
-  FFmpegDecoderModule(FFmpegLibWrapper* aLib) : mLib(aLib) {}
+  FFmpegDecoderModule() {}
   virtual ~FFmpegDecoderModule() {}
 
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
                      FlushableTaskQueue* aVideoTaskQueue,
                      MediaDataDecoderCallback* aCallback) override
   {
     RefPtr<MediaDataDecoder> decoder =
-      new FFmpegVideoDecoder<V>(mLib, aVideoTaskQueue, aCallback, aConfig,
+      new FFmpegVideoDecoder<V>(aVideoTaskQueue, aCallback, aConfig,
                                 aImageContainer);
     return decoder.forget();
   }
 
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
                      FlushableTaskQueue* aAudioTaskQueue,
                      MediaDataDecoderCallback* aCallback) override
   {
 #ifdef USING_MOZFFVPX
     return nullptr;
 #else
     RefPtr<MediaDataDecoder> decoder =
-      new FFmpegAudioDecoder<V>(mLib, aAudioTaskQueue, aCallback, aConfig);
+      new FFmpegAudioDecoder<V>(aAudioTaskQueue, aCallback, aConfig);
     return decoder.forget();
 #endif
   }
 
   bool SupportsMimeType(const nsACString& aMimeType) const override
   {
 #ifdef USING_MOZFFVPX
     AVCodecID audioCodec = AV_CODEC_ID_NONE;
 #else
     AVCodecID audioCodec = FFmpegAudioDecoder<V>::GetCodecId(aMimeType);
 #endif
     AVCodecID videoCodec = FFmpegVideoDecoder<V>::GetCodecId(aMimeType);
     if (audioCodec == AV_CODEC_ID_NONE && videoCodec == AV_CODEC_ID_NONE) {
       return false;
     }
     AVCodecID codec = audioCodec != AV_CODEC_ID_NONE ? audioCodec : videoCodec;
-    return !!FFmpegDataDecoder<V>::FindAVCodec(mLib, codec);
+    return !!FFmpegDataDecoder<V>::FindAVCodec(codec);
   }
 
   ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override
   {
     if (aConfig.IsVideo() &&
         (aConfig.mMimeType.EqualsLiteral("video/avc") ||
          aConfig.mMimeType.EqualsLiteral("video/mp4"))) {
       return PlatformDecoderModule::kNeedAVCC;
     } else {
       return kNeedNone;
     }
   }
 
-private:
-  FFmpegLibWrapper* mLib;
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegDecoderModule_h__
new file mode 100644
--- /dev/null
+++ b/dom/media/platforms/ffmpeg/FFmpegFunctionList.h
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+/* libavcodec */
+AV_FUNC(avcodec_alloc_context3, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(avcodec_close, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(avcodec_decode_audio4, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(avcodec_decode_video2, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(avcodec_find_decoder, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(avcodec_flush_buffers, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(avcodec_open2, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(avcodec_register_all, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(av_init_packet, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(av_parser_init, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(av_parser_close, AV_FUNC_AVCODEC_ALL)
+AV_FUNC(av_parser_parse2, AV_FUNC_AVCODEC_ALL)
+#if LIBAVCODEC_VERSION_MAJOR <= 54 || defined(LIBAVCODEC_ALLVERSION)
+AV_FUNC(avcodec_get_frame_defaults, (AV_FUNC_53 | AV_FUNC_54))
+#endif
+
+/* libavutil */
+AV_FUNC(av_log_set_level, AV_FUNC_AVUTIL_ALL)
+AV_FUNC(av_malloc, AV_FUNC_AVUTIL_ALL)
+AV_FUNC(av_freep, AV_FUNC_AVUTIL_ALL)
+
+#if defined(LIBAVCODEC_VERSION_MAJOR) || defined(LIBAVCODEC_ALLVERSION)
+#if LIBAVCODEC_VERSION_MAJOR == 54 || defined(LIBAVCODEC_ALLVERSION)
+/* libavutil v54 only */
+AV_FUNC(avcodec_alloc_frame, AV_FUNC_AVUTIL_54)
+AV_FUNC(avcodec_free_frame, AV_FUNC_AVUTIL_54)
+#endif
+#if LIBAVCODEC_VERSION_MAJOR >= 55 || defined(LIBAVCODEC_ALLVERSION)
+/* libavutil v55 and later only */
+AV_FUNC(av_frame_alloc, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
+AV_FUNC(av_frame_free, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
+AV_FUNC(av_frame_unref, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
+#endif
+#endif
deleted file mode 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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 "FFmpegLibWrapper.h"
-#include "FFmpegLog.h"
-#include "mozilla/PodOperations.h"
-#include "mozilla/Types.h"
-#include "prlink.h"
-
-#define AV_LOG_DEBUG    48
-
-namespace mozilla
-{
-
-FFmpegLibWrapper::FFmpegLibWrapper()
-{
-  PodZero(this);
-}
-
-FFmpegLibWrapper::~FFmpegLibWrapper()
-{
-  Unlink();
-}
-
-bool
-FFmpegLibWrapper::Link()
-{
-  if (!mAVCodecLib || !mAVUtilLib) {
-    Unlink();
-    return false;
-  }
-
-  avcodec_version =
-    (decltype(avcodec_version))PR_FindSymbol(mAVCodecLib, "avcodec_version");
-  if (!avcodec_version) {
-    Unlink();
-    return false;
-  }
-  uint32_t version = avcodec_version();
-  mVersion = (version >> 16) & 0xff;
-  uint32_t micro = version & 0xff;
-  if (mVersion == 57 && micro != 100) {
-    // a micro version of 100 indicates that it's FFmpeg (as opposed to LibAV).
-    // Due to current AVCodecContext binary incompatibility we can only
-    // support FFmpeg 57 at this stage.
-    Unlink();
-    return false;
-  }
-
-  enum {
-    AV_FUNC_AVUTIL_MASK = 1 << 8,
-    AV_FUNC_53 = 1 << 0,
-    AV_FUNC_54 = 1 << 1,
-    AV_FUNC_55 = 1 << 2,
-    AV_FUNC_56 = 1 << 3,
-    AV_FUNC_57 = 1 << 4,
-    AV_FUNC_AVUTIL_53 = AV_FUNC_53 | AV_FUNC_AVUTIL_MASK,
-    AV_FUNC_AVUTIL_54 = AV_FUNC_54 | AV_FUNC_AVUTIL_MASK,
-    AV_FUNC_AVUTIL_55 = AV_FUNC_55 | AV_FUNC_AVUTIL_MASK,
-    AV_FUNC_AVUTIL_56 = AV_FUNC_56 | AV_FUNC_AVUTIL_MASK,
-    AV_FUNC_AVUTIL_57 = AV_FUNC_57 | AV_FUNC_AVUTIL_MASK,
-    AV_FUNC_AVCODEC_ALL = AV_FUNC_53 | AV_FUNC_54 | AV_FUNC_55 | AV_FUNC_56 | AV_FUNC_57,
-    AV_FUNC_AVUTIL_ALL = AV_FUNC_AVCODEC_ALL | AV_FUNC_AVUTIL_MASK
-  };
-
-  switch (mVersion) {
-    case 53:
-      version = AV_FUNC_53;
-      break;
-    case 54:
-      version = AV_FUNC_54;
-      break;
-    case 55:
-      version = AV_FUNC_55;
-      break;
-    case 56:
-      version = AV_FUNC_56;
-      break;
-    case 57:
-      version = AV_FUNC_57;
-      break;
-    default:
-      FFMPEG_LOG("Unknown avcodec version");
-      Unlink();
-      return false;
-  }
-
-#define AV_FUNC(func, ver)                                                     \
-  if ((ver) & version) {                                                      \
-    if (!(func = (decltype(func))PR_FindSymbol(((ver) & AV_FUNC_AVUTIL_MASK) ? mAVUtilLib : mAVCodecLib, #func))) { \
-      FFMPEG_LOG("Couldn't load function " # func);                            \
-      Unlink();                                                                \
-      return false;                                                            \
-    }                                                                          \
-  } else {                                                                     \
-    func = (decltype(func))nullptr;                                            \
-  }
-  AV_FUNC(avcodec_alloc_context3, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_close, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_decode_audio4, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_decode_video2, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_find_decoder, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_flush_buffers, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_open2, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_register_all, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(av_init_packet, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(av_parser_init, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(av_parser_close, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(av_parser_parse2, AV_FUNC_AVCODEC_ALL)
-  AV_FUNC(avcodec_get_frame_defaults, (AV_FUNC_53 | AV_FUNC_54))
-  AV_FUNC(av_log_set_level, AV_FUNC_AVUTIL_ALL)
-  AV_FUNC(av_malloc, AV_FUNC_AVUTIL_ALL)
-  AV_FUNC(av_freep, AV_FUNC_AVUTIL_ALL)
-  AV_FUNC(avcodec_alloc_frame, AV_FUNC_AVUTIL_54)
-  AV_FUNC(avcodec_free_frame, AV_FUNC_AVUTIL_54)
-  AV_FUNC(av_frame_alloc, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
-  AV_FUNC(av_frame_free, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
-  AV_FUNC(av_frame_unref, (AV_FUNC_AVUTIL_55 | AV_FUNC_AVUTIL_56 | AV_FUNC_AVUTIL_57))
-#undef AV_FUNC
-
-  avcodec_register_all();
-#ifdef DEBUG
-  av_log_set_level(AV_LOG_DEBUG);
-#endif
-
-  return true;
-}
-
-void
-FFmpegLibWrapper::Unlink()
-{
-  if (mAVUtilLib && mAVUtilLib != mAVCodecLib) {
-    PR_UnloadLibrary(mAVUtilLib);
-  }
-  if (mAVCodecLib) {
-    PR_UnloadLibrary(mAVCodecLib);
-  }
-  PodZero(this);
-}
-
-} // namespace mozilla
\ No newline at end of file
deleted file mode 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-#ifndef __FFmpegLibWrapper_h__
-#define __FFmpegLibWrapper_h__
-
-#include "mozilla/Types.h"
-
-struct AVCodec;
-struct AVCodecContext;
-struct AVFrame;
-struct AVPacket;
-struct AVDictionary;
-struct AVCodecParserContext;
-struct PRLibrary;
-
-namespace mozilla
-{
-
-struct FFmpegLibWrapper
-{
-  FFmpegLibWrapper();
-  ~FFmpegLibWrapper();
-
-  // Attempt to resolve all symbols. Return true of successful.
-  // Upon failure, the entire object will be reset and any attached libraries
-  // will be unlinked.
-  bool Link();
-
-  // Reset the wrapper and unlink all attached libraries.
-  void Unlink();
-
-  // indicate the version of libavcodec linked to.
-  // 0 indicates that the function wasn't initialized with Link().
-  int mVersion;
-
-  // libavcodec
-  unsigned (*avcodec_version)();
-  AVCodecContext* (*avcodec_alloc_context3)(const AVCodec* codec);
-  int (*avcodec_close)(AVCodecContext* avctx);
-  int (*avcodec_decode_audio4)(AVCodecContext* avctx, AVFrame* frame, int* got_frame_ptr, const AVPacket* avpkt);
-  int (*avcodec_decode_video2)(AVCodecContext* avctx, AVFrame* picture, int* got_picture_ptr, const AVPacket* avpkt);
-  AVCodec* (*avcodec_find_decoder)(int id);
-  void (*avcodec_flush_buffers)(AVCodecContext *avctx);
-  int (*avcodec_open2)(AVCodecContext *avctx, const AVCodec* codec, AVDictionary** options);
-  void (*avcodec_register_all)();
-  void (*av_init_packet)(AVPacket* pkt);
-  AVCodecParserContext* (*av_parser_init)(int codec_id);
-  void (*av_parser_close)(AVCodecParserContext* s);
-  int (*av_parser_parse2)(AVCodecParserContext* s, AVCodecContext* avctx, uint8_t** poutbuf, int* poutbuf_size, const uint8_t* buf, int buf_size, int64_t pts, int64_t dts, int64_t pos);
-
-  // only used in libavcodec <= 54
-  void (*avcodec_get_frame_defaults)(AVFrame* pic);
-
-  // libavutil
-  void (*av_log_set_level)(int level);
-  void*	(*av_malloc)(size_t size);
-  void (*av_freep)(void *ptr);
-
-  // libavutil v54 only
-  AVFrame* (*avcodec_alloc_frame)();
-  void (*avcodec_free_frame)(AVFrame** frame);
-
-  // libavutil v55 and later only
-  AVFrame* (*av_frame_alloc)();
-  void (*av_frame_free)(AVFrame** frame);
-  void (*av_frame_unref)(AVFrame* frame);
-
-  PRLibrary* mAVCodecLib;
-  PRLibrary* mAVUtilLib;
-
-private:
-};
-
-} // namespace mozilla
-
-#endif // FFmpegLibWrapper
\ No newline at end of file
--- a/dom/media/platforms/ffmpeg/FFmpegLibs.h
+++ b/dom/media/platforms/ffmpeg/FFmpegLibs.h
@@ -2,16 +2,18 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __FFmpegLibs_h__
 #define __FFmpegLibs_h__
 
+#include "mozilla/Types.h"
+
 extern "C" {
 #ifdef __GNUC__
 #pragma GCC visibility push(default)
 #endif
 #include "libavcodec/avcodec.h"
 #include "libavutil/avutil.h"
 #include "libavutil/mem.h"
 #ifdef __GNUC__
@@ -30,9 +32,28 @@ typedef CodecID AVCodecID;
 #endif
 
 #ifdef FFVPX_VERSION
 enum { LIBAV_VER = FFVPX_VERSION };
 #else
 enum { LIBAV_VER = LIBAVCODEC_VERSION_MAJOR };
 #endif
 
+namespace mozilla {
+
+#ifdef USING_MOZFFVPX
+namespace ffvpx {
+#endif
+
+#define AV_FUNC(func, ver) extern decltype(func)* func;
+#include "FFmpegFunctionList.h"
+#undef AV_FUNC
+
+#ifdef USING_MOZFFVPX
+} // namespace ffvpx
+#define AV_CALL(func) mozilla::ffvpx::func
+#else
+#define AV_CALL(func) mozilla::func
+#endif
+
+}
+
 #endif // __FFmpegLibs_h__
--- a/dom/media/platforms/ffmpeg/FFmpegLog.h
+++ b/dom/media/platforms/ffmpeg/FFmpegLog.h
@@ -2,14 +2,12 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __FFmpegLog_h__
 #define __FFmpegLog_h__
 
-#include "mozilla/Logging.h"
-
 extern mozilla::LogModule* GetPDMLog();
 #define FFMPEG_LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 #endif // __FFmpegLog_h__
--- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
@@ -1,34 +1,32 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "FFmpegRuntimeLinker.h"
-#include "FFmpegLibWrapper.h"
 #include "mozilla/ArrayUtils.h"
 #include "FFmpegLog.h"
+#include "mozilla/Types.h"
 #include "prlink.h"
 
 namespace mozilla
 {
 
 FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus =
   LinkStatus_INIT;
 
 template <int V> class FFmpegDecoderModule
 {
 public:
-  static already_AddRefed<PlatformDecoderModule> Create(FFmpegLibWrapper*);
+  static already_AddRefed<PlatformDecoderModule> Create();
 };
 
-static FFmpegLibWrapper sLibAV;
-
 static const char* sLibs[] = {
 #if defined(XP_DARWIN)
   "libavcodec.57.dylib",
   "libavcodec.56.dylib",
   "libavcodec.55.dylib",
   "libavcodec.54.dylib",
   "libavcodec.53.dylib",
 #else
@@ -37,60 +35,168 @@ static const char* sLibs[] = {
   "libavcodec.so.57",
   "libavcodec.so.56",
   "libavcodec.so.55",
   "libavcodec.so.54",
   "libavcodec.so.53",
 #endif
 };
 
+PRLibrary* FFmpegRuntimeLinker::sLinkedLib = nullptr;
+PRLibrary* FFmpegRuntimeLinker::sLinkedUtilLib = nullptr;
+static unsigned (*avcodec_version)() = nullptr;
+
+#ifdef __GNUC__
+#define AV_FUNC(func, ver) void (*func)();
+#define LIBAVCODEC_ALLVERSION
+#else
+#define AV_FUNC(func, ver) decltype(func)* func;
+#endif
+#include "FFmpegFunctionList.h"
+#undef AV_FUNC
+
+static PRLibrary*
+MozAVLink(const char* aName)
+{
+  PRLibSpec lspec;
+  lspec.type = PR_LibSpec_Pathname;
+  lspec.value.pathname = aName;
+  return PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
+}
+
 /* static */ bool
-FFmpegRuntimeLinker::Init()
+FFmpegRuntimeLinker::Link()
 {
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
   MOZ_ASSERT(NS_IsMainThread());
 
   for (size_t i = 0; i < ArrayLength(sLibs); i++) {
     const char* lib = sLibs[i];
-    PRLibSpec lspec;
-    lspec.type = PR_LibSpec_Pathname;
-    lspec.value.pathname = lib;
-    sLibAV.mAVCodecLib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-    if (sLibAV.mAVCodecLib) {
-      sLibAV.mAVUtilLib = sLibAV.mAVCodecLib;
-      if (sLibAV.Link()) {
+    sLinkedLib = MozAVLink(lib);
+    if (sLinkedLib) {
+      sLinkedUtilLib = sLinkedLib;
+      if (Bind(lib)) {
         sLinkStatus = LinkStatus_SUCCEEDED;
         return true;
       }
+      // Shouldn't happen but if it does then we try the next lib..
+      Unlink();
     }
   }
 
   FFMPEG_LOG("H264/AAC codecs unsupported without [");
   for (size_t i = 0; i < ArrayLength(sLibs); i++) {
     FFMPEG_LOG("%s %s", i ? "," : "", sLibs[i]);
   }
   FFMPEG_LOG(" ]\n");
 
+  Unlink();
+
   sLinkStatus = LinkStatus_FAILED;
   return false;
 }
 
+/* static */ bool
+FFmpegRuntimeLinker::Bind(const char* aLibName)
+{
+  avcodec_version = (decltype(avcodec_version))PR_FindSymbol(sLinkedLib,
+                                                           "avcodec_version");
+  uint32_t major, minor, micro;
+  if (!GetVersion(major, minor, micro)) {
+    return false;
+  }
+
+  int version;
+  switch (major) {
+    case 53:
+      version = AV_FUNC_53;
+      break;
+    case 54:
+      version = AV_FUNC_54;
+      break;
+    case 56:
+      // We use libavcodec 55 code instead. Fallback
+    case 55:
+      version = AV_FUNC_55;
+      break;
+    case 57:
+      if (micro != 100) {
+        // a micro version of 100 indicates that it's FFmpeg (as opposed to LibAV.
+        // Due to current AVCodecContext binary incompatibility we can only
+        // support FFmpeg at this stage.
+        return false;
+      }
+      version = AV_FUNC_57;
+      break;
+    default:
+      // Not supported at this stage.
+      return false;
+  }
+
+#define AV_FUNC(func, ver)                                                     \
+  if ((ver) & version) {                                                       \
+    if (!(func = (decltype(func))PR_FindSymbol(((ver) & AV_FUNC_AVUTIL_MASK) ? sLinkedUtilLib : sLinkedLib, #func))) { \
+      FFMPEG_LOG("Couldn't load function " #func " from %s.", aLibName);       \
+      return false;                                                            \
+    }                                                                          \
+  } else {                                                                     \
+    func = (decltype(func))nullptr;                                            \
+  }
+#include "FFmpegFunctionList.h"
+#undef AV_FUNC
+  return true;
+}
+
 /* static */ already_AddRefed<PlatformDecoderModule>
 FFmpegRuntimeLinker::CreateDecoderModule()
 {
-  if (!Init()) {
+  if (!Link()) {
     return nullptr;
   }
+  uint32_t major, minor, micro;
+  if (!GetVersion(major, minor, micro)) {
+    return  nullptr;
+  }
+
   RefPtr<PlatformDecoderModule> module;
-  switch (sLibAV.mVersion) {
-    case 53: module = FFmpegDecoderModule<53>::Create(&sLibAV); break;
-    case 54: module = FFmpegDecoderModule<54>::Create(&sLibAV); break;
+  switch (major) {
+    case 53: module = FFmpegDecoderModule<53>::Create(); break;
+    case 54: module = FFmpegDecoderModule<54>::Create(); break;
     case 55:
-    case 56: module = FFmpegDecoderModule<55>::Create(&sLibAV); break;
-    case 57: module = FFmpegDecoderModule<57>::Create(&sLibAV); break;
+    case 56: module = FFmpegDecoderModule<55>::Create(); break;
+    case 57: module = FFmpegDecoderModule<57>::Create(); break;
     default: module = nullptr;
   }
   return module.forget();
 }
 
+/* static */ void
+FFmpegRuntimeLinker::Unlink()
+{
+  if (sLinkedUtilLib && sLinkedUtilLib != sLinkedLib) {
+    PR_UnloadLibrary(sLinkedUtilLib);
+  }
+  if (sLinkedLib) {
+    PR_UnloadLibrary(sLinkedLib);
+    sLinkedLib = nullptr;
+    sLinkStatus = LinkStatus_INIT;
+    avcodec_version = nullptr;
+  }
+  sLinkedUtilLib = nullptr;
+}
+
+/* static */ bool
+FFmpegRuntimeLinker::GetVersion(uint32_t& aMajor, uint32_t& aMinor, uint32_t& aMicro)
+{
+  if (!avcodec_version) {
+    return false;
+  }
+  uint32_t version = avcodec_version();
+  aMajor = (version >> 16) & 0xff;
+  aMinor = (version >> 8) & 0xff;
+  aMicro = version & 0xff;
+  return true;
+}
+
+#undef LIBAVCODEC_ALLVERSION
 } // namespace mozilla
--- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h
+++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h
@@ -3,27 +3,53 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __FFmpegRuntimeLinker_h__
 #define __FFmpegRuntimeLinker_h__
 
 #include "PlatformDecoderModule.h"
+#include <stdint.h>
+
+struct PRLibrary;
 
 namespace mozilla
 {
 
+enum {
+  AV_FUNC_AVUTIL_MASK = 1 << 8,
+  AV_FUNC_53 = 1 << 0,
+  AV_FUNC_54 = 1 << 1,
+  AV_FUNC_55 = 1 << 2,
+  AV_FUNC_56 = 1 << 3,
+  AV_FUNC_57 = 1 << 4,
+  AV_FUNC_AVUTIL_53 = AV_FUNC_53 | AV_FUNC_AVUTIL_MASK,
+  AV_FUNC_AVUTIL_54 = AV_FUNC_54 | AV_FUNC_AVUTIL_MASK,
+  AV_FUNC_AVUTIL_55 = AV_FUNC_55 | AV_FUNC_AVUTIL_MASK,
+  AV_FUNC_AVUTIL_56 = AV_FUNC_56 | AV_FUNC_AVUTIL_MASK,
+  AV_FUNC_AVUTIL_57 = AV_FUNC_57 | AV_FUNC_AVUTIL_MASK,
+  AV_FUNC_AVCODEC_ALL = AV_FUNC_53 | AV_FUNC_54 | AV_FUNC_55 | AV_FUNC_56 | AV_FUNC_57,
+  AV_FUNC_AVUTIL_ALL = AV_FUNC_AVCODEC_ALL | AV_FUNC_AVUTIL_MASK
+};
+
 class FFmpegRuntimeLinker
 {
 public:
-  static bool Init();
+  static bool Link();
+  static void Unlink();
   static already_AddRefed<PlatformDecoderModule> CreateDecoderModule();
+  static bool GetVersion(uint32_t& aMajor, uint32_t& aMinor, uint32_t& aMicro);
 
 private:
+  static PRLibrary* sLinkedLib;
+  static PRLibrary* sLinkedUtilLib;
+
+  static bool Bind(const char* aLibName);
+
   static enum LinkStatus {
     LinkStatus_INIT = 0,
     LinkStatus_FAILED,
     LinkStatus_SUCCEEDED
   } sLinkStatus;
 };
 
 }
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -93,21 +93,21 @@ void
 FFmpegVideoDecoder<LIBAV_VER>::PtsCorrectionContext::Reset()
 {
   mNumFaultyPts = 0;
   mNumFaultyDts = 0;
   mLastPts = INT64_MIN;
   mLastDts = INT64_MIN;
 }
 
-FFmpegVideoDecoder<LIBAV_VER>::FFmpegVideoDecoder(FFmpegLibWrapper* aLib,
+FFmpegVideoDecoder<LIBAV_VER>::FFmpegVideoDecoder(
   FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const VideoInfo& aConfig,
   ImageContainer* aImageContainer)
-  : FFmpegDataDecoder(aLib, aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
+  : FFmpegDataDecoder(aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
   , mImageContainer(aImageContainer)
   , mDisplay(aConfig.mDisplay)
   , mImage(aConfig.mImage)
   , mCodecParser(nullptr)
 {
   MOZ_COUNT_CTOR(FFmpegVideoDecoder);
   // Use a new MediaByteBuffer as the object will be modified during initialization.
   mExtraData = new MediaByteBuffer;
@@ -146,17 +146,17 @@ FFmpegVideoDecoder<LIBAV_VER>::InitCodec
   mCodecContext->thread_count = decode_threads;
   if (decode_threads > 1) {
     mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
   }
 
   // FFmpeg will call back to this to negotiate a video pixel format.
   mCodecContext->get_format = ChoosePixelFormat;
 
-  mCodecParser = mLib->av_parser_init(mCodecID);
+  mCodecParser = AV_CALL(av_parser_init(mCodecID));
   if (mCodecParser) {
     mCodecParser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
   }
 }
 
 FFmpegVideoDecoder<LIBAV_VER>::DecodeResult
 FFmpegVideoDecoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
 {
@@ -170,20 +170,20 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecodeF
 #if LIBAVCODEC_VERSION_MAJOR >= 55
       || mCodecID == AV_CODEC_ID_VP9
 #endif
       )) {
     bool gotFrame = false;
     while (inputSize) {
       uint8_t* data;
       int size;
-      int len = mLib->av_parser_parse2(mCodecParser, mCodecContext, &data, &size,
-                                       inputData, inputSize,
-                                       aSample->mTime, aSample->mTimecode,
-                                       aSample->mOffset);
+      int len = AV_CALL(av_parser_parse2(mCodecParser, mCodecContext, &data, &size,
+                                         inputData, inputSize,
+                                         aSample->mTime, aSample->mTimecode,
+                                         aSample->mOffset));
       if (size_t(len) > inputSize) {
         mCallback->Error();
         return DecodeResult::DECODE_ERROR;
       }
       inputData += len;
       inputSize -= len;
       if (size) {
         switch (DoDecodeFrame(aSample, data, size)) {
@@ -205,17 +205,17 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecodeF
 
 FFmpegVideoDecoder<LIBAV_VER>::DecodeResult
 FFmpegVideoDecoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
                                             uint8_t* aData, int aSize)
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
 
   AVPacket packet;
-  mLib->av_init_packet(&packet);
+  AV_CALL(av_init_packet(&packet));
 
   packet.data = aData;
   packet.size = aSize;
   packet.dts = aSample->mTimecode;
   packet.pts = aSample->mTime;
   packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0;
   packet.pos = aSample->mOffset;
 
@@ -232,17 +232,17 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecodeF
     return DecodeResult::DECODE_ERROR;
   }
 
   // Required with old version of FFmpeg/LibAV
   mFrame->reordered_opaque = AV_NOPTS_VALUE;
 
   int decoded;
   int bytesConsumed =
-    mLib->avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet);
+    AV_CALL(avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet));
 
   FFMPEG_LOG("DoDecodeFrame:decode_video: rv=%d decoded=%d "
              "(Input: pts(%lld) dts(%lld) Output: pts(%lld) "
              "opaque(%lld) pkt_pts(%lld) pkt_dts(%lld))",
              bytesConsumed, decoded, packet.pts, packet.dts, mFrame->pts,
              mFrame->reordered_opaque, mFrame->pkt_pts, mFrame->pkt_dts);
 
   if (bytesConsumed < 0) {
@@ -356,17 +356,17 @@ FFmpegVideoDecoder<LIBAV_VER>::ProcessFl
   mDurationMap.Clear();
   FFmpegDataDecoder::ProcessFlush();
 }
 
 FFmpegVideoDecoder<LIBAV_VER>::~FFmpegVideoDecoder()
 {
   MOZ_COUNT_DTOR(FFmpegVideoDecoder);
   if (mCodecParser) {
-    mLib->av_parser_close(mCodecParser);
+    AV_CALL(av_parser_close(mCodecParser));
     mCodecParser = nullptr;
   }
 }
 
 AVCodecID
 FFmpegVideoDecoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
 {
   if (aMimeType.EqualsLiteral("video/avc") || aMimeType.EqualsLiteral("video/mp4")) {
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
@@ -2,17 +2,16 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __FFmpegVideoDecoder_h__
 #define __FFmpegVideoDecoder_h__
 
-#include "FFmpegLibWrapper.h"
 #include "FFmpegDataDecoder.h"
 #include "mozilla/Pair.h"
 #include "nsTArray.h"
 
 namespace mozilla
 {
 
 template <int V>
@@ -28,20 +27,20 @@ class FFmpegVideoDecoder<LIBAV_VER> : pu
 
   enum DecodeResult {
     DECODE_FRAME,
     DECODE_NO_FRAME,
     DECODE_ERROR
   };
 
 public:
-  FFmpegVideoDecoder(FFmpegLibWrapper* aLib, FlushableTaskQueue* aTaskQueue,
-                     MediaDataDecoderCallback* aCallback,
-                     const VideoInfo& aConfig,
-                     ImageContainer* aImageContainer);
+  FFmpegVideoDecoder(FlushableTaskQueue* aTaskQueue,
+                    MediaDataDecoderCallback* aCallback,
+                    const VideoInfo& aConfig,
+                    ImageContainer* aImageContainer);
   virtual ~FFmpegVideoDecoder();
 
   RefPtr<InitPromise> Init() override;
   nsresult Input(MediaRawData* aSample) override;
   void ProcessDrain() override;
   void ProcessFlush() override;
   void InitCodecContext() override;
   static AVCodecID GetCodecId(const nsACString& aMimeType);
--- a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
@@ -1,58 +1,78 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "FFVPXRuntimeLinker.h"
-#include "FFmpegLibWrapper.h"
+#include "FFmpegRuntimeLinker.h"
 #include "FFmpegLog.h"
+#include "mozilla/Types.h"
 #include "nsIFile.h"
 #include "nsXPCOMPrivate.h" // for XUL_DLL
 #include "prmem.h"
 #include "prlink.h"
 
+#if defined(XP_WIN)
+#include "libavcodec/avcodec.h"
+#include "libavutil/avutil.h"
+#endif
+
 namespace mozilla
 {
 
 template <int V> class FFmpegDecoderModule
 {
 public:
-  static already_AddRefed<PlatformDecoderModule> Create(FFmpegLibWrapper*);
+  static already_AddRefed<PlatformDecoderModule> Create();
 };
 
-static FFmpegLibWrapper sFFVPXLib;
+namespace ffvpx
+{
 
 FFVPXRuntimeLinker::LinkStatus FFVPXRuntimeLinker::sLinkStatus =
   LinkStatus_INIT;
 
+PRLibrary* FFVPXRuntimeLinker::sLinkedLib = nullptr;
+PRLibrary* FFVPXRuntimeLinker::sLinkedUtilLib = nullptr;
+static unsigned (*avcodec_version)() = nullptr;
+
+#ifdef __GNUC__
+#define AV_FUNC(func, ver) void (*func)();
+#define LIBAVCODEC_ALLVERSION
+#else
+#define AV_FUNC(func, ver) decltype(func)* func;
+#endif
+#include "FFmpegFunctionList.h"
+#undef AV_FUNC
+
 static PRLibrary*
 MozAVLink(const char* aName)
 {
   PRLibSpec lspec;
   lspec.type = PR_LibSpec_Pathname;
   lspec.value.pathname = aName;
   return PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
 }
 
 /* static */ bool
-FFVPXRuntimeLinker::Init()
+FFVPXRuntimeLinker::Link()
 {
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
   MOZ_ASSERT(NS_IsMainThread());
 
   // We retrieve the path of the XUL library as this is where mozavcodec and
   // mozavutil libs are located.
   char* path =
-    PR_GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Init);
+    PR_GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Link);
   if (!path) {
     return false;
   }
   nsCOMPtr<nsIFile> xulFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
   if (!xulFile ||
       NS_FAILED(xulFile->InitWithNativePath(nsDependentCString(path)))) {
     PR_Free(path);
     return false;
@@ -69,34 +89,74 @@ FFVPXRuntimeLinker::Init()
   }
 
   char* libname = NULL;
   /* Get the platform-dependent library name of the module */
   libname = PR_GetLibraryName(rootPath.get(), "mozavutil");
   if (!libname) {
     return false;
   }
-  sFFVPXLib.mAVUtilLib = MozAVLink(libname);
+  sLinkedUtilLib = MozAVLink(libname);
   PR_FreeLibraryName(libname);
   libname = PR_GetLibraryName(rootPath.get(), "mozavcodec");
   if (libname) {
-    sFFVPXLib.mAVCodecLib = MozAVLink(libname);
+    sLinkedLib = MozAVLink(libname);
     PR_FreeLibraryName(libname);
+    if (sLinkedLib && sLinkedUtilLib) {
+      if (Bind("mozavcodec")) {
+        sLinkStatus = LinkStatus_SUCCEEDED;
+        return true;
+      }
+    }
   }
-  if (sFFVPXLib.Link()) {
-    sLinkStatus = LinkStatus_SUCCEEDED;
-    return true;
+
+  Unlink();
+
+  sLinkStatus = LinkStatus_FAILED;
+  return false;
+}
+
+/* static */ bool
+FFVPXRuntimeLinker::Bind(const char* aLibName)
+{
+  int version = AV_FUNC_57;
+
+#define AV_FUNC(func, ver)                                                     \
+  if ((ver) & version) {                                                       \
+    if (!(func = (decltype(func))PR_FindSymbol(((ver) & AV_FUNC_AVUTIL_MASK) ? sLinkedUtilLib : sLinkedLib, #func))) { \
+      FFMPEG_LOG("Couldn't load function " #func " from %s.", aLibName);       \
+      return false;                                                            \
+    }                                                                          \
+  } else {                                                                     \
+    func = (decltype(func))nullptr;                                            \
   }
-  sLinkStatus = LinkStatus_FAILED;
-
-  return false;
+#include "FFmpegFunctionList.h"
+#undef AV_FUNC
+  return true;
 }
 
 /* static */ already_AddRefed<PlatformDecoderModule>
 FFVPXRuntimeLinker::CreateDecoderModule()
 {
-  if (!Init()) {
+  if (!Link()) {
     return nullptr;
   }
-  return FFmpegDecoderModule<FFVPX_VERSION>::Create(&sFFVPXLib);
+  return FFmpegDecoderModule<FFVPX_VERSION>::Create();
 }
 
+/* static */ void
+FFVPXRuntimeLinker::Unlink()
+{
+  if (sLinkedUtilLib && sLinkedUtilLib != sLinkedLib) {
+    PR_UnloadLibrary(sLinkedUtilLib);
+  }
+  if (sLinkedLib) {
+    PR_UnloadLibrary(sLinkedLib);
+    sLinkedLib = nullptr;
+    sLinkStatus = LinkStatus_INIT;
+    avcodec_version = nullptr;
+  }
+  sLinkedUtilLib = nullptr;
+}
+
+#undef LIBAVCODEC_ALLVERSION
+} // namespace ffvpx
 } // namespace mozilla
--- a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.h
+++ b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.h
@@ -4,28 +4,40 @@
  * 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/. */
 
 #ifndef __FFVPXRuntimeLinker_h__
 #define __FFVPXRuntimeLinker_h__
 
 #include "PlatformDecoderModule.h"
 
+struct PRLibrary;
+
 namespace mozilla
 {
+namespace ffvpx
+{
 
 class FFVPXRuntimeLinker
 {
 public:
-  static bool Init();
+  static bool Link();
+  static void Unlink();
   static already_AddRefed<PlatformDecoderModule> CreateDecoderModule();
 
 private:
+  static PRLibrary* sLinkedLib;
+  static PRLibrary* sLinkedUtilLib;
   static enum LinkStatus {
     LinkStatus_INIT = 0,
     LinkStatus_FAILED,
     LinkStatus_SUCCEEDED
   } sLinkStatus;
+
+  static bool Bind(const char* aLibName);
+
 };
 
 }
+}
+
 
 #endif /* __FFVPXRuntimeLinker_h__ */
deleted file mode 100644
--- a/dom/media/platforms/ffmpeg/moz.build
+++ /dev/null
@@ -1,22 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# 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/.
-
-EXPORTS += [
-    'FFmpegRuntimeLinker.h',
-]
-
-DIRS += [
-    'libav53',
-    'libav54',
-    'libav55',
-    'ffmpeg57',
-]
-
-UNIFIED_SOURCES += [
-    'FFmpegRuntimeLinker.cpp',
-]
-
-FINAL_LIBRARY = 'xul'
--- a/dom/media/platforms/moz.build
+++ b/dom/media/platforms/moz.build
@@ -33,30 +33,33 @@ DIRS += [
 ]
 
 if CONFIG['MOZ_WMF']:
     DIRS += [ 'wmf' ];
 
 if CONFIG['MOZ_EME']:
     DIRS += ['agnostic/eme']
 
-if CONFIG['MOZ_FFVPX'] or CONFIG['MOZ_FFMPEG']:
-    # common code to either FFmpeg or FFVPX
-    UNIFIED_SOURCES += [
-        'ffmpeg/FFmpegLibWrapper.cpp',
-    ]
-
 if CONFIG['MOZ_FFVPX']:
     DIRS += [
         'ffmpeg/ffvpx',
     ]
 
 if CONFIG['MOZ_FFMPEG']:
+    EXPORTS += [
+        'ffmpeg/FFmpegRuntimeLinker.h',
+    ]
+    UNIFIED_SOURCES += [
+        'ffmpeg/FFmpegRuntimeLinker.cpp',
+    ]
     DIRS += [
-        'ffmpeg',
+        'ffmpeg/libav53',
+        'ffmpeg/libav54',
+        'ffmpeg/libav55',
+        'ffmpeg/ffmpeg57',
     ]
 
 if CONFIG['MOZ_APPLEMEDIA']:
   EXPORTS += [
       'apple/AppleDecoderModule.h',
   ]
   UNIFIED_SOURCES += [
       'apple/AppleATDecoder.cpp',
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -92,16 +92,20 @@
 #ifdef MOZ_WEBSPEECH
 #include "nsSynthVoiceRegistry.h"
 #endif
 
 #ifdef MOZ_ANDROID_OMX
 #include "AndroidMediaPluginHost.h"
 #endif
 
+#ifdef MOZ_FFMPEG
+#include "FFmpegRuntimeLinker.h"
+#endif
+
 #include "CubebUtils.h"
 #include "Latency.h"
 #include "WebAudioUtils.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsVolumeService.h"
 using namespace mozilla::system;
 #endif
@@ -385,16 +389,20 @@ nsLayoutStatics::Shutdown()
   nsXBLService::Shutdown();
   nsAutoCopyListener::Shutdown();
   FrameLayerBuilder::Shutdown();
 
 #ifdef MOZ_ANDROID_OMX
   AndroidMediaPluginHost::Shutdown();
 #endif
 
+#ifdef MOZ_FFMPEG
+  FFmpegRuntimeLinker::Unlink();
+#endif
+
   CubebUtils::ShutdownLibrary();
   AsyncLatencyLogger::ShutdownLogger();
   WebAudioUtils::Shutdown();
 
 #ifdef MOZ_WIDGET_GONK
   nsVolumeService::Shutdown();
 #endif