[FFmpeg-devel] [PATCH 2/2] Implement dynamic loading of NewTek NDI library

Marton Balint cus at passwd.hu
Wed Feb 21 11:16:28 EET 2018



On Wed, 21 Feb 2018, Maksym Veremeyenko wrote:

> 21.02.2018 0:39, Carl Eugen Hoyos пише:
>> 2018-02-20 23:35 GMT+01:00 Marton Balint <cus at passwd.hu>:
>>>
>>> On Tue, 20 Feb 2018, Carl Eugen Hoyos wrote:
>>>
>>>> 2018-02-20 17:32 GMT+01:00 Maksym Veremeyenko <verem at m1stereo.tv>:
>>>>
>>>>> attached patch implement dynamic loading of NewTek library and
>>>>> drop dependencies from NewTek SDK (if previous patch with
>>>>> including headers applied)
>>>>
>>>> This patch is not ok assuming the runtime library is not open
>>>> source and has a license compatible with the GPL.
>>>
>>> The patch might has merits even if the library remains in the
>>> NONFREE section, no?
>> 
>> It might, I do not immediately see them, though.
>
> patch without altering *EXTERNAL_LIBRARY_NONFREE_LIST* has any chance to 
> be reviewed?

Sure:

> From 8c0337878bdb8a1ccbc56ede42686e2a4d8e882e Mon Sep 17 00:00:00 2001
> From: Maksym Veremeyenko <verem at m1.tv>
> Date: Tue, 20 Feb 2018 17:16:46 +0200
> Subject: [PATCH 2/2] Implement dynamic loading of NewTek NDI library
> 
> ---
>  configure                          |   8 +--
>  libavdevice/Makefile               |   4 +-
>  libavdevice/libndi_newtek_common.c | 105 +++++++++++++++++++++++++++++++++++++
>  libavdevice/libndi_newtek_common.h |   4 +-
>  libavdevice/libndi_newtek_dec.c    |  32 ++++++-----
>  libavdevice/libndi_newtek_enc.c    |  16 ++++--
>  6 files changed, 144 insertions(+), 25 deletions(-)
>  create mode 100644 libavdevice/libndi_newtek_common.c
> 
> diff --git a/configure b/configure
> index 013308c..4782c77 100755
> --- a/configure
> +++ b/configure
> @@ -1569,7 +1569,6 @@ EXTERNAL_LIBRARY_GPL_LIST="
>
>  EXTERNAL_LIBRARY_NONFREE_LIST="
>      decklink
> -    libndi_newtek
>      libfdk_aac
>      openssl
>      libtls
> @@ -1648,6 +1647,7 @@ EXTERNAL_LIBRARY_LIST="
>      mediacodec
>      openal
>      opengl
> +    libndi_newtek
>  "

Some people disagree with this, so better leave it in NONFREE for now.

>
>  HWACCEL_AUTODETECT_LIBRARY_LIST="
> @@ -3093,10 +3093,11 @@ decklink_indev_deps="decklink threads"
>  decklink_indev_extralibs="-lstdc++"
>  decklink_outdev_deps="decklink threads"
>  decklink_outdev_extralibs="-lstdc++"
> +libndi_newtek_deps_any="libdl LoadLibrary"
>  libndi_newtek_indev_deps="libndi_newtek"
> -libndi_newtek_indev_extralibs="-lndi"
> +libndi_newtek_indev_extralibs=""

I believe you can simply delete this line.

>  libndi_newtek_outdev_deps="libndi_newtek"
> -libndi_newtek_outdev_extralibs="-lndi"
> +libndi_newtek_outdev_extralibs=""

And this.

>  dshow_indev_deps="IBaseFilter"
>  dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32 -lshlwapi"
>  fbdev_indev_deps="linux_fb_h"
> @@ -5866,7 +5867,6 @@ enabled cuda_sdk          && require cuda_sdk cuda.h cuCtxCreate -lcuda
>  enabled chromaprint       && require chromaprint chromaprint.h chromaprint_get_version -lchromaprint
>  enabled decklink          && { require_header DeckLinkAPI.h &&
>                                 { check_cpp_condition DeckLinkAPIVersion.h "BLACKMAGIC_DECKLINK_API_VERSION >= 0x0a060100" || die "ERROR: Decklink API version must be >= 10.6.1."; } }
> -enabled libndi_newtek     && require_header Processing.NDI.Lib.h

As other already pointed out, external headers in ffmpeg source tree are not
welcome anymore, so I guess you should keep this check. Maybe you should also
check the version of the headers, because you require SDK version V3 from 
now on, right?

