avioflow 0.7.3

High-performance audio decoding, encoding and resampling powered by FFmpeg
include(FetchContent)
include(CheckCXXSourceCompiles)

set(_ffmpeg_release_base "https://github.com/lxp3/ffmpeg-build/releases/download/v0.3.4")

function(_avioflow_normalize_arch out_var)
    if(WIN32 AND CMAKE_GENERATOR_PLATFORM)
        string(TOLOWER "${CMAKE_GENERATOR_PLATFORM}" _processor)
    elseif(WIN32 AND CMAKE_VS_PLATFORM_NAME)
        string(TOLOWER "${CMAKE_VS_PLATFORM_NAME}" _processor)
    else()
        string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _processor)
    endif()

    if(_processor MATCHES "^(x86_64|amd64|x64)$")
        set(${out_var} "x86_64" PARENT_SCOPE)
    elseif(_processor MATCHES "^(aarch64|arm64|arm64ec|arm64.*)$")
        set(${out_var} "aarch64" PARENT_SCOPE)
    else()
        message(FATAL_ERROR
            "Unsupported FFmpeg architecture: ${_processor}. "
            "Supported architectures: x86_64, aarch64."
        )
    endif()
endfunction()

function(_avioflow_remove_unavailable_atomic)
    if(NOT (UNIX AND NOT APPLE AND NOT BUILD_SHARED_LIBS))
        return()
    endif()

    set(_avioflow_saved_required_libraries "${CMAKE_REQUIRED_LIBRARIES}")
    set(CMAKE_REQUIRED_LIBRARIES atomic)
    check_cxx_source_compiles("int main() { return 0; }" AVIOFLOW_HAVE_LIBATOMIC)
    set(CMAKE_REQUIRED_LIBRARIES "${_avioflow_saved_required_libraries}")

    if(AVIOFLOW_HAVE_LIBATOMIC)
        return()
    endif()

    foreach(_ffmpeg_target ffmpeg::ffmpeg ffmpeg::avdevice ffmpeg::avfilter ffmpeg::avformat ffmpeg::avcodec ffmpeg::swscale ffmpeg::swresample ffmpeg::avutil)
        if(TARGET ${_ffmpeg_target})
            get_target_property(_ffmpeg_links ${_ffmpeg_target} INTERFACE_LINK_LIBRARIES)
            if(_ffmpeg_links)
                list(REMOVE_ITEM _ffmpeg_links atomic)
                set_target_properties(${_ffmpeg_target} PROPERTIES
                    INTERFACE_LINK_LIBRARIES "${_ffmpeg_links}"
                )
            endif()
        endif()
    endforeach()
endfunction()

if(EMSCRIPTEN)
    include(cmake/ffmpeg-wasm.cmake)
    return()
endif()

_avioflow_normalize_arch(_ffmpeg_arch)

if(BUILD_SHARED_LIBS)
    set(_ffmpeg_linkage "shared")
else()
    set(_ffmpeg_linkage "static")
endif()

if(WIN32)
    if(BUILD_SHARED_LIBS)
        set(_ffmpeg_platform "w64-mingw32")
    else()
        set(_ffmpeg_platform "msvc")
    endif()
elseif(APPLE)
    set(_ffmpeg_platform "macos")
else()
    set(_ffmpeg_platform "linux-gnu")
endif()

set(_ffmpeg_package "ffmpeg-7.1-${_ffmpeg_linkage}-${_ffmpeg_arch}-${_ffmpeg_platform}.tar.gz")
set(FFMPEG_URL "${_ffmpeg_release_base}/${_ffmpeg_package}")

