Added support for libav/ffmpeg dual installs (#346)

* [config] Added support for libav/ffmpeg dual installs

Reordered CPPFLAGS/LIBS so that library flags (includes etc) appear
ahead of prefix/global directives and the correct headers/libraries
are checked (if symbols are defined in alternative libraries).
Updated libav checks to use header declaration checks
rather than link checks (so differences between
libav/ffmpeg can be correctly found), and updated code references
to use new defines.  Added support the alternate pkg-config
package names for libav.  Updated ffmpeg vs libav check
to check MICRO version number (>=100 for ffmpeg).  Simplified
resulting configure script by using a function to merge
CPPFLAGS variables.

* [config] Use FORKED_OPTS prefix for libevent_pthreads option

* [config] Add --with-libav option to select libav even if ffmpeg present
This commit is contained in:
sshambar 2017-02-19 06:21:00 -08:00 committed by ejurgensen
parent ff49e176f2
commit c54c909ae4
6 changed files with 130 additions and 81 deletions

View File

@ -99,13 +99,15 @@ AC_SUBST([COMMON_LIBS])
AC_SUBST([COMMON_CPPFLAGS])
AC_SUBST([FORKED_LIBS])
AC_SUBST([FORKED_CPPFLAGS])
AC_SUBST([FORKED_OPTS_LIBS])
AC_SUBST([FORKED_OPTS_CPPFLAGS])
AM_ICONV
dnl All FORK_ macros defined in m4/fork_checks.m4
FORK_FUNC_REQUIRE([COMMON], [GNU libunistring], [LIBUNISTRING], [unistring],
[u8_strconv_from_locale], [uniconv.h], [],
[dnl Retry test with iconv library
FORK_VARS_APPEND([COMMON], [LIBICONV], [INCICONV])
FORK_VARS_PREPEND([COMMON], [LIBICONV], [INCICONV])
FORK_FUNC_REQUIRE([COMMON], [GNU libunistring], [LIBUNISTRING],
[unistring], [u8_strconv_from_locale], [uniconv.h])])
@ -133,27 +135,6 @@ FORK_MODULES_CHECK([COMMON], [SQLITE3], [sqlite3 >= 3.5.0],
[AC_MSG_RESULT([[runtime will tell]])])
])
dnl libav/ffmpeg requires many feature checks
FORK_MODULES_CHECK([FORKED], [LIBAV],
[libavformat libavcodec libswscale libavutil libavfilter],
[av_init_packet], [libavcodec/avcodec.h],
[dnl Checks for misc libav and ffmpeg API differences
AC_CHECK_FUNCS([avcodec_find_best_pix_fmt_of_list],
[AC_DEFINE([HAVE_FFMPEG], 1,
[Define to 1 if you have ffmpeg (not libav)])])
AC_CHECK_FUNCS([av_buffersrc_add_frame_flags])
AC_CHECK_FUNCS([av_buffersink_get_frame])
AC_CHECK_FUNCS([avfilter_graph_parse_ptr])
AC_CHECK_FUNCS([av_packet_unref])
AC_CHECK_FUNCS([av_packet_rescale_ts])
AC_CHECK_FUNCS([avformat_alloc_output_context2])
AC_CHECK_FUNCS([av_frame_alloc])
AC_CHECK_FUNCS([av_frame_get_best_effort_timestamp])
AC_CHECK_FUNCS([av_image_fill_arrays])
AC_CHECK_FUNCS([av_image_get_buffer_size])
AC_CHECK_HEADERS([libavutil/channel_layout.h libavutil/mathematics.h])
])
dnl libevent2 requires version checks
FORK_MODULES_CHECK([FORKED], [LIBEVENT], [libevent >= 2],
[event_base_new], [event2/event.h],
@ -206,33 +187,80 @@ AC_CHECK_DECL([htobe16], [],
#endif
]])
dnl libav checks should be last, as they are sometimes both installed
dnl and the CPPFLAGS/LIBS needs to be at the front of the search list.
dnl Handle alternative package names for libav
PKG_CHECK_EXISTS([libavcodec-libav], [LIBAV=-libav], [LIBAV=])
dnl Preference for ffmpeg if we have both (this could be an option...)
PKG_CHECK_EXISTS([libavcodec], [LIBAV=])
dnl Option to choose libav even if ffmpeg is detected first
AC_ARG_WITH([libav], [AS_HELP_STRING([--with-libav],
[choose libav even if ffmpeg present (default=no)])],
[[LIBAV=-libav]], [[LIBAV=]])
dnl libav/ffmpeg requires many feature checks
FORK_MODULES_CHECK([FORKED], [LIBAV],
[libavformat$LIBAV libavcodec$LIBAV libswscale$LIBAV libavutil$LIBAV libavfilter$LIBAV],
[av_init_packet], [libavcodec/avcodec.h],
[dnl Checks for misc libav and ffmpeg API differences
AC_MSG_CHECKING([whether libav libraries are ffmpeg])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <libavcodec/avcodec.h>
]], [[
#if LIBAVCODEC_VERSION_MICRO >= 100
/* ffmpeg uses 100+ as its micro version */
#else
#error libav provider is not ffmpeg
#endif
]])], [
[is_ffmpeg=yes]
AC_DEFINE([HAVE_FFMPEG], 1,
[Define to 1 if you have ffmpeg (not libav)])],
[[is_ffmpeg=no]])
AC_MSG_RESULT([$is_ffmpeg])
FORK_CHECK_DECLS([av_buffersrc_add_frame_flags],
[libavfilter/buffersrc.h])
FORK_CHECK_DECLS([av_buffersink_get_frame],
[libavfilter/buffersink.h])
FORK_CHECK_DECLS([avfilter_graph_parse_ptr],
[libavfilter/avfilter.h])
FORK_CHECK_DECLS([av_packet_unref], [libavcodec/avcodec.h])
FORK_CHECK_DECLS([av_packet_rescale_ts], [libavcodec/avcodec.h])
FORK_CHECK_DECLS([avformat_alloc_output_context2],
[libavformat/avformat.h])
FORK_CHECK_DECLS([av_frame_alloc], [libavutil/frame.h])
FORK_CHECK_DECLS([av_frame_get_best_effort_timestamp],
[libavutil/frame.h])
FORK_CHECK_DECLS([av_image_fill_arrays], [libavutil/imgutils.h])
FORK_CHECK_DECLS([av_image_get_buffer_size], [libavutil/imgutils.h])
AC_CHECK_HEADERS([libavutil/channel_layout.h libavutil/mathematics.h])
])
AC_CHECK_SIZEOF([void *])
dnl --- Begin configuring the options ---
dnl ALSA
FORK_ARG_WITH_CHECK([FORKED], [ALSA support], [alsa], [ALSA],
FORK_ARG_WITH_CHECK([FORKED_OPTS], [ALSA support], [alsa], [ALSA],
[alsa], [snd_mixer_open], [asoundlib.h])
AM_CONDITIONAL([COND_ALSA], [[test "x$with_alsa" = "xyes"]])
dnl PULSEAUDIO
FORK_ARG_WITH_CHECK([FORKED], [Pulseaudio support], [pulseaudio], [LIBPULSE],
FORK_ARG_WITH_CHECK([FORKED_OPTS], [Pulseaudio support], [pulseaudio], [LIBPULSE],
[libpulse], [pa_stream_get_state], [pulse/pulseaudio.h],
[AC_CHECK_FUNCS([pa_threaded_mainloop_set_name])])
AM_CONDITIONAL([COND_PULSEAUDIO], [[test "x$with_pulseaudio" = "xyes"]])
dnl Build with libcurl
FORK_ARG_WITH_CHECK([FORKED], [libcurl support], [libcurl], [LIBCURL],
FORK_ARG_WITH_CHECK([FORKED_OPTS], [libcurl support], [libcurl], [LIBCURL],
[libcurl], [curl_global_init], [curl/curl.h])
dnl Build with libevent_pthreads
FORK_ARG_WITH_CHECK([FORKED], [libevent_pthreads support], [libevent_pthreads],
[LIBEVENT_PTHREADS], [libevent_pthreads], [evthread_use_pthreads],
[event2/thread.h])
FORK_ARG_WITH_CHECK([FORKED_OPTS], [libevent_pthreads support],
[libevent_pthreads], [LIBEVENT_PTHREADS], [libevent_pthreads],
[evthread_use_pthreads], [event2/thread.h])
dnl Build with json-c
FORK_ARG_WITH_CHECK([FORKED], [json-c support], [json], [JSON_C],
FORK_ARG_WITH_CHECK([FORKED_OPTS], [json-c support], [json], [JSON_C],
[json-c >= 0.11], [json_tokener_parse], [json.h], [],
[FORK_MODULES_CHECK([FORKED], [JSON_C], [json],
[FORK_MODULES_CHECK([FORKED_OPTS], [JSON_C], [json],
[json_tokener_parse], [json.h],
[[with_json=yes]
AC_DEFINE([HAVE_JSON_C_OLD], 1,
@ -243,17 +271,17 @@ FORK_ARG_WITH_CHECK([FORKED], [json-c support], [json], [JSON_C],
)])
dnl Build with Avahi (or Bonjour if not)
FORK_ARG_WITH_CHECK([FORKED], [Avahi mDNS], [avahi], [AVAHI],
FORK_ARG_WITH_CHECK([FORKED_OPTS], [Avahi mDNS], [avahi], [AVAHI],
[avahi-client >= 0.6.24], [avahi_client_new], [avahi-client/client.h])
AS_IF([[test "x$with_avahi" = "xno"]],
[FORK_FUNC_REQUIRE([FORKED], [Bonjour DNS_SD], [DNSSD], [dns_sd],
[FORK_FUNC_REQUIRE([FORKED_OPTS], [Bonjour DNS_SD], [DNSSD], [dns_sd],
[DNSServiceGetAddrInfo], [dns_sd.h], [],
[AC_MSG_ERROR([[Avahi client or Bonjour DNS_SD required, please install one.]])])])
AM_CONDITIONAL([COND_AVAHI], [[test "x$with_avahi" = "xyes"]])
dnl iTunes playlists with libplist
FORK_ARG_ENABLE([iTunes Music Library XML support], [itunes], [ITUNES],
[FORK_MODULES_CHECK([FORKED], [LIBPLIST], [libplist >= 0.16],
[FORK_MODULES_CHECK([FORKED_OPTS], [LIBPLIST], [libplist >= 0.16],
[plist_dict_get_item], [plist/plist.h])])
AM_CONDITIONAL([COND_ITUNES], [[test "x$enable_itunes" = "xyes"]])
@ -263,14 +291,15 @@ FORK_ARG_ENABLE([Spotify support], [spotify], [SPOTIFY],
[AC_MSG_ERROR([[Spotify support requires json-c]])])
AS_IF([[test "x$with_libevent_pthreads" = "xno"]],
[AC_MSG_ERROR([[Spotify support requires libevent_pthreads]])])
AC_CHECK_HEADER([[libspotify/api.h]], [],
[AC_MSG_ERROR([[libspotify/api.h not found]])])
FORK_MODULES_CHECK([SPOTIFY], [LIBSPOTIFY], [libspotify],
[], [libspotify/api.h])
AC_DEFINE([HAVE_SPOTIFY_H], 1,
[Define to 1 if you have the <libspotify/api.h> header file.])
dnl Don't link to libspotify, but instead enable dynamic linking
dnl Don't link with libspotify, use dynamic linking
AC_SEARCH_LIBS([dlopen], [dl], [],
[AC_MSG_ERROR([[Spotify support requires dlopen]])])
AC_LIB_APPENDTOVAR([FORKED_CPPFLAGS], [-rdynamic])
FORK_VAR_PREPEND([FORKED_OPTS_CPPFLAGS], [$SPOTIFY_CPPFLAGS])
FORK_VAR_PREPEND([FORKED_OPTS_LIBS], [-rdynamic])
])
AM_CONDITIONAL([COND_SPOTIFY], [[test "x$enable_spotify" = "xyes"]])
@ -284,10 +313,10 @@ dnl ChromeCast support with libprotobuf-c
FORK_ARG_ENABLE([Chromecast support], [chromecast], [CHROMECAST],
[AS_IF([[test "x$with_json" = "xno"]],
[AC_MSG_ERROR([[Chromecast support requires json-c]])])
FORK_MODULES_CHECK([FORKED], [LIBPROTOBUF_C],
FORK_MODULES_CHECK([FORKED_OPTS], [LIBPROTOBUF_C],
[libprotobuf-c >= 1.0.0], [protobuf_c_message_pack],
[protobuf-c/protobuf-c.h], [],
[FORK_FUNC_REQUIRE([FORKED], [v0 libprotobuf-c],
[FORK_FUNC_REQUIRE([FORKED_OPTS], [v0 libprotobuf-c],
[LIBPROTOBUF_OLD], [protobuf-c],
[protobuf_c_message_pack],
[google/protobuf-c/protobuf-c.h],
@ -296,7 +325,7 @@ FORK_ARG_ENABLE([Chromecast support], [chromecast], [CHROMECAST],
[protobuf_old=yes]],
[AC_MSG_ERROR([[Chromecast support requires protobuf-c]])])
])
FORK_MODULES_CHECK([FORKED], [GNUTLS], [gnutls], [gnutls_init],
FORK_MODULES_CHECK([FORKED_OPTS], [GNUTLS], [gnutls], [gnutls_init],
[gnutls/gnutls.h])
])
AM_CONDITIONAL([COND_CHROMECAST], [[test "x$enable_chromecast" = "xyes"]])

View File

@ -1,4 +1,4 @@
# fork_checks.m4 serial 1
# fork_checks.m4 serial 2
dnl Copyright (c) Scott Shambarger <devel@shambarger.net>
dnl
dnl Copying and distribution of this file, with or without modification, are
@ -6,36 +6,49 @@ dnl permitted in any medium without royalty provided the copyright notice
dnl and this notice are preserved. This file is offered as-is, without any
dnl warranty.
dnl _FORK_CFLAGS_APPEND(TARGET, SOURCE)
dnl -----------------------------------
dnl Internal use only. Shamelessly copied from AC_LIB_APPENDTOVAR,
dnl but without prefix expansion that breaks nesting.
m4_define([_FORK_CFLAGS_APPEND],
[[
for element in $2; do
haveit=
for x in $$1; do
dnl _FORK_FUNC_MERGE
dnl ----------------
dnl Internal only. Defines function used by FORK_VAR_PREPEND
AC_DEFUN([_FORK_FUNC_MERGE], [[
# fork_fn_merge(before, after)
# create wordlist removing duplicates
fork_fn_merge() {
fork_fn_var_result=$][1
for element in $][2; do
fork_fn_var_haveit=
for x in $fork_fn_var_result; do
if test "X$x" = "X$element"; then
haveit=yes
fork_fn_var_haveit=1
break
fi
done
if test -z "$haveit"; then
$1="${$1}${$1:+ }$element"
if test -z "$fork_fn_var_haveit"; then
fork_fn_var_result="${fork_fn_var_result}${fork_fn_var_result:+ }$element"
fi
done
]])
echo "$fork_fn_var_result"
unset fork_fn_var_haveit
unset fork_fn_var_result
}]])
dnl FORK_VARS_APPEND(TARGET, LIBS_ENV, CFLAGS_ENV)
dnl ----------------------------------------------
dnl FORK_VAR_PREPEND(VARNAME, BEFORE)
dnl ---------------------------------
dnl Prepends words in BEFORE to the contents of VARNAME, skipping any
dnl duplicate words.
AC_DEFUN([FORK_VAR_PREPEND],
[AC_REQUIRE([_FORK_FUNC_MERGE])dnl
[ $1=$(fork_fn_merge "$2" "$$1")]])
dnl FORK_VARS_PREPEND(TARGET, LIBS_ENV, CFLAGS_ENV)
dnl -----------------------------------------------
dnl Prepend LIBS_ENV to LIBS and TARGET_LIBS
dnl Append CFLAGS_ENV to CPPFLAGS and TARGET_CPPFLAGS.
AC_DEFUN([FORK_VARS_APPEND],
AC_DEFUN([FORK_VARS_PREPEND],
[[
LIBS="$$2 $LIBS"
$1_LIBS="$$2 $$1_LIBS"]
_FORK_CFLAGS_APPEND([CPPFLAGS], [$$3])
_FORK_CFLAGS_APPEND([$1_CPPFLAGS], [$$3])
FORK_VAR_PREPEND([CPPFLAGS], [$$3])
FORK_VAR_PREPEND([$1_CPPFLAGS], [$$3])
])
dnl _FORK_VARS_ADD_PREFIX(TARGET)
@ -49,11 +62,23 @@ AC_DEFUN([_FORK_VARS_ADD_PREFIX],
eval LIBS=\"-L$libdir $LIBS\"
eval $1_LIBS=\"-L$libdir $$1_LIBS\"
eval fork_tmp_cppflags=\"-I$includedir\"]
_FORK_CFLAGS_APPEND([CPPFLAGS], [$fork_tmp_cppflags])
_FORK_CFLAGS_APPEND([$1_CPPFLAGS], [$fork_tmp_cppflags])
FORK_VAR_PREPEND([CPPFLAGS], [$fork_tmp_cppflags])
FORK_VAR_PREPEND([$1_CPPFLAGS], [$fork_tmp_cppflags])
])
])
dnl FORK_CHECK_DECLS(SYMBOLS, INCLUDE, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl -----------------------------------------------------
dnl Expands AC_CHECK_DECLS with SYMBOLS and INCLUDE appended to
dnl AC_INCLUDES_DEFAULT.
dnl NOTE: Remember that AC_CHECK_DECLS defines HAVE_* to 1 or 0
dnl (not 1 or undefined!)
AC_DEFUN([FORK_CHECK_DECLS],
[AC_CHECK_DECLS([$1], [$3], [$4], [AC_INCLUDES_DEFAULT
[@%:@include <$2>]])
])
dnl FORK_FUNC_REQUIRE(TARGET, DESCRIPTION, ENV, LIBRARY, FUNCTION, [HEADER],
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl ------------------------------------------------------------------------
@ -81,7 +106,7 @@ AC_DEFUN([FORK_FUNC_REQUIRE],
AS_VAR_SET([FORK_MSG], [["
Library specific environment variables $3_LIBS and
$3_CFLAGS were used, verify they are correct..."]])
FORK_VARS_APPEND([$1], [$3_LIBS], [$3_CFLAGS])
FORK_VARS_PREPEND([$1], [$3_LIBS], [$3_CFLAGS])
AC_CHECK_FUNC([[$5]], [],
[AC_MSG_FAILURE([[Unable to link function $5 with $2.$]FORK_MSG])])],
[dnl Search w/o LIBRARY, w/ LIBRARY, and finally adding $prefix path
@ -125,7 +150,7 @@ dnl overriding default error. Restores original CPPFLAGS and LIBS when done.
AC_DEFUN([FORK_MODULES_CHECK],
[PKG_CHECK_MODULES([$2], [[$3]],
[[fork_save_$2_LIBS=$LIBS; fork_save_$2_CPPFLAGS=$CPPFLAGS]
FORK_VARS_APPEND([$1], [$2_LIBS], [$2_CFLAGS])
FORK_VARS_PREPEND([$1], [$2_LIBS], [$2_CFLAGS])
m4_ifval([$4], [AC_CHECK_FUNC([[$4]], [],
[AC_MSG_ERROR([[Unable to link function $4]])])])
m4_ifval([$5], [AC_CHECK_HEADER([[$5]], [],

View File

@ -66,6 +66,7 @@ ANTLR_SRC = \
AM_CPPFLAGS += \
$(FORKED_CPPFLAGS) \
$(FORKED_OPTS_CPPFLAGS) \
$(COMMON_CPPFLAGS) \
\
-D_GNU_SOURCE \
@ -76,6 +77,7 @@ AM_CPPFLAGS += \
forked_daapd_LDADD = \
$(FORKED_LIBS) \
$(FORKED_OPTS_LIBS) \
$(COMMON_LIBS)
forked_daapd_SOURCES = main.c \

View File

@ -508,7 +508,7 @@ artwork_rescale(struct evbuffer *evbuf, AVFormatContext *src_ctx, int s, int out
goto out_free_frames;
}
#ifdef HAVE_AV_IMAGE_FILL_ARRAYS
#if HAVE_DECL_AV_IMAGE_FILL_ARRAYS
av_image_fill_arrays(o_frame->data, o_frame->linesize, buf, dst->pix_fmt, src->width, src->height, 1);
#else
avpicture_fill((AVPicture *)o_frame, buf, dst->pix_fmt, src->width, src->height);

View File

@ -13,24 +13,24 @@
# define avcodec_find_best_pix_fmt_of_list(a, b, c, d) avcodec_find_best_pix_fmt2((enum AVPixelFormat *)(a), (b), (c), (d))
#endif
#ifndef HAVE_AV_FRAME_ALLOC
#if !HAVE_DECL_AV_FRAME_ALLOC
# define av_frame_alloc() avcodec_alloc_frame()
# define av_frame_free(x) avcodec_free_frame((x))
#endif
#ifndef HAVE_AV_FRAME_GET_BEST_EFFORT_TIMESTAMP
#if !HAVE_DECL_AV_FRAME_GET_BEST_EFFORT_TIMESTAMP
# define av_frame_get_best_effort_timestamp(x) (x)->pts
#endif
#ifndef HAVE_AV_IMAGE_GET_BUFFER_SIZE
#if !HAVE_DECL_AV_IMAGE_GET_BUFFER_SIZE
# define av_image_get_buffer_size(a, b, c, d) avpicture_get_size((a), (b), (c))
#endif
#ifndef HAVE_AV_PACKET_UNREF
#if !HAVE_DECL_AV_PACKET_UNREF
# define av_packet_unref(a) av_free_packet((a))
#endif
#ifndef HAVE_AV_PACKET_RESCALE_TS
#if !HAVE_DECL_AV_PACKET_RESCALE_TS
__attribute__((unused)) static void
av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
{
@ -45,7 +45,7 @@ av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
}
#endif
#ifndef HAVE_AVFORMAT_ALLOC_OUTPUT_CONTEXT2
#if !HAVE_DECL_AVFORMAT_ALLOC_OUTPUT_CONTEXT2
# include <libavutil/opt.h>
__attribute__((unused)) static int

View File

@ -33,14 +33,7 @@
#include <libavutil/time.h>
#include <libavutil/pixdesc.h>
#ifdef HAVE_LIBAVFILTER
# ifdef HAVE_LIBAVUTIL_CHANNEL_LAYOUT_H
# include <libavutil/channel_layout.h>
# endif
# include <libavfilter/avcodec.h>
#else
# include "ffmpeg-compat.h"
#endif
#include "ffmpeg-compat.h"
#include "logger.h"
#include "conffile.h"
@ -408,7 +401,7 @@ encode_write_frame(struct encode_ctx *ctx, AVFrame *filt_frame, unsigned int str
return ret;
}
#if defined(HAVE_AV_BUFFERSRC_ADD_FRAME_FLAGS) && defined(HAVE_AV_BUFFERSINK_GET_FRAME)
#if HAVE_DECL_AV_BUFFERSRC_ADD_FRAME_FLAGS && HAVE_DECL_AV_BUFFERSINK_GET_FRAME
static int
filter_encode_write_frame(struct encode_ctx *ctx, AVFrame *frame, unsigned int stream_index)
{
@ -863,7 +856,7 @@ close_output(struct encode_ctx *ctx)
avformat_free_context(ctx->ofmt_ctx);
}
#ifdef HAVE_AVFILTER_GRAPH_PARSE_PTR
#if HAVE_DECL_AVFILTER_GRAPH_PARSE_PTR
static int
open_filter(struct filter_ctx *filter_ctx, AVCodecContext *dec_ctx, AVCodecContext *enc_ctx, const char *filter_spec)
{