>  enabled frei0r            && require_header frei0r.h
>  enabled gmp               && require gmp gmp.h mpz_export -lgmp
>  enabled gnutls            && require_pkg_config gnutls gnutls gnutls/gnutls.h gnutls_global_init
> diff --git a/libavdevice/Makefile b/libavdevice/Makefile
> index 8228d62..2d3322e 100644
> --- a/libavdevice/Makefile
> +++ b/libavdevice/Makefile
> @@ -19,8 +19,8 @@ OBJS-$(CONFIG_BKTR_INDEV)                += bktr.o
>  OBJS-$(CONFIG_CACA_OUTDEV)               += caca.o
>  OBJS-$(CONFIG_DECKLINK_OUTDEV)           += decklink_enc.o decklink_enc_c.o decklink_common.o
>  OBJS-$(CONFIG_DECKLINK_INDEV)            += decklink_dec.o decklink_dec_c.o decklink_common.o
> -OBJS-$(CONFIG_LIBNDI_NEWTEK_OUTDEV)      += libndi_newtek_enc.o
> -OBJS-$(CONFIG_LIBNDI_NEWTEK_INDEV)       += libndi_newtek_dec.o
> +OBJS-$(CONFIG_LIBNDI_NEWTEK_OUTDEV)      += libndi_newtek_enc.o libndi_newtek_common.o
> +OBJS-$(CONFIG_LIBNDI_NEWTEK_INDEV)       += libndi_newtek_dec.o libndi_newtek_common.o
>  OBJS-$(CONFIG_DSHOW_INDEV)               += dshow_crossbar.o dshow.o dshow_enummediatypes.o \
>                                              dshow_enumpins.o dshow_filter.o \
>                                              dshow_pin.o dshow_common.o
> diff --git a/libavdevice/libndi_newtek_common.c b/libavdevice/libndi_newtek_common.c
> new file mode 100644
> index 0000000..5202993
> --- /dev/null
> +++ b/libavdevice/libndi_newtek_common.c
> @@ -0,0 +1,105 @@
> +/*
> + * NewTek NDI common code
> + * Copyright (c) 2018 Maksym Veremeyenko
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libavformat/avformat.h"
> +#include "libavformat/internal.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/imgutils.h"
> +
> +#ifdef _WIN32
> +#include <windows.h>
> +#else
> +#include <dlfcn.h>
> +#endif
> +
> +#include "libndi_newtek_common.h"
> +
> +#define NDI_LIB_LOAD_ERROR_TEXT "\nPlease re-install the NewTek NDI Runtimes from " NDILIB_REDIST_URL " to use this functionality."
> +
> +const NDIlib_v3* ndi_lib_load(AVFormatContext *avctx) {

Use the ff_ prefix for global functions.

> +    char *path = NULL, *e;
> +    const NDIlib_v3* (*NDIlib_v3_load)(void) = NULL;
> +#ifdef _WIN32
> +    HMODULE
> +#else
> +    void*
> +#endif
> +        hNDILib;

The library handle should be returned, and freed when the device is freed,
otherwise you are leaking it.

> +
> +    e = getenv(NDILIB_REDIST_FOLDER);
> +    if (!e) {
> +        path = av_strdup(NDILIB_LIBRARY_NAME);
> +        if (!path)
> +            return NULL;
> +    }
> +    else {
> +        int s = strlen(NDILIB_LIBRARY_NAME) + 1 + strlen(e) + 1;
> +        path = av_malloc(s);
> +        if (!path)
> +            return NULL;
> +        snprintf(path, s, "%s"
> +#ifdef _WIN32
> +            "\\"
> +#else
> +            "/"
> +#endif
> +            "%s", e, NDILIB_LIBRARY_NAME);
> +    }

You can use a simpler approach to do this using av_asprintf which 
allocates the result (you need to define DS to "\\" or "/" depending on 
arch):

if (e)
     path = av_asprintf("%s%s%s", e, DS, NDILIB_LIBRARY_NAME);
else
     path = av_strdup(NDILIB_LIBRARY_NAME);

> +
> +
> +#ifdef _WIN32
> +    /* Try to load the library */
> +    hNDILib = LoadLibrary(path);
> +
> +    if (!hNDILib)
> +        av_log(avctx, AV_LOG_ERROR, "LoadLibrary(%s) failed. " NDI_LIB_LOAD_ERROR_TEXT "\n", path);
> +    else {
> +
> +        /* get NDIlib_v3_load address */
> +        *((FARPROC*)&NDIlib_v3_load) = GetProcAddress(hNDILib, "NDIlib_v3_load");
> +
> +        if (!NDIlib_v3_load) {
> +            av_log(avctx, AV_LOG_ERROR, "GetProcAddress(NDIlib_v3_load) failed in file [%s]. " NDI_LIB_LOAD_ERROR_TEXT "\n", path);
> +            FreeLibrary(hNDILib);
> +        }
> +    }
> +#else
> +    /* Try to load the library */
> +    hNDILib = dlopen(path, RTLD_LOCAL | RTLD_LAZY);
> +
> +    if (!hNDILib)
> +        av_log(avctx, AV_LOG_ERROR, "dlopen(%s) failed. " NDI_LIB_LOAD_ERROR_TEXT "\n", path);
> +    else {
> +
> +        /* get NDIlib_v3_load address */
> +        *((void**)&NDIlib_v3_load) = dlsym(hNDILib, "NDIlib_v3_load");
> +
> +        if (!NDIlib_v3_load) {
> +            av_log(avctx, AV_LOG_ERROR, "dlsym(NDIlib_v3_load) failed in file[%s]. " NDI_LIB_LOAD_ERROR_TEXT "\n", path);
> +            dlclose(hNDILib);
> +        }
> +    }
> +#endif

You should be able to load the library using common code if you use the
compat/w32dlfcn.h wrapper for WIN32, similarly how amfenc or avisynth does it.

However, the win32 wrapper expects a single library name, so you might 
have to extend the wrapper so that it detects if there is a backslash in 
the name, and act accordingly.

Regards,
Marton


More information about the ffmpeg-devel mailing list