From 23c6bb2850b82c473e67df111333479805b0ba4b Mon Sep 17 00:00:00 2001 From: Neal Gompa Date: Tue, 15 Feb 2022 10:29:05 -0500 Subject: [PATCH] avcodec/openh264: Add the ability to dlopen() OpenH264 We can't directly depend on OpenH264, but we can weakly link to it and gracefully expose the capability. Co-authored-by: Andreas Schneider Co-authored-by: Neal Gompa Signed-off-by: Neal Gompa --- configure | 3 + libavcodec/libopenh264.c | 11 +++ libavcodec/libopenh264_dlopen.h | 164 ++++++++++++++++++++++++++++++++ libavcodec/libopenh264dec.c | 9 ++ libavcodec/libopenh264enc.c | 9 ++ 5 files changed, 196 insertions(+) create mode 100644 libavcodec/libopenh264_dlopen.h diff --git a/configure b/configure index 6b5ef6332e..f08e566e98 100755 --- a/configure +++ b/configure @@ -250,6 +250,7 @@ External library support: --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] --enable-libopencv enable video filtering via libopencv [no] --enable-libopenh264 enable H.264 encoding via OpenH264 [no] + --enable-libopenh264-dlopen enable H.264 encoding via dlopen()'ed OpenH264 [no] --enable-libopenjpeg enable JPEG 2000 de/encoding via OpenJPEG [no] --enable-libopenmpt enable decoding tracked files via libopenmpt [no] --enable-libopenvino enable OpenVINO as a DNN module backend @@ -1839,6 +1840,7 @@ EXTERNAL_LIBRARY_LIST=" libmysofa libopencv libopenh264 + libopenh264_dlopen libopenjpeg libopenmpt libopenvino @@ -6575,6 +6577,7 @@ enabled libopencv && { check_headers opencv2/core/core_c.h && require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } enabled libopenh264 && require_pkg_config libopenh264 openh264 wels/codec_api.h WelsGetCodecVersion +enabled libopenh264_dlopen && enable libopenh264 && add_cppflags "-I$(dirname `readlink -f $0`)/ffdlopenhdrs/include -DCONFIG_LIBOPENH264_DLOPEN=1" enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++" diff --git a/libavcodec/libopenh264.c b/libavcodec/libopenh264.c index 59c61a3a4c..382a34562a 100644 --- a/libavcodec/libopenh264.c +++ b/libavcodec/libopenh264.c @@ -20,8 +20,13 @@ */ #include + +#ifdef CONFIG_LIBOPENH264_DLOPEN +#include "libopenh264_dlopen.h" +#else #include #include +#endif #include "libavutil/log.h" @@ -52,6 +57,12 @@ int ff_libopenh264_check_version(void *logctx) // function (for functions returning larger structs), thus skip the check in those // configurations. #if !defined(_WIN32) || !defined(__GNUC__) || !ARCH_X86_32 || AV_GCC_VERSION_AT_LEAST(4, 7) + +#ifdef CONFIG_LIBOPENH264_DLOPEN + if (loadLibOpenH264(logctx)) + return -1; +#endif + OpenH264Version libver = WelsGetCodecVersion(); if (memcmp(&libver, &g_stCodecVersion, sizeof(libver))) { av_log(logctx, AV_LOG_ERROR, "Incorrect library version loaded\n"); diff --git a/libavcodec/libopenh264_dlopen.h b/libavcodec/libopenh264_dlopen.h new file mode 100644 index 0000000000..c58fcd704d --- /dev/null +++ b/libavcodec/libopenh264_dlopen.h @@ -0,0 +1,164 @@ +/*! + *@page License + * + * \copy + * Copyright (c) 2022, Andreas Schneider + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef CONFIG_LIBOPENH264_DLOPEN + +#include + +#include +#include + +#include "avcodec.h" +/* + * The symbol binding makes sure we do not run into strict aliasing issues which + * can lead into segfaults. + */ +typedef int (*__oh264_WelsCreateSVCEncoder)(ISVCEncoder **); +typedef void (*__oh264_WelsDestroySVCEncoder)(ISVCEncoder *); +typedef int (*__oh264_WelsGetDecoderCapability)(SDecoderCapability *); +typedef long (*__oh264_WelsCreateDecoder)(ISVCDecoder **); +typedef void (*__oh264_WelsDestroyDecoder)(ISVCDecoder *); +typedef OpenH264Version (*__oh264_WelsGetCodecVersion)(void); +typedef void (*__oh264_WelsGetCodecVersionEx)(OpenH264Version *); + +#define OH264_SYMBOL_ENTRY(i) \ + union { \ + __oh264_##i f; \ + void *obj; \ + } _oh264_##i + +struct oh264_symbols { + OH264_SYMBOL_ENTRY(WelsCreateSVCEncoder); + OH264_SYMBOL_ENTRY(WelsDestroySVCEncoder); + OH264_SYMBOL_ENTRY(WelsGetDecoderCapability); + OH264_SYMBOL_ENTRY(WelsCreateDecoder); + OH264_SYMBOL_ENTRY(WelsDestroyDecoder); + OH264_SYMBOL_ENTRY(WelsGetCodecVersion); + OH264_SYMBOL_ENTRY(WelsGetCodecVersionEx); +}; + +/* Symbols are bound by loadLibOpenH264() */ +static struct oh264_symbols openh264_symbols; + +static int oh264_WelsCreateSVCEncoder(ISVCEncoder **ppEncoder) { + return openh264_symbols._oh264_WelsCreateSVCEncoder.f(ppEncoder); +} +#define WelsCreateSVCEncoder oh264_WelsCreateSVCEncoder + +static void oh264_WelsDestroySVCEncoder(ISVCEncoder *pEncoder) { + return openh264_symbols._oh264_WelsDestroySVCEncoder.f(pEncoder); +} +#define WelsDestroySVCEncoder oh264_WelsDestroySVCEncoder + +static int oh264_WelsGetDecoderCapability(SDecoderCapability *pDecCapability) { + return openh264_symbols._oh264_WelsGetDecoderCapability.f(pDecCapability); +} +#define WelsGetDecoderCapability oh264_WelsGetDecoderCapability + +static long oh264_WelsCreateDecoder(ISVCDecoder **ppDecoder) { + return openh264_symbols._oh264_WelsCreateDecoder.f(ppDecoder); +} +#define WelsCreateDecoder oh264_WelsCreateDecoder + +static void oh264_WelsDestroyDecoder(ISVCDecoder *pDecoder) { + return openh264_symbols._oh264_WelsDestroyDecoder.f(pDecoder); +} +#define WelsDestroyDecoder oh264_WelsDestroyDecoder + +static OpenH264Version oh264_WelsGetCodecVersion(void) { + return openh264_symbols._oh264_WelsGetCodecVersion.f(); +} +#define WelsGetCodecVersion oh264_WelsGetCodecVersion + +static void oh264_WelsGetCodecVersionEx(OpenH264Version *pVersion) { + openh264_symbols._oh264_WelsGetCodecVersionEx.f(pVersion); +} +#define WelsGetCodecVersionEx oh264_WelsGetCodecVersionEx + +static void *_oh264_bind_symbol(AVCodecContext *avctx, + void *handle, + const char *sym_name) { + void *sym = NULL; + + sym = dlsym(handle, sym_name); + if (sym == NULL) { + const char *err = dlerror(); + av_log(avctx, + AV_LOG_WARNING, + "%s: Failed to bind %s\n", + err, + sym_name); + return NULL; + } + + return sym; +} + +#define oh264_bind_symbol(avctx, handle, sym_name) \ + if (openh264_symbols._oh264_##sym_name.obj == NULL) { \ + openh264_symbols._oh264_##sym_name.obj = _oh264_bind_symbol(avctx, handle, #sym_name); \ + if (openh264_symbols._oh264_##sym_name.obj == NULL) { \ + return 1; \ + } \ + } + +static int loadLibOpenH264(AVCodecContext *avctx) { + void *libopenh264 = NULL; + const char *err = NULL; + +#define OPENH264_LIB "libopenh264.so.6" + libopenh264 = dlopen(OPENH264_LIB, RTLD_LAZY); + err = dlerror(); + if (err != NULL) { + av_log(avctx, AV_LOG_WARNING, + "%s: %s is missing, openh264 support will be disabled\n", err, + OPENH264_LIB); + if (libopenh264) { + dlclose(libopenh264); + } + return 1; + } + + oh264_bind_symbol(avctx, libopenh264, WelsCreateSVCEncoder); + oh264_bind_symbol(avctx, libopenh264, WelsDestroySVCEncoder); + oh264_bind_symbol(avctx, libopenh264, WelsGetDecoderCapability); + oh264_bind_symbol(avctx, libopenh264, WelsCreateDecoder); + oh264_bind_symbol(avctx, libopenh264, WelsDestroyDecoder); + oh264_bind_symbol(avctx, libopenh264, WelsGetCodecVersion); + oh264_bind_symbol(avctx, libopenh264, WelsGetCodecVersionEx); + + return 0; +} + +#endif // CONFIG_LIBOPENH264_DLOPEN diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c index 7f5e85402a..281e43c3c0 100644 --- a/libavcodec/libopenh264dec.c +++ b/libavcodec/libopenh264dec.c @@ -19,8 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef CONFIG_LIBOPENH264_DLOPEN +#include "libopenh264_dlopen.h" +#else #include #include +#endif #include "libavutil/common.h" #include "libavutil/fifo.h" @@ -55,6 +59,11 @@ static av_cold int svc_decode_init(AVCodecContext *avctx) int log_level; WelsTraceCallback callback_function; +#ifdef CONFIG_LIBOPENH264_DLOPEN + if (loadLibOpenH264(avctx)) + return -1; +#endif + if ((err = ff_libopenh264_check_version(avctx)) < 0) return err; diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index de4b85c411..555351982e 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -19,8 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef CONFIG_LIBOPENH264_DLOPEN +#include "libopenh264_dlopen.h" +#else #include #include +#endif #include "libavutil/attributes.h" #include "libavutil/common.h" @@ -136,6 +140,11 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) WelsTraceCallback callback_function; AVCPBProperties *props; +#ifdef CONFIG_LIBOPENH264_DLOPEN + if (loadLibOpenH264(avctx)) + return -1; +#endif + if ((err = ff_libopenh264_check_version(avctx)) < 0) return err; -- 2.34.1