This simplifies use of the patent license, simplifying use with a library that has been downloaded at runtime (making it possible to actually load and run libavcodec before the corresponding OpenH264 library exists). --- This patch was sent for review earlier, and got some feedback, but it was deferred back then due not knowing how much interest there would be in it - see https://patches.libav.org/patch/56287/.
Now there seems to be interest in it, see https://lists.libav.org/pipermail/libav-devel/2016-July/078139.html, so I'm resending it, with the feedback from the previous round applied, and updated on top of the latest master. --- configure | 8 ++++-- libavcodec/Makefile | 1 + libavcodec/libopenh264.c | 4 +-- libavcodec/libopenh264.h | 5 +++- libavcodec/libopenh264dec.c | 61 ++++++++++++++++++++++++++++++++++++++++++--- libavcodec/libopenh264enc.c | 49 +++++++++++++++++++++++++++++++++--- 6 files changed, 115 insertions(+), 13 deletions(-) diff --git a/configure b/configure index ed32341..8dbc73b 100755 --- a/configure +++ b/configure @@ -204,6 +204,7 @@ External library support: --enable-libopencore-amrwb AMR-WB audio decoding --enable-libopencv computer vision --enable-libopenh264 H.264 video encoding/decoding + --enable-libopenh264-dyn H.264 video encoding/decoding via a dynamically loaded OpenH264 --enable-libopenjpeg JPEG 2000 image encoding/decoding --enable-libopus Opus audio encoding/decoding --enable-libpulse Pulseaudio sound server @@ -1254,6 +1255,7 @@ EXTERNAL_LIBRARY_LIST=" libopencore_amrwb libopencv libopenh264 + libopenh264_dyn libopenjpeg libopus libpulse @@ -2237,9 +2239,9 @@ libopencore_amrnb_decoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_select="audio_frame_queue" libopencore_amrwb_decoder_deps="libopencore_amrwb" -libopenh264_decoder_deps="libopenh264" +libopenh264_decoder_deps_any="libopenh264 libopenh264_dyn" libopenh264_decoder_select="h264_mp4toannexb_bsf" -libopenh264_encoder_deps="libopenh264" +libopenh264_encoder_deps_any="libopenh264 libopenh264_dyn" libopenjpeg_decoder_deps="libopenjpeg" libopenjpeg_encoder_deps="libopenjpeg" libopus_decoder_deps="libopus" @@ -4594,6 +4596,8 @@ enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb enabled libopencv && require_pkg_config opencv opencv/cv.h cvCreateImageHeader enabled libopenh264 && require_pkg_config openh264 wels/codec_api.h WelsGetCodecVersion +enabled libopenh264_dyn && { { check_header wels/codec_ver.h && enabled dyn_lib_open; } || + die "ERROR: OpenH264 1.3 header not found, or dlopen/LoadLibrary not found"; } enabled libopenjpeg && { { check_header openjpeg.h && check_lib2 openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC; } || { require_pkg_config libopenjpeg1 openjpeg.h opj_version -DOPJ_STATIC; } } enabled libopus && require_pkg_config opus opus_multistream.h opus_multistream_decoder_create diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 8eb7d36..f639ac5 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -771,6 +771,7 @@ SKIPHEADERS += %_tablegen.h \ SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h +SKIPHEADERS-$(CONFIG_LIBOPENH264) += libopenh264.h SKIPHEADERS-$(CONFIG_LIBVPX) += libvpx.h SKIPHEADERS-$(CONFIG_MPEG_XVMC_DECODER) += xvmc.h SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h diff --git a/libavcodec/libopenh264.c b/libavcodec/libopenh264.c index 6252cfd..77bac8e 100644 --- a/libavcodec/libopenh264.c +++ b/libavcodec/libopenh264.c @@ -46,13 +46,13 @@ void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg) av_log(ctx, equiv_libav_log_level, "%s\n", msg); } -int ff_libopenh264_check_version(void *logctx) +int ff_libopenh264_check_version(void *logctx, OpenH264Version (*get_version_func)(void)) { // Mingw GCC < 4.7 on x86_32 uses an incorrect/buggy ABI for the WelsGetCodecVersion // 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) - OpenH264Version libver = WelsGetCodecVersion(); + OpenH264Version libver = get_version_func(); if (memcmp(&libver, &g_stCodecVersion, sizeof(libver))) { av_log(logctx, AV_LOG_ERROR, "Incorrect library version loaded\n"); return AVERROR(EINVAL); diff --git a/libavcodec/libopenh264.h b/libavcodec/libopenh264.h index 7c69481..865cb00 100644 --- a/libavcodec/libopenh264.h +++ b/libavcodec/libopenh264.h @@ -22,6 +22,9 @@ #ifndef AVCODEC_LIBOPENH264_H #define AVCODEC_LIBOPENH264_H +#include <wels/codec_api.h> +#include <wels/codec_ver.h> + #define OPENH264_VER_AT_LEAST(maj, min) \ ((OPENH264_MAJOR > (maj)) || \ (OPENH264_MAJOR == (maj) && OPENH264_MINOR >= (min))) @@ -34,6 +37,6 @@ void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg); -int ff_libopenh264_check_version(void *logctx); +int ff_libopenh264_check_version(void *logctx, OpenH264Version (*get_version_func)(void)); #endif /* AVCODEC_LIBOPENH264_H */ diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c index cc18f24..6f45782 100644 --- a/libavcodec/libopenh264dec.c +++ b/libavcodec/libopenh264dec.c @@ -23,6 +23,9 @@ #include <wels/codec_ver.h> #include "libavutil/common.h" +#if CONFIG_LIBOPENH264_DYN +#include "libavutil/dyn_lib_open.h" +#endif #include "libavutil/fifo.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" @@ -34,19 +37,38 @@ #include "libopenh264.h" typedef struct SVCContext { + const AVClass *av_class; +#if CONFIG_LIBOPENH264_DYN + const char *libname; + void *lib; +#endif + void (*destroy_func)(ISVCDecoder *ppDecoder); ISVCDecoder *decoder; AVBSFContext *bsf; AVFifoBuffer *packet_fifo; AVPacket pkt_filtered; } SVCContext; +#define OFFSET(x) offsetof(SVCContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { +#if CONFIG_LIBOPENH264_DYN + { "openh264lib", "OpenH264 library name", OFFSET(libname), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VD }, +#endif + { NULL } +}; + +static const AVClass class = { + "libopenh264dec", av_default_item_name, options, LIBAVUTIL_VERSION_INT +}; + static av_cold int svc_decode_close(AVCodecContext *avctx) { SVCContext *s = avctx->priv_data; AVPacket pkt; - if (s->decoder) - WelsDestroyDecoder(s->decoder); + if (s->decoder && s->destroy_func) + s->destroy_func(s->decoder); while (s->packet_fifo && av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); @@ -56,6 +78,10 @@ static av_cold int svc_decode_close(AVCodecContext *avctx) av_bsf_free(&s->bsf); av_packet_unref(&s->pkt_filtered); av_fifo_free(s->packet_fifo); +#if CONFIG_LIBOPENH264_DYN + if (s->lib) + free_library(s->lib); +#endif return 0; } @@ -67,15 +93,41 @@ static av_cold int svc_decode_init(AVCodecContext *avctx) int err; int log_level; WelsTraceCallback callback_function; + int (*create_func)(ISVCDecoder **ppDecoder); + OpenH264Version (*get_version_func)(void); + +#if CONFIG_LIBOPENH264_DYN + if (!s->libname) { + av_log(avctx, AV_LOG_ERROR, "No library name provided\n"); + return AVERROR(EINVAL); + } + s->lib = load_library(s->libname); + if (!s->lib) { + av_log(avctx, AV_LOG_ERROR, "Unable to load %s\n", s->libname); + return AVERROR(EINVAL); + } + create_func = (void*) get_function(s->lib, "WelsCreateDecoder"); + s->destroy_func = (void*) get_function(s->lib, "WelsDestroyDecoder"); + get_version_func = (void*) get_function(s->lib, "WelsGetCodecVersion"); + + if (!create_func || !s->destroy_func || !get_version_func) { + av_log(avctx, AV_LOG_ERROR, "%s doesn't contain the necessary functions\n", s->libname); + return AVERROR(EINVAL); + } +#else + create_func = WelsCreateDecoder; + get_version_func = WelsGetCodecVersion; + s->destroy_func = WelsDestroyDecoder; +#endif - if ((err = ff_libopenh264_check_version(avctx)) < 0) + if ((err = ff_libopenh264_check_version(avctx, get_version_func)) < 0) return err; s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); if (!s->packet_fifo) return AVERROR(ENOMEM); - if (WelsCreateDecoder(&s->decoder)) { + if (create_func(&s->decoder)) { av_log(avctx, AV_LOG_ERROR, "Unable to create decoder\n"); return AVERROR_UNKNOWN; } @@ -239,4 +291,5 @@ AVCodec ff_libopenh264_decoder = { .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .priv_class = &class, }; diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index a09b7cf..1d67fdb 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -24,6 +24,9 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" +#if CONFIG_LIBOPENH264_DYN +#include "libavutil/dyn_lib_open.h" +#endif #include "libavutil/opt.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -39,6 +42,11 @@ typedef struct SVCContext { const AVClass *av_class; +#if CONFIG_LIBOPENH264_DYN + const char *libname; + void *lib; +#endif + void (*destroy_func)(ISVCEncoder *ppEncoder); ISVCEncoder *encoder; int slice_mode; int loopfilter; @@ -52,6 +60,9 @@ typedef struct SVCContext { #define OFFSET(x) offsetof(SVCContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { +#if CONFIG_LIBOPENH264_DYN + { "openh264lib", "OpenH264 library name", OFFSET(libname), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, +#endif #if OPENH264_VER_AT_LEAST(1, 6) { "slice_mode", "Slice mode", OFFSET(slice_mode), AV_OPT_TYPE_INT, { .i64 = SM_FIXEDSLCNUM_SLICE }, SM_SINGLE_SLICE, SM_RESERVED, VE, "slice_mode" }, #else @@ -82,10 +93,14 @@ static av_cold int svc_encode_close(AVCodecContext *avctx) { SVCContext *s = avctx->priv_data; - if (s->encoder) - WelsDestroySVCEncoder(s->encoder); + if (s->encoder && s->destroy_func) + s->destroy_func(s->encoder); if (s->skipped > 0) av_log(avctx, AV_LOG_WARNING, "%d frames skipped\n", s->skipped); +#if CONFIG_LIBOPENH264_DYN + if (s->lib) + free_library(s->lib); +#endif return 0; } @@ -97,11 +112,37 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) int log_level; WelsTraceCallback callback_function; AVCPBProperties *props; + int (*create_func)(ISVCEncoder **ppEncoder); + OpenH264Version (*get_version_func)(void); + +#if CONFIG_LIBOPENH264_DYN + if (!s->libname) { + av_log(avctx, AV_LOG_ERROR, "No library name provided\n"); + return AVERROR(EINVAL); + } + s->lib = load_library(s->libname); + if (!s->lib) { + av_log(avctx, AV_LOG_ERROR, "Unable to load %s\n", s->libname); + return AVERROR(EINVAL); + } + create_func = (void*) get_function(s->lib, "WelsCreateSVCEncoder"); + s->destroy_func = (void*) get_function(s->lib, "WelsDestroySVCEncoder"); + get_version_func = (void*) get_function(s->lib, "WelsGetCodecVersion"); + + if (!create_func || !s->destroy_func || !get_version_func) { + av_log(avctx, AV_LOG_ERROR, "%s doesn't contain the necessary functions\n", s->libname); + return AVERROR(EINVAL); + } +#else + create_func = WelsCreateSVCEncoder; + get_version_func = WelsGetCodecVersion; + s->destroy_func = WelsDestroySVCEncoder; +#endif - if ((err = ff_libopenh264_check_version(avctx)) < 0) + if ((err = ff_libopenh264_check_version(avctx, get_version_func)) < 0) return err; - if (WelsCreateSVCEncoder(&s->encoder)) { + if (create_func(&s->encoder)) { av_log(avctx, AV_LOG_ERROR, "Unable to create encoder\n"); return AVERROR_UNKNOWN; } -- 2.7.4 (Apple Git-66) _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
