Bug 1240630: [ffvpx] P1. Add a FFVPX PDM. r=kentuckyfriedtakahe

This allows support for linking to two different version of libavcodec: our own and the system one if found.
ffvpx symbols are loaded within the namespace mozilla::ffvpx.
This commit is contained in:
Jean-Yves Avenard 2016-01-19 17:29:19 +11:00
parent c7cf4b994f
commit aeefe81d51
10 changed files with 316 additions and 96 deletions

View File

@ -101,7 +101,7 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
AVPacket packet;
av_init_packet(&packet);
AV_CALL(av_init_packet(&packet));
packet.data = const_cast<uint8_t*>(aSample->Data());
packet.size = aSample->Size();
@ -118,7 +118,7 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
while (packet.size > 0) {
int decoded;
int bytesConsumed =
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.");

View File

@ -54,7 +54,7 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
StaticMutexAutoLock mon(sMonitor);
if (!(mCodecContext = avcodec_alloc_context3(codec))) {
if (!(mCodecContext = AV_CALL(avcodec_alloc_context3(codec)))) {
NS_WARNING("Couldn't init ffmpeg context");
return NS_ERROR_FAILURE;
}
@ -77,10 +77,10 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
}
if (avcodec_open2(mCodecContext, codec, nullptr) < 0) {
if (AV_CALL(avcodec_open2(mCodecContext, codec, nullptr)) < 0) {
NS_WARNING("Couldn't initialise ffmpeg decoder");
avcodec_close(mCodecContext);
av_freep(&mCodecContext);
AV_CALL(avcodec_close(mCodecContext));
AV_CALL(av_freep(&mCodecContext));
return NS_ERROR_FAILURE;
}
@ -141,7 +141,7 @@ FFmpegDataDecoder<LIBAV_VER>::ProcessFlush()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
if (mCodecContext) {
avcodec_flush_buffers(mCodecContext);
AV_CALL(avcodec_flush_buffers(mCodecContext));
}
MonitorAutoLock mon(mMonitor);
mIsFlushing = false;
@ -154,12 +154,12 @@ FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown()
StaticMutexAutoLock mon(sMonitor);
if (sFFmpegInitDone && mCodecContext) {
avcodec_close(mCodecContext);
av_freep(&mCodecContext);
AV_CALL(avcodec_close(mCodecContext));
AV_CALL(av_freep(&mCodecContext));
#if LIBAVCODEC_VERSION_MAJOR >= 55
av_frame_free(&mFrame);
AV_CALL(av_frame_free(&mFrame));
#elif LIBAVCODEC_VERSION_MAJOR == 54
avcodec_free_frame(&mFrame);
AV_CALL(avcodec_free_frame(&mFrame));
#else
delete mFrame;
mFrame = nullptr;
@ -173,20 +173,20 @@ FFmpegDataDecoder<LIBAV_VER>::PrepareFrame()
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
#if LIBAVCODEC_VERSION_MAJOR >= 55
if (mFrame) {
av_frame_unref(mFrame);
AV_CALL(av_frame_unref(mFrame));
} else {
mFrame = av_frame_alloc();
mFrame = AV_CALL(av_frame_alloc());
}
#elif LIBAVCODEC_VERSION_MAJOR == 54
if (mFrame) {
avcodec_get_frame_defaults(mFrame);
AV_CALL(avcodec_get_frame_defaults(mFrame));
} else {
mFrame = avcodec_alloc_frame();
mFrame = AV_CALL(avcodec_alloc_frame());
}
#else
delete mFrame;
mFrame = new AVFrame;
avcodec_get_frame_defaults(mFrame);
AV_CALL(avcodec_get_frame_defaults(mFrame));
#endif
return mFrame;
}
@ -196,13 +196,13 @@ FFmpegDataDecoder<LIBAV_VER>::FindAVCodec(AVCodecID aCodec)
{
StaticMutexAutoLock mon(sMonitor);
if (!sFFmpegInitDone) {
avcodec_register_all();
AV_CALL(avcodec_register_all());
#ifdef DEBUG
av_log_set_level(AV_LOG_DEBUG);
AV_CALL(av_log_set_level(AV_LOG_DEBUG));
#endif
sFFmpegInitDone = true;
}
return avcodec_find_decoder(aCodec);
return AV_CALL(avcodec_find_decoder(aCodec));
}
} // namespace mozilla

View File

@ -47,14 +47,22 @@ public:
FlushableTaskQueue* aAudioTaskQueue,
MediaDataDecoderCallback* aCallback) override
{
#ifdef USING_MOZFFVPX
return nullptr;
#else
RefPtr<MediaDataDecoder> decoder =
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 = FFmpegH264Decoder<V>::GetCodecId(aMimeType);
if (audioCodec == AV_CODEC_ID_NONE && videoCodec == AV_CODEC_ID_NONE) {
return false;

View File

@ -151,7 +151,7 @@ FFmpegH264Decoder<LIBAV_VER>::InitCodecContext()
// FFmpeg will call back to this to negotiate a video pixel format.
mCodecContext->get_format = ChoosePixelFormat;
mCodecParser = av_parser_init(mCodecID);
mCodecParser = AV_CALL(av_parser_init(mCodecID));
if (mCodecParser) {
mCodecParser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
}
@ -175,10 +175,10 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
while (inputSize) {
uint8_t* data;
int size;
int len = 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;
@ -210,7 +210,7 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
AVPacket packet;
av_init_packet(&packet);
AV_CALL(av_init_packet(&packet));
packet.data = aData;
packet.size = aSize;
@ -237,7 +237,7 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
int decoded;
int bytesConsumed =
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) "
@ -361,7 +361,7 @@ FFmpegH264Decoder<LIBAV_VER>::~FFmpegH264Decoder()
{
MOZ_COUNT_DTOR(FFmpegH264Decoder);
if (mCodecParser) {
av_parser_close(mCodecParser);
AV_CALL(av_parser_close(mCodecParser));
mCodecParser = nullptr;
}
}

View File

@ -31,14 +31,29 @@ extern "C" {
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__

View File

@ -7,18 +7,9 @@
#include "FFmpegRuntimeLinker.h"
#include "mozilla/ArrayUtils.h"
#include "FFmpegLog.h"
#include "mozilla/Preferences.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
{
@ -53,6 +44,7 @@ PRLibrary* FFmpegRuntimeLinker::sLinkedLib = nullptr;
PRLibrary* FFmpegRuntimeLinker::sLinkedUtilLib = nullptr;
static unsigned (*avcodec_version)() = nullptr;
#if !defined(XP_WIN)
#ifdef __GNUC__
#define AV_FUNC(func, ver) void (*func)();
#define LIBAVCODEC_ALLVERSION
@ -61,6 +53,7 @@ static unsigned (*avcodec_version)() = nullptr;
#endif
#include "FFmpegFunctionList.h"
#undef AV_FUNC
#endif
static PRLibrary*
MozAVLink(const char* aName)
@ -77,7 +70,7 @@ FFmpegRuntimeLinker::Link()
if (sLinkStatus) {
return sLinkStatus == LinkStatus_SUCCEEDED;
}
#if !defined(XP_WIN)
MOZ_ASSERT(NS_IsMainThread());
for (size_t i = 0; i < ArrayLength(sLibs); i++) {
@ -100,55 +93,8 @@ FFmpegRuntimeLinker::Link()
}
FFMPEG_LOG(" ]\n");
#ifdef MOZ_FFVPX
// 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)&FFmpegRuntimeLinker::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;
}
PR_Free(path);
nsCOMPtr<nsIFile> rootDir;
if (NS_FAILED(xulFile->GetParent(getter_AddRefs(rootDir))) || !rootDir) {
return false;
}
nsAutoCString rootPath;
if (NS_FAILED(rootDir->GetNativePath(rootPath))) {
return false;
}
char* libname = NULL;
/* Get the platform-dependent library name of the module */
libname = PR_GetLibraryName(rootPath.get(), "mozavutil");
if (!libname) {
return false;
}
sLinkedUtilLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
libname = PR_GetLibraryName(rootPath.get(), "mozavcodec");
if (!libname) {
Unlink();
return false;
}
sLinkedLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
if (sLinkedLib && sLinkedUtilLib) {
if (Bind("mozavcodec")) {
sLinkStatus = LinkStatus_SUCCEEDED;
return true;
}
}
#endif
Unlink();
#endif
sLinkStatus = LinkStatus_FAILED;
return false;
@ -157,6 +103,9 @@ FFmpegRuntimeLinker::Link()
/* static */ bool
FFmpegRuntimeLinker::Bind(const char* aLibName)
{
#if defined(XP_WIN)
return false;
#else
avcodec_version = (decltype(avcodec_version))PR_FindSymbol(sLinkedLib,
"avcodec_version");
uint32_t major, minor, micro;
@ -203,11 +152,15 @@ FFmpegRuntimeLinker::Bind(const char* aLibName)
#include "FFmpegFunctionList.h"
#undef AV_FUNC
return true;
#endif
}
/* static */ already_AddRefed<PlatformDecoderModule>
FFmpegRuntimeLinker::CreateDecoderModule()
{
#if defined(XP_WIN)
return nullptr;
#else
if (!Link()) {
return nullptr;
}
@ -218,16 +171,15 @@ FFmpegRuntimeLinker::CreateDecoderModule()
RefPtr<PlatformDecoderModule> module;
switch (major) {
#ifndef XP_WIN
case 53: module = FFmpegDecoderModule<53>::Create(); break;
case 54: module = FFmpegDecoderModule<54>::Create(); break;
case 55:
case 56: module = FFmpegDecoderModule<55>::Create(); break;
#endif
case 57: module = FFmpegDecoderModule<57>::Create(); break;
default: module = nullptr;
}
return module.forget();
#endif
}
/* static */ void

View File

@ -0,0 +1,162 @@
/* -*- 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 "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();
};
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::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::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;
}
PR_Free(path);
nsCOMPtr<nsIFile> rootDir;
if (NS_FAILED(xulFile->GetParent(getter_AddRefs(rootDir))) || !rootDir) {
return false;
}
nsAutoCString rootPath;
if (NS_FAILED(rootDir->GetNativePath(rootPath))) {
return false;
}
char* libname = NULL;
/* Get the platform-dependent library name of the module */
libname = PR_GetLibraryName(rootPath.get(), "mozavutil");
if (!libname) {
return false;
}
sLinkedUtilLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
libname = PR_GetLibraryName(rootPath.get(), "mozavcodec");
if (libname) {
sLinkedLib = MozAVLink(libname);
PR_FreeLibraryName(libname);
if (sLinkedLib && sLinkedUtilLib) {
if (Bind("mozavcodec")) {
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; \
}
#include "FFmpegFunctionList.h"
#undef AV_FUNC
return true;
}
/* static */ already_AddRefed<PlatformDecoderModule>
FFVPXRuntimeLinker::CreateDecoderModule()
{
if (!Link()) {
return nullptr;
}
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

View File

@ -0,0 +1,43 @@
/* -*- 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/. */
#ifndef __FFVPXRuntimeLinker_h__
#define __FFVPXRuntimeLinker_h__
#include "PlatformDecoderModule.h"
struct PRLibrary;
namespace mozilla
{
namespace ffvpx
{
class FFVPXRuntimeLinker
{
public:
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__ */

View File

@ -0,0 +1,44 @@
# -*- 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/.
LOCAL_INCLUDES += ['/xpcom/build']
EXPORTS += [
'FFVPXRuntimeLinker.h',
]
UNIFIED_SOURCES += [
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegH264Decoder.cpp',
]
SOURCES += [
'FFVPXRuntimeLinker.cpp',
]
LOCAL_INCLUDES += [
'..',
'../ffmpeg57/include',
]
if CONFIG['OS_ARCH'] == 'WINNT':
LOCAL_INCLUDES += [
'../ffmpeg57/include',
]
if CONFIG['GNU_CXX']:
CXXFLAGS += [ '-Wno-deprecated-declarations' ]
if CONFIG['CLANG_CXX']:
CXXFLAGS += [
'-Wno-unknown-attributes',
]
if CONFIG['_MSC_VER']:
CXXFLAGS += [
'-wd4996', # deprecated declaration
]
DEFINES['FFVPX_VERSION'] = 46465650
DEFINES['USING_MOZFFVPX'] = True
FINAL_LIBRARY = 'xul'

View File

@ -39,27 +39,23 @@ if CONFIG['MOZ_EME']:
DIRS += ['agnostic/eme']
if CONFIG['MOZ_FFMPEG']:
LOCAL_INCLUDES += ['/xpcom/build']
EXPORTS += [
'ffmpeg/FFmpegRuntimeLinker.h',
]
UNIFIED_SOURCES += [
'ffmpeg/FFmpegRuntimeLinker.cpp',
]
if CONFIG['MOZ_FFVPX']:
DIRS += [
'ffmpeg/ffvpx',
]
if CONFIG['OS_ARCH'] != 'WINNT':
DIRS += [
'ffmpeg/libav53',
'ffmpeg/libav54',
'ffmpeg/libav55',
'ffmpeg/ffmpeg57',
]
else:
LOCAL_INCLUDES += [
'ffmpeg/ffmpeg57/include',
]
DIRS += [
'ffmpeg/ffmpeg57',
]
if CONFIG['MOZ_APPLEMEDIA']:
EXPORTS += [