if(_ffmpeg_package STREQUAL "ffmpeg-7.1-static-x86_64-linux-gnu.tar.gz")
    set(FFMPEG_HASH "20830ece2d6d3716af0b71a412d6565be1760e277bd5ee14ba07c52dcc6f55c0")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-static-aarch64-linux-gnu.tar.gz")
    set(FFMPEG_HASH "a258959964d2be85dd5757a0315b6cb154a3b2eec1c0232b2e274ea7ead6487a")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-shared-x86_64-linux-gnu.tar.gz")
    set(FFMPEG_HASH "d3e4c011bf82a794bc48420b12245dcf0ac208baa1452179e8397edcbba264ff")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-shared-aarch64-linux-gnu.tar.gz")
    set(FFMPEG_HASH "fa7d118748edf48f7270193ca29ea23fd4a44377b8b1a7414214838dd39dbde9")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-static-x86_64-macos.tar.gz")
    set(FFMPEG_HASH "b171fb6bba99c0e51de10784ee281fd8da56ea247e49512f4bf6dd920c229748")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-static-aarch64-macos.tar.gz")
    set(FFMPEG_HASH "72ffc438538d142128ee6cf098d55965791a01410a18095372ca971faefb27eb")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-shared-x86_64-macos.tar.gz")
    set(FFMPEG_HASH "32ba6c47919ddb5650f6624513519649cfbc654849c6ab7d57a0b2081ba269fe")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-shared-aarch64-macos.tar.gz")
    set(FFMPEG_HASH "4b86e038e9a27adf5d16c478995806ff32dcd7deda5c4710f12467e0e860116d")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-static-x86_64-msvc.tar.gz")
    set(FFMPEG_HASH "9320cfee3c05c70d0db0319584e6aea8fba930bbec69bcf2d1c2cc99ed10eab7")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-static-aarch64-msvc.tar.gz")
    set(FFMPEG_HASH "93dca5646c19f0117bee990260ab72a84c29b8cf89b4de7bc27214be210b29da")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-shared-x86_64-w64-mingw32.tar.gz")
    set(FFMPEG_HASH "5a64f04ed9e3db27e8074bc3b27fa7504d4829b2ca42e914ac58d2d3d35f11b3")
elseif(_ffmpeg_package STREQUAL "ffmpeg-7.1-shared-aarch64-w64-mingw32.tar.gz")
    set(FFMPEG_HASH "a8b7278921d1822c7b7d92ccc389e86ac98c1d81e6a6f6ef08706be22dd2b017")
else()
    message(FATAL_ERROR "Unsupported FFmpeg package selection: ${_ffmpeg_package}")
endif()

message(STATUS "FFmpeg package: ${_ffmpeg_package}")
message(STATUS "FFmpeg URL: ${FFMPEG_URL}")

set(_ffmpeg_fetch_args
    URL ${FFMPEG_URL}
    URL_HASH SHA256=${FFMPEG_HASH}
    DOWNLOAD_NO_PROGRESS FALSE
)

if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
    list(APPEND _ffmpeg_fetch_args DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
    if(POLICY CMP0135)
        cmake_policy(SET CMP0135 NEW)
    endif()
endif()

set(FETCHCONTENT_QUIET OFF CACHE BOOL "" FORCE)
FetchContent_Declare(ffmpeg_bin ${_ffmpeg_fetch_args})
FetchContent_MakeAvailable(ffmpeg_bin)
FetchContent_GetProperties(ffmpeg_bin SOURCE_DIR FFMPEG_EXTRACT_DIR)

if(EXISTS "${FFMPEG_EXTRACT_DIR}/lib/cmake/FFmpeg/FFmpegConfig.cmake")
    set(FFMPEG_ROOT "${FFMPEG_EXTRACT_DIR}")
else()
    file(GLOB _ffmpeg_candidates "${FFMPEG_EXTRACT_DIR}/ffmpeg-*")
    set(FFMPEG_ROOT "")
    foreach(_ffmpeg_candidate IN LISTS _ffmpeg_candidates)
        if(EXISTS "${_ffmpeg_candidate}/lib/cmake/FFmpeg/FFmpegConfig.cmake")
            set(FFMPEG_ROOT "${_ffmpeg_candidate}")
            break()
        endif()
    endforeach()
endif()

if(NOT FFMPEG_ROOT)
    message(FATAL_ERROR
        "Downloaded FFmpeg package does not contain lib/cmake/FFmpeg/FFmpegConfig.cmake. "
        "Package: ${_ffmpeg_package}; extract dir: ${FFMPEG_EXTRACT_DIR}"
    )
endif()

set(FFMPEG_ROOT "${FFMPEG_ROOT}" CACHE PATH "FFmpeg root" FORCE)
set(FFmpeg_DIR "${FFMPEG_ROOT}/lib/cmake/FFmpeg" CACHE PATH "FFmpeg CMake package directory" FORCE)

message(STATUS "FFmpeg Root set to: ${FFMPEG_ROOT}")
find_package(FFmpeg CONFIG REQUIRED)
_avioflow_remove_unavailable_atomic()

set(FFMPEG_INCLUDE_DIRS "${FFmpeg_INCLUDE_DIR}")
set(FFMPEG_LIB_DIR "${FFmpeg_LIBRARY_DIR}")
set(FFMPEG_BIN_DIR "${FFmpeg_BINARY_DIR}")