diff --git a/CMakeLists.txt b/CMakeLists.txt index e96c61dd..6979022a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,14 +73,17 @@ include_directories(${p8-platform_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIRS} ${KODI_INCLUDE_DIR}/..) # Hack way with "/..", need bigger Kodi cmake rework to match right include ways (becomes done in future) +# We don't add FFMPEG_LIBRARIES here as we handle them at the end list(APPEND DEPLIBS ${p8-platform_LIBRARIES} - ${FFMPEG_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES}) + if(WIN32) + # Windows does need to know about FFMPEG_LIBRARIES here list(APPEND DEPLIBS ${ICONV_LIBRARIES} ${OPENSSL_LIBRARIES} - ${LIBXML2_LIBRARIES}) + ${LIBXML2_LIBRARIES} + ${FFMPEG_LIBRARIES}) endif() # to see linker output @@ -102,11 +105,9 @@ if(CORE_SYSTEM_NAME STREQUAL osx OR ${COCOA} ${COREFOUNDATION} ${COREMEDIA} - ${COREVIDEO} ${COREMEDIAIO} ${VIDEOTOOLBOX} - ${SECURITY} - ${COCOA}) + ${SECURITY}) list(APPEND DEPLIBS ${AUDIOTOOLBOX} ${COREFOUNDATION} ${COREMEDIA} ${VIDEOTOOLBOX} ${SECURITY}) endif() @@ -116,6 +117,12 @@ add_definitions(-DCATCHUP_VERSION=${CATCHUP_VERSION}) build_addon(inputstream.ffmpegdirect CATCHUP DEPLIBS) +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # Due to a bug in CMake and frameworks on OSX we strip them from FFMPEG_LDFLAGS + # and along with the ';''s and allow CMake to add them back + string(REGEX REPLACE "-framework;([A-Za-z0-9_]+);?" "" FFMPEG_LDFLAGS "${FFMPEG_LDFLAGS}") + string(REGEX REPLACE ";" " " FFMPEG_LDFLAGS "${FFMPEG_LDFLAGS}") +endif() set_target_properties(inputstream.ffmpegdirect PROPERTIES LINK_FLAGS "${FFMPEG_LDFLAGS}") if(CORE_SYSTEM_NAME STREQUAL windowsstore) diff --git a/depends/common/gnutls/03-include-libdl-if-available.patch b/depends/common/gnutls/03-include-libdl-if-available.patch new file mode 100644 index 00000000..30757203 --- /dev/null +++ b/depends/common/gnutls/03-include-libdl-if-available.patch @@ -0,0 +1,26 @@ +diff --git a/configure.ac b/configure.ac +index db1ce841f..264712b56 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -512,6 +512,9 @@ LT_INIT([disable-static,win32-dll,shared]) + + + AC_LIB_HAVE_LINKFLAGS(dl,, [#include ], [dladdr (0, 0);]) ++if test "x$HAVE_LIBDL" = "xyes"; then ++ AC_SUBST([LIBDL], [-ldl]) ++fi + + AC_ARG_ENABLE(fips140-mode, + AS_HELP_STRING([--enable-fips140-mode], [enable FIPS140-2 mode]), +diff --git a/lib/gnutls.pc.in b/lib/gnutls.pc.in +index ffad3e168..15b990764 100644 +--- a/lib/gnutls.pc.in ++++ b/lib/gnutls.pc.in +@@ -19,6 +19,6 @@ Description: Transport Security Layer implementation for the GNU system + URL: https://www.gnutls.org/ + Version: @VERSION@ + Libs: -L${libdir} -lgnutls +-Libs.private: @LIBINTL@ @LIBSOCKET@ @INET_PTON_LIB@ @LIBPTHREAD@ @LIB_SELECT@ @TSS_LIBS@ @GMP_LIBS@ @LIBUNISTRING@ @LIBIDN2_LIBS@ @LIBATOMIC_LIBS@ ++Libs.private: @LIBINTL@ @LIBSOCKET@ @INET_PTON_LIB@ @LIBPTHREAD@ @LIB_SELECT@ @TSS_LIBS@ @GMP_LIBS@ @LIBUNISTRING@ @LIBIDN2_LIBS@ @LIBATOMIC_LIBS@ @LIBDL@ + @GNUTLS_REQUIRES_PRIVATE@ + Cflags: -I${includedir} diff --git a/inputstream.ffmpegdirect/addon.xml.in b/inputstream.ffmpegdirect/addon.xml.in index e09b9192..1b9042a1 100644 --- a/inputstream.ffmpegdirect/addon.xml.in +++ b/inputstream.ffmpegdirect/addon.xml.in @@ -1,7 +1,7 @@ @ADDON_DEPENDS@ @@ -17,6 +17,11 @@ InputStream Client for streams that can be opened by FFmpeg's libavformat such as plain TS, HLS and DASH (without DRM) streams. The addon also has support for Archive/Catchup services where there is a replay windows (usually in days) and can timeshift across that span. For documenation visit: https://github.com/xbmc/inputstream.ffmpegdirect/blob/Matrix/README.md @PLATFORM@ +v1.4.0 +- Added: gnutls patch to add libdl to support newer OSes +- Added: Add support for mms and rtp/udp streams with sources +- Fixed: Add workaround for CMake and Frameworks on Darwin + v1.3.0 - Added: Support for Windows and iOS - Update: To gmp-6.2.0 diff --git a/inputstream.ffmpegdirect/changelog.txt b/inputstream.ffmpegdirect/changelog.txt index 6d0194df..552730c4 100644 --- a/inputstream.ffmpegdirect/changelog.txt +++ b/inputstream.ffmpegdirect/changelog.txt @@ -1,3 +1,8 @@ +v1.4.0 +- Added: gnutls patch to add libdl to support newer OSes +- Added: Add support for mms and rtp/udp streams with sources +- Fixed: Add workaround for CMake and Frameworks on Darwin + v1.3.0 - Added: Support for Windows and iOS - Update: To gmp-6.2.0 diff --git a/src/StreamManager.cpp b/src/StreamManager.cpp index 5db26f08..2422ecb5 100644 --- a/src/StreamManager.cpp +++ b/src/StreamManager.cpp @@ -37,12 +37,12 @@ CInputStreamLibavformat::~CInputStreamLibavformat() bool CInputStreamLibavformat::Open(INPUTSTREAM& props) { - kodi::Log(ADDON_LOG_NOTICE, "inputstream.ffmpegdirect: OpenStream() - Num Props: %d", props.m_nCountInfoValues); + Log(LOGLEVEL_NOTICE, "inputstream.ffmpegdirect: OpenStream() - Num Props: %d", props.m_nCountInfoValues); std::string tempString; for (size_t i = 0; i < props.m_nCountInfoValues; ++i) { - kodi::Log(ADDON_LOG_NOTICE, "inputstream.ffmpegdirect property: %s = %s", props.m_ListItemProperties[i].m_strKey, props.m_ListItemProperties[i].m_strValue); + Log(LOGLEVEL_NOTICE, "inputstream.ffmpegdirect property: %s = %s", props.m_ListItemProperties[i].m_strKey, props.m_ListItemProperties[i].m_strValue); if (MIME_TYPE == props.m_ListItemProperties[i].m_strKey) { @@ -143,7 +143,7 @@ void CInputStreamLibavformat::Close() void CInputStreamLibavformat::GetCapabilities(INPUTSTREAM_CAPABILITIES &caps) { - kodi::Log(ADDON_LOG_DEBUG, "GetCapabilities()"); + Log(LOGLEVEL_DEBUG, "GetCapabilities()"); m_stream->GetCapabilities(caps); } @@ -200,7 +200,7 @@ void CInputStreamLibavformat::DemuxSetSpeed(int speed) void CInputStreamLibavformat::SetVideoResolution(int width, int height) { - kodi::Log(ADDON_LOG_NOTICE, "inputstream.ffmpegdirect: SetVideoResolution()"); + Log(LOGLEVEL_NOTICE, "inputstream.ffmpegdirect: SetVideoResolution()"); m_videoWidth = width; m_videoHeight = height; diff --git a/src/stream/FFmpegCatchupStream.cpp b/src/stream/FFmpegCatchupStream.cpp index 1e56043b..f807618e 100644 --- a/src/stream/FFmpegCatchupStream.cpp +++ b/src/stream/FFmpegCatchupStream.cpp @@ -126,7 +126,7 @@ DemuxPacket* FFmpegCatchupStream::DemuxRead() void FFmpegCatchupStream::GetCapabilities(INPUTSTREAM_CAPABILITIES& caps) { - kodi::Log(ADDON_LOG_DEBUG, "GetCapabilities()"); + Log(LOGLEVEL_DEBUG, "GetCapabilities()"); caps.m_mask = INPUTSTREAM_CAPABILITIES::SUPPORTS_IDEMUX | // INPUTSTREAM_CAPABILITIES::SUPPORTS_IDISPLAYTIME | INPUTSTREAM_CAPABILITIES::SUPPORTS_ITIME | diff --git a/src/stream/FFmpegStream.cpp b/src/stream/FFmpegStream.cpp index 88a3519f..498b00f0 100644 --- a/src/stream/FFmpegStream.cpp +++ b/src/stream/FFmpegStream.cpp @@ -111,7 +111,7 @@ FFmpegStream::~FFmpegStream() bool FFmpegStream::Open(const std::string& streamUrl, const std::string& mimeType, bool isRealTimeStream, const std::string& programProperty) { - kodi::Log(ADDON_LOG_DEBUG, "inputstream.ffmpegdirect: OpenStream()"); + Log(LOGLEVEL_DEBUG, "inputstream.ffmpegdirect: OpenStream()"); m_streamUrl = streamUrl; m_mimeType = mimeType; @@ -147,7 +147,7 @@ void FFmpegStream::Close() void FFmpegStream::GetCapabilities(INPUTSTREAM_CAPABILITIES &caps) { - kodi::Log(ADDON_LOG_DEBUG, "GetCapabilities()"); + Log(LOGLEVEL_DEBUG, "GetCapabilities()"); caps.m_mask = INPUTSTREAM_CAPABILITIES::SUPPORTS_IDEMUX | // INPUTSTREAM_CAPABILITIES::SUPPORTS_IDISPLAYTIME | // INPUTSTREAM_CAPABILITIES::SUPPORTS_ITIME | @@ -840,30 +840,72 @@ bool FFmpegStream::OpenWithAVFormat(AVInputFormat* iformat, const AVIOInterruptC CURL url; url.Parse(m_streamUrl); + std::string strFile = m_streamUrl; - m_pFormatContext->flags |= AVFMT_FLAG_PRIV_OPT; - if (avformat_open_input(&m_pFormatContext, m_streamUrl.c_str(), iformat, &options) < 0) + int result = -1; + if (url.IsProtocol("mms")) { - Log(LOGLEVEL_DEBUG, "Error, could not open file %s", CURL::GetRedacted(m_streamUrl).c_str()); - Dispose(); - av_dict_free(&options); - return false; + // try mmsh, then mmst + url.SetProtocol("mmsh"); + url.SetProtocolOptions(""); + result = avformat_open_input(&m_pFormatContext, url.Get().c_str(), iformat, &options); + if (result < 0) + { + url.SetProtocol("mmst"); + strFile = url.Get(); + } } + else if (url.IsProtocol("udp") || url.IsProtocol("rtp")) + { + std::string strURL = url.Get(); + Log(LOGLEVEL_DEBUG, "CDVDDemuxFFmpeg::Open() UDP/RTP Original URL '%s'", strURL.c_str()); + size_t found = strURL.find("://"); + if (found != std::string::npos) + { + size_t start = found + 3; + found = strURL.find("@"); - av_dict_free(&options); - avformat_close_input(&m_pFormatContext); - m_pFormatContext = avformat_alloc_context(); - m_pFormatContext->interrupt_callback = int_cb; - m_pFormatContext->flags &= ~AVFMT_FLAG_PRIV_OPT; - options = GetFFMpegOptionsFromInput(); - av_dict_set_int(&options, "load_all_variants", 0, AV_OPT_SEARCH_CHILDREN); - - if (avformat_open_input(&m_pFormatContext, m_streamUrl.c_str(), iformat, &options) < 0) + if (found != std::string::npos && found > start) + { + // sourceip found + std::string strSourceIp = strURL.substr(start, found - start); + + strFile = strURL.substr(0, start); + strFile += strURL.substr(found); + if(strFile.back() == '/') + strFile.pop_back(); + strFile += "?sources="; + strFile += strSourceIp; + Log(LOGLEVEL_DEBUG, "CDVDDemuxFFmpeg::Open() UDP/RTP URL '%s'", strFile.c_str()); + } + } + } + if (result < 0) { - Log(LOGLEVEL_DEBUG, "Error, could not open file (2) %s", CURL::GetRedacted(m_streamUrl).c_str()); - Dispose(); + m_pFormatContext->flags |= AVFMT_FLAG_PRIV_OPT; + if (avformat_open_input(&m_pFormatContext, m_streamUrl.c_str(), iformat, &options) < 0) + { + Log(LOGLEVEL_DEBUG, "Error, could not open file %s", CURL::GetRedacted(m_streamUrl).c_str()); + Dispose(); + av_dict_free(&options); + return false; + } + av_dict_free(&options); - return false; + avformat_close_input(&m_pFormatContext); + m_pFormatContext = avformat_alloc_context(); + m_pFormatContext->interrupt_callback = int_cb; + m_pFormatContext->flags &= ~AVFMT_FLAG_PRIV_OPT; + options = GetFFMpegOptionsFromInput(); + av_dict_set_int(&options, "load_all_variants", 0, AV_OPT_SEARCH_CHILDREN); + + if (avformat_open_input(&m_pFormatContext, m_streamUrl.c_str(), iformat, &options) < 0) + { + Log(LOGLEVEL_DEBUG, "Error, could not open file (2) %s", CURL::GetRedacted(m_streamUrl).c_str()); + Dispose(); + av_dict_free(&options); + return false; + } } av_dict_free(&options); diff --git a/src/stream/url/URL.cpp b/src/stream/url/URL.cpp index 30f9a9ef..74eb0a8c 100644 --- a/src/stream/url/URL.cpp +++ b/src/stream/url/URL.cpp @@ -343,7 +343,9 @@ void CURL::Parse(const std::string& strURL1) if(iSlash >= iEnd) iSlash = std::string::npos; // was an invalid slash as it was contained in options - if( !IsProtocol("iso9660") ) + // also skip parsing username:password@ for udp/rtp as it not valid + // and conflicts with the following example: rtp://sourceip@multicastip + if (!IsProtocol("iso9660") && !IsProtocol("udp") && !IsProtocol("rtp")) { size_t iAlphaSign = strURL.find("@", iPos); if (iAlphaSign != std::string::npos && iAlphaSign < iEnd && (iAlphaSign < iSlash || iSlash == std::string::npos))