diff options
Diffstat (limited to 'cmake/FindFFmpeg.cmake')
-rw-r--r-- | cmake/FindFFmpeg.cmake | 289 |
1 files changed, 185 insertions, 104 deletions
diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 1ee312578..ecf9b07cb 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause #.rst: # FindFFmpeg # ---------- @@ -18,10 +20,7 @@ # :: # # FFMPEG_FOUND - System has the all required components. -# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. -# FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. -# FFMPEG_LIBRARY_DIRS - Link directories -# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. +# FFMPEG_SHARED_LIBRARIES - Found FFmpeg shared libraries. # # For each of the components it will additionally set. # @@ -59,8 +58,6 @@ # Copyright (c) 2011, Michael Jansen, <kde@michael-jansen.biz> # Copyright (c) 2017, Alexander Drozdov, <adrozdoff@gmail.com> # -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. include(FindPackageHandleStandardArgs) @@ -69,14 +66,42 @@ if (NOT FFmpeg_FIND_COMPONENTS) set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL) endif () +if (QT_DEPLOY_FFMPEG AND BUILD_SHARED_LIBS) + set(shared_libs_desired TRUE) +endif() + +# finds FFmpeg libs, including symlinks, for the specified component. +macro(find_shared_libs_for_component _component) + # the searching pattern is pretty rough but it seems to be sufficient to gather dynamic libs + get_filename_component(name_we ${${_component}_LIBRARY} NAME_WE) + + if (WIN32) + get_filename_component(dir_name ${${_component}_LIBRARY_DIR} NAME) + if (${dir_name} STREQUAL "lib" AND EXISTS "${${_component}_LIBRARY_DIR}/../bin") + # llvm-mingv builds aux ffmpeg static libs like lib/libavutil.dll.a and cmake finds + # only them even though the folder bin/ contains proper *.dll and *.lib. + + string(REGEX REPLACE "^lib" "" name_we "${name_we}") + set(shared_lib_pattern "../bin/${name_we}*${CMAKE_SHARED_LIBRARY_SUFFIX}") + else() + set(shared_lib_pattern "${name_we}*${CMAKE_SHARED_LIBRARY_SUFFIX}") + endif() + + else() + set(shared_lib_pattern "${name_we}*${CMAKE_SHARED_LIBRARY_SUFFIX}*") + endif() + + file(GLOB ${_component}_SHARED_LIBRARIES "${${_component}_LIBRARY_DIR}/${shared_lib_pattern}") +endmacro() + # ### Macro: set_component_found # -# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. +# Marks the given component as found if both *_LIBRARY_NAME AND *_INCLUDE_DIRS is present. # -macro(set_component_found _component ) - if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) - # message(STATUS " - ${_component} found.") +macro(set_component_found _component) + if (${_component}_LIBRARY_NAME AND ${_component}_INCLUDE_DIR) + # message(STATUS " - ${_component} found.") set(${_component}_FOUND TRUE) set(${CMAKE_FIND_PACKAGE_NAME}_${_component}_FOUND TRUE) else () @@ -114,7 +139,12 @@ macro(find_component _component _pkgconfig _library _header) list(APPEND CMAKE_FIND_ROOT_PATH "${FFMPEG_ROOT}") endif() - find_path(${_component}_INCLUDE_DIRS ${_header} + if (${_component}_INCLUDE_DIR AND NOT EXISTS ${${_component}_INCLUDE_DIR}) + message(STATUS "Cached include dir ${${_component}_INCLUDE_DIR} doesn't exist") + unset(${_component}_INCLUDE_DIR CACHE) + endif() + + find_path(${_component}_INCLUDE_DIR ${_header} HINTS ${PC_${_component}_INCLUDEDIR} ${PC_${_component}_INCLUDE_DIRS} @@ -125,7 +155,17 @@ macro(find_component _component _pkgconfig _library _header) ffmpeg include ) - find_library(${_component}_LIBRARY NAMES ${PC_${_component}_LIBRARIES} ${_library} + if (shared_libs_desired AND NOT WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_SHARED_LIBRARY_SUFFIX};${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif() + + if (${_component}_LIBRARY AND NOT EXISTS ${${_component}_LIBRARY}) + message(STATUS "Cached library ${${_component}_LIBRARY} doesn't exist") + unset(${_component}_LIBRARY CACHE) + endif() + + find_library(${_component}_LIBRARY + NAMES ${PC_${_component}_LIBRARIES} ${_library} HINTS ${PC_${_component}_LIBDIR} ${PC_${_component}_LIBRARY_DIRS} @@ -133,140 +173,185 @@ macro(find_component _component _pkgconfig _library _header) PATHS ${FFMPEG_DIR} PATH_SUFFIXES - lib + lib bin ) if(FFMPEG_DIR OR FFMPEG_ROOT) set(CMAKE_FIND_ROOT_PATH "${__find_ffmpeg_backup_root_dir}") endif() - get_filename_component(${_component}_LIBRARY_DIR_FROM_FIND ${${_component}_LIBRARY} DIRECTORY) - get_filename_component(${_component}_LIBRARY_FROM_FIND ${${_component}_LIBRARY} NAME) - - set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") - set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") - set(${_component}_LIBRARY_DIRS ${${_component}_LIBRARY_DIR_FROM_FIND} CACHE STRING "The ${_component} library dirs.") - set(${_component}_LIBRARIES ${${_component}_LIBRARY_FROM_FIND} CACHE STRING "The ${_component} libraries.") + if (${_component}_LIBRARY) + get_filename_component(${_component}_LIBRARY_DIR ${${_component}_LIBRARY} DIRECTORY) + get_filename_component(${_component}_LIBRARY_NAME ${${_component}_LIBRARY} NAME) -# message("Libs" ${FFMPEG_DIR} ${${_component}_LIBRARIES} ${${_component}_LIBRARY_DIRS}) + # On Windows, shared linking goes through 'integration' static libs, so we should look for shared ones anyway + # On Unix, we gather symlinks as well so that we could install them. + if (WIN32 OR ${${_component}_LIBRARY_NAME} MATCHES "\\${CMAKE_SHARED_LIBRARY_SUFFIX}$") + find_shared_libs_for_component(${_component}) + endif() -# message(STATUS "L0: ${${_component}_LIBRARIES}") -# message(STATUS "L1: ${PC_${_component}_LIBRARIES}") -# message(STATUS "L2: ${_library}") -# message(STATUS "L3: ${${_component}_LIBRARY}") -# message(STATUS "L4: ${${_component}_LIBRARY_DIRS}") + endif() + set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER}) set_component_found(${_component}) - mark_as_advanced( - ${_component}_LIBRARY - ${_component}_INCLUDE_DIRS - ${_component}_LIBRARY_DIRS - ${_component}_LIBRARIES - ${_component}_DEFINITIONS - ${_component}_VERSION) + mark_as_advanced(${_component}_LIBRARY) endmacro() # Clear the previously cached variables, because they are recomputed every time # the Find script is included. -set(FFMPEG_INCLUDE_DIRS "") -set(FFMPEG_LIBRARIES "") -set(FFMPEG_DEFINITIONS "") -set(FFMPEG_LIBRARY_DIRS "") +unset(FFMPEG_SHARED_LIBRARIES CACHE) +unset(FFMPEG_STUBS CACHE) + +# Check for components. +foreach (_component ${FFmpeg_FIND_COMPONENTS}) + string(TOLOWER ${_component} library) + find_component(${_component} "lib${library}" ${library} "lib${library}/${library}.h") + + if (${_component}_FOUND) + list(APPEND FFMPEG_LIBRARIES ${${_component}_LIBRARY_NAME}) + list(APPEND FFMPEG_DEFINITIONS ${${_component}_DEFINITIONS}) + list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIR}) + list(APPEND FFMPEG_LIBRARY_DIRS ${${_component}_LIBRARY_DIR}) + + if (${_component}_SHARED_LIBRARIES) + list(APPEND FFMPEG_SHARED_LIBRARIES ${${_component}_SHARED_LIBRARIES}) + list(APPEND FFMPEG_SHARED_COMPONENTS ${_component}) + else() + list(APPEND FFMPEG_STATIC_COMPONENTS ${_component}) + endif() + + mark_as_advanced(${_component}_LIBRARY_NAME ${_component}_DEFINITIONS ${_component}_INCLUDE_DIR + ${_component}_LIBRARY_DIR ${_component}_SHARED_LIBRARIES) + endif() +endforeach() + + +function(qt_internal_multimedia_try_add_dynamic_resolve_dependency _component dep) + set(dynamic_resolve_added FALSE PARENT_SCOPE) + + if (NOT ANDROID AND NOT LINUX) + return() + endif() + + set(supported_stubs "ssl|crypto|va|va-drm|va-x11") + if(${_component}_SHARED_LIBRARIES) + set(stub_prefix "Qt${PROJECT_VERSION_MAJOR}FFmpegStub-") + if (${dep} MATCHES "^${stub_prefix}(${supported_stubs})$") + string(REPLACE "${stub_prefix}" "" dep "${dep}") + set(FFMPEG_STUBS ${FFMPEG_STUBS} ${dep} CACHE INTERNAL "") + + set(dynamic_resolve_added TRUE PARENT_SCOPE) + endif() + elseif (${dep} MATCHES "^(${supported_stubs})$") + set(FFMPEG_STUBS ${FFMPEG_STUBS} ${dep} CACHE INTERNAL "") + set(dynamic_resolve_added TRUE PARENT_SCOPE) + endif() +endfunction() # Function parses package config file to find the static library dependencies # and adds them to the target library. -function(__ffmpeg_internal_set_dependencies lib) - set(PC_FILE ${FFMPEG_DIR}/lib/pkgconfig/lib${lib}.pc) +function(__ffmpeg_internal_set_dependencies _component) + string(TOLOWER ${_component} lib) + set(PC_FILE ${${_component}_LIBRARY_DIR}/pkgconfig/lib${lib}.pc) if(EXISTS ${PC_FILE}) file(READ ${PC_FILE} pcfile) - string(REGEX REPLACE ".*Libs:([A-Za-z0-9_. \${}-]+).*" "\\1" out "${pcfile}") - string(REGEX MATCHALL "\\-l[a-z0-9_-]+" libs_dependency ${out}) - string(REGEX MATCHALL "[A-Za-z0-9_-]+\\.lib" libs_dependency_lib ${out}) - - string(REGEX REPLACE ".*Libs.private:([A-Za-z0-9_. \${}-]+).*" "\\1" out "${pcfile}") - string(REGEX MATCHALL "\\-l[a-z0-9_-]+" libs_private_dependency ${out}) - string(REGEX MATCHALL "[A-Za-z0-9_-]+\\.lib" libs_private_dependency_lib ${out}) - - list(APPEND no_sufix ${libs_dependency} ${libs_private_dependency}) - list(APPEND lib_sufix ${libs_dependency_lib} ${libs_private_dependency_lib}) - - foreach(d ${no_sufix}) - string(REGEX REPLACE "\\-l" "" d ${d}) - if(NOT ${lib} MATCHES ${d}) - target_link_libraries(FFmpeg::${lib} INTERFACE ${d}) + set(prefix_l "(^| )\\-l") + set(suffix_lib "\\.lib($| )") + + string(REGEX REPLACE ".*Libs:([^\n\r]+).*" "\\1" out "${pcfile}") + string(REGEX MATCHALL "${prefix_l}[^ ]+" libs_dependency ${out}) + string(REGEX MATCHALL "[^ ]+${suffix_lib}" libs_dependency_lib ${out}) + + string(REGEX REPLACE ".*Libs.private:([^\n\r]+).*" "\\1" out "${pcfile}") + string(REGEX MATCHALL "${prefix_l}[^ ]+" libs_private_dependency ${out}) + string(REGEX MATCHALL "[^ ]+${suffix_lib}" libs_private_dependency_lib ${out}) + + list(APPEND deps_no_suffix ${libs_dependency} ${libs_private_dependency}) + foreach(dependency ${deps_no_suffix}) + string(REGEX REPLACE ${prefix_l} "" dependency ${dependency}) + if(NOT ${lib} STREQUAL ${dependency}) + qt_internal_multimedia_try_add_dynamic_resolve_dependency(${_component} ${dependency}) + if(NOT dynamic_resolve_added AND NOT ${_component}_SHARED_LIBRARIES) + target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency}) + endif() endif() endforeach() - foreach(d ${lib_sufix}) - string(REGEX REPLACE "\\.lib" "" d ${d}) - target_link_libraries(FFmpeg::${lib} INTERFACE ${d}) - endforeach() + + if(NOT ${_component}_SHARED_LIBRARIES) + list(APPEND deps_lib_suffix ${libs_dependency_lib} ${libs_private_dependency_lib}) + foreach(dependency ${deps_lib_suffix}) + string(REGEX REPLACE ${suffix_lib} "" dependency ${dependency}) + target_link_libraries(FFmpeg::${lib} INTERFACE ${dependency}) + endforeach() + endif() + else() + message(WARNING "FFmpeg pc file ${PC_FILE} is not found") endif() endfunction() # Check for cached results. If there are skip the costly part. #if (NOT FFMPEG_LIBRARIES) - # Check for all possible component. - find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) - find_component(AVFORMAT libavformat avformat libavformat/avformat.h) - find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) - find_component(AVUTIL libavutil avutil libavutil/avutil.h) - find_component(AVFILTER libavfilter avfilter libavfilter/avfilter.h) - find_component(SWSCALE libswscale swscale libswscale/swscale.h) - find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h) - find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h) - # Check if the required components were found and add their stuff to the FFMPEG_* vars. - foreach (_component ${FFmpeg_FIND_COMPONENTS}) - if (${_component}_FOUND) - # message(STATUS "Libs: ${${_component}_LIBRARIES} | ${PC_${_component}_LIBRARIES}") - - # message(STATUS "Required component ${_component} present.") - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARY} ${${_component}_LIBRARIES}) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS}) - list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) - list(APPEND FFMPEG_LIBRARY_DIRS ${${_component}_LIBRARY_DIRS}) + foreach (_component ${FFmpeg_FIND_COMPONENTS}) + if (${_component}_FOUND) string(TOLOWER ${_component} _lowerComponent) if (NOT TARGET FFmpeg::${_lowerComponent}) add_library(FFmpeg::${_lowerComponent} INTERFACE IMPORTED) set_target_properties(FFmpeg::${_lowerComponent} PROPERTIES INTERFACE_COMPILE_OPTIONS "${${_component}_DEFINITIONS}" - INTERFACE_INCLUDE_DIRECTORIES ${${_component}_INCLUDE_DIRS} - INTERFACE_LINK_LIBRARIES "${${_component}_LIBRARIES}" - INTERFACE_LINK_DIRECTORIES "${${_component}_LIBRARY_DIRS}" + INTERFACE_INCLUDE_DIRECTORIES ${${_component}_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES "${${_component}_LIBRARY_NAME}" + INTERFACE_LINK_DIRECTORIES "${${_component}_LIBRARY_DIR}" ) - __ffmpeg_internal_set_dependencies(${_lowerComponent}) - target_link_libraries(FFmpeg::${_lowerComponent} INTERFACE "${${_component}_LIBRARY}") + + __ffmpeg_internal_set_dependencies(${_component}) + target_link_libraries(FFmpeg::${_lowerComponent} INTERFACE "${${_component}_LIBRARY_NAME}") if (UNIX AND NOT APPLE) target_link_options(FFmpeg::${_lowerComponent} INTERFACE "-Wl,--exclude-libs=lib${_lowerComponent}") endif () - endif() - else() - # message(STATUS "Required component ${_component} missing.") + endif() endif() endforeach () # Build the include path with duplicates removed. - if (FFMPEG_INCLUDE_DIRS) - list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) - endif () + list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) + list(REMOVE_DUPLICATES FFMPEG_LIBRARY_DIRS) + list(REMOVE_DUPLICATES FFMPEG_SHARED_LIBRARIES) + list(REMOVE_DUPLICATES FFMPEG_STUBS) + + message(STATUS "FFmpeg shared libs: ${FFMPEG_SHARED_LIBRARIES}") + message(STATUS "FFmpeg stubs: ${FFMPEG_STUBS}") # cache the vars. - set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) - set(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBRARY_DIRS} CACHE STRING "The FFmpeg library dirs." FORCE) + set(FFMPEG_SHARED_LIBRARIES ${FFMPEG_SHARED_LIBRARIES} CACHE STRING "The FFmpeg dynamic libraries." FORCE) + set(FFMPEG_STUBS ${FFMPEG_STUBS} CACHE STRING "The FFmpeg stubs." FORCE) - mark_as_advanced(FFMPEG_INCLUDE_DIRS - FFMPEG_LIBRARIES - FFMPEG_DEFINITIONS - FFMPEG_LIBRARY_DIRS) + mark_as_advanced(FFMPEG_SHARED_LIBRARIES) + mark_as_advanced(FFMPEG_STUBS) +# endif () -#endif () +list(LENGTH FFMPEG_LIBRARY_DIRS DIRS_COUNT) +if (${DIRS_COUNT} GREATER 1) + message(WARNING "One ffmpeg library dir is expected, found dirs: ${FFMPEG_LIBRARY_DIRS}") +endif() + +if(FFMPEG_SHARED_COMPONENTS AND FFMPEG_STATIC_COMPONENTS) + message(WARNING + "Only static or shared components are expected\n" + " static components: ${FFMPEG_STATIC_COMPONENTS}\n" + " shared components: ${FFMPEG_SHARED_COMPONENTS}") +endif() + +if (shared_libs_desired AND NOT FFMPEG_SHARED_COMPONENTS) + message(WARNING + "Shared FFmpeg libs are desired as QT_DEPLOY_FFMPEG=TRUE, but haven't been found!\n" + "Remove QT_DEPLOY_FFMPEG or set the proper path to shared FFmpeg via FFMPEG_DIR.") +endif() if (NOT TARGET FFmpeg::FFmpeg) add_library(FFmpeg INTERFACE) @@ -274,19 +359,15 @@ if (NOT TARGET FFmpeg::FFmpeg) INTERFACE_COMPILE_OPTIONS "${FFMPEG_DEFINITIONS}" INTERFACE_INCLUDE_DIRECTORIES "${FFMPEG_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${FFMPEG_LIBRARIES}" - INTERFACE_LINK_DIRECTORIES "${FFMPEG_LIBRARY_DIRS}") + INTERFACE_LINK_DIRECTORIES "${FFMPEG_LIBRARY_DIRS}" + ) add_library(FFmpeg::FFmpeg ALIAS FFmpeg) endif() -# Now set the noncached _FOUND vars for the components. -foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE) - set_component_found(${_component}) -endforeach () - # Compile the list of required vars set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) foreach (_component ${FFmpeg_FIND_COMPONENTS}) - list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) + list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARY ${_component}_INCLUDE_DIR) endforeach () # Give a nice error message if some of the required vars are missing. |