ffmpeg: Move into its own component

While we're at it, let's also fix the invalid destructor, as well as the NVENC HEVC encoder incorrectly using H264.Level to store H265.Level.
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2023-09-06 02:48:42 +02:00 committed by Xaymar
parent d2a543f118
commit d5cf2d2ccf
38 changed files with 60 additions and 193 deletions

View file

@ -287,14 +287,6 @@ endif()
set(${PREFIX}VERSION "" CACHE STRING "Specify an override for the automatically detected version. Accepts a mixture of SemVer 2.0 and CMake Version.") set(${PREFIX}VERSION "" CACHE STRING "Specify an override for the automatically detected version. Accepts a mixture of SemVer 2.0 and CMake Version.")
# Features # Features
## Encoders
set(${PREFIX}ENABLE_ENCODER_FFMPEG ${FEATURE_STABLE} CACHE BOOL "Enable FFmpeg Encoder integration.")
set(${PREFIX}ENABLE_ENCODER_FFMPEG_AMF ${FEATURE_DEPRECATED} CACHE BOOL "Enable AMF Encoder in FFmpeg.")
set(${PREFIX}ENABLE_ENCODER_FFMPEG_NVENC ${FEATURE_STABLE} CACHE BOOL "Enable NVENC Encoder in FFmpeg.")
set(${PREFIX}ENABLE_ENCODER_FFMPEG_PRORES ${FEATURE_STABLE} CACHE BOOL "Enable ProRes Encoder in FFmpeg.")
set(${PREFIX}ENABLE_ENCODER_FFMPEG_DNXHR ${FEATURE_STABLE} CACHE BOOL "Enable DNXHR Encoder in FFmpeg.")
set(${PREFIX}ENABLE_ENCODER_FFMPEG_CFHD ${FEATURE_STABLE} CACHE BOOL "Enable CineForm Encoder in FFmpeg.")
## Filters ## Filters
set(${PREFIX}ENABLE_FILTER_AUTOFRAMING ${FEATURE_EXPERIMENTAL} CACHE BOOL "Enable Auto-Framing Filter") set(${PREFIX}ENABLE_FILTER_AUTOFRAMING ${FEATURE_EXPERIMENTAL} CACHE BOOL "Enable Auto-Framing Filter")
set(${PREFIX}ENABLE_FILTER_AUTOFRAMING_NVIDIA ${FEATURE_EXPERIMENTAL} CACHE BOOL "Enable NVIDIA provider(s) Auto-Framing Filter") set(${PREFIX}ENABLE_FILTER_AUTOFRAMING_NVIDIA ${FEATURE_EXPERIMENTAL} CACHE BOOL "Enable NVIDIA provider(s) Auto-Framing Filter")
@ -449,54 +441,6 @@ macro(set_feature_disabled FEATURE DISABLED)
set(${PREFIX}DISABLE_${FEATURE} ${DISABLED} CACHE INTERNAL "" FORCE) set(${PREFIX}DISABLE_${FEATURE} ${DISABLED} CACHE INTERNAL "" FORCE)
endmacro() endmacro()
# Features
function(feature_encoder_ffmpeg RESOLVE)
is_feature_enabled(ENCODER_FFMPEG T_CHECK)
if(RESOLVE AND T_CHECK)
if(NOT HAVE_FFMPEG)
message(WARNING "FFmpeg Encoder requires FFmpeg. Disabling...")
set_feature_disabled(ENCODER_FFMPEG ON)
else()
# AMF
is_feature_enabled(ENCODER_FFMPEG_AMF T_CHECK)
if(T_CHECK AND D_PLATFORM_MAC)
message(WARNING "FFmpeg Encoder 'AMF' requires Windows or Linux. Disabling...")
set_feature_disabled(ENCODER_FFMPEG_AMF ON)
endif()
# NVENC
is_feature_enabled(ENCODER_FFMPEG_NVENC T_CHECK)
if(T_CHECK AND D_PLATFORM_MAC)
message(WARNING "FFmpeg Encoder 'NVENC' requires Windows or Linux. Disabling...")
set_feature_disabled(ENCODER_FFMPEG_NVENC ON)
endif()
# ProRes
is_feature_enabled(ENCODER_FFMPEG_PRORES T_CHECK)
# DNxHR
is_feature_enabled(ENCODER_FFMPEG_DNXHR T_CHECK)
# CineForm
is_feature_enabled(ENCODER_FFMPEG_CFHD T_CHECK)
endif()
elseif(T_CHECK)
set(REQUIRE_FFMPEG ON PARENT_SCOPE)
endif()
endfunction()
function(feature_encoder_aom_av1 RESOLVE)
is_feature_enabled(ENCODER_AOM_AV1 T_CHECK)
if(RESOLVE AND T_CHECK)
if(NOT HAVE_AOM)
message(WARNING "AOM AV1 encoder missing AOM library. Disabling...")
set_feature_disabled(ENCODER_AOM_AV1 ON)
endif()
elseif(T_CHECK)
set(REQUIRE_AOM ON PARENT_SCOPE)
endif()
endfunction()
function(feature_filter_autoframing RESOLVE) function(feature_filter_autoframing RESOLVE)
is_feature_enabled(FILTER_AUTOFRAMING T_CHECK) is_feature_enabled(FILTER_AUTOFRAMING T_CHECK)
if(RESOLVE AND T_CHECK) if(RESOLVE AND T_CHECK)
@ -651,8 +595,6 @@ function(feature_updater RESOLVE)
endfunction() endfunction()
# Set Requirements # Set Requirements
feature_encoder_ffmpeg(OFF)
feature_encoder_aom_av1(OFF)
feature_filter_autoframing(OFF) feature_filter_autoframing(OFF)
feature_filter_blur(OFF) feature_filter_blur(OFF)
feature_filter_color_grade(OFF) feature_filter_color_grade(OFF)
@ -713,24 +655,6 @@ if(REQUIRE_CURL)
find_package("CURL") find_package("CURL")
endif() endif()
#- FFmpeg
set(HAVE_FFMPEG OFF)
if(REQUIRE_FFMPEG)
find_package("FFmpeg"
COMPONENTS "avutil" "avcodec" "swscale"
)
set(HAVE_FFMPEG ${FFmpeg_FOUND})
endif()
#- AOM
set(HAVE_AOM OFF)
if(REQUIRE_AOM)
if(NOT D_PLATFORM_MAC)
find_package("AOM")
set(HAVE_AOM ${AOM_FOUND})
endif()
endif()
#- JSON #- JSON
set(HAVE_JSON OFF) set(HAVE_JSON OFF)
if(REQUIRE_JSON) if(REQUIRE_JSON)
@ -808,8 +732,6 @@ if(REQUIRE_QT)
endif() endif()
# Verify Requirements # Verify Requirements
feature_encoder_ffmpeg(ON)
feature_encoder_aom_av1(ON)
feature_filter_autoframing(ON) feature_filter_autoframing(ON)
feature_filter_blur(ON) feature_filter_blur(ON)
feature_filter_color_grade(ON) feature_filter_color_grade(ON)
@ -882,15 +804,6 @@ if(CURL_FOUND)
list(APPEND PROJECT_LIBRARIES CURL::libcurl) list(APPEND PROJECT_LIBRARIES CURL::libcurl)
endif() endif()
if(HAVE_FFMPEG)
list(APPEND PROJECT_LIBRARIES
${FFMPEG_LIBRARIES}
)
list(APPEND PROJECT_INCLUDE_DIRS
${FFMPEG_INCLUDE_DIRS}
)
endif()
if(HAVE_JSON) if(HAVE_JSON)
list(APPEND PROJECT_INCLUDE_DIRS ${JSON_INCLUDE_DIR}) list(APPEND PROJECT_INCLUDE_DIRS ${JSON_INCLUDE_DIR})
endif() endif()
@ -1102,107 +1015,6 @@ list(APPEND PROJECT_INCLUDE_DIRS
"${PROJECT_SOURCE_DIR}/source" "${PROJECT_SOURCE_DIR}/source"
) )
# Encoder/FFmpeg
is_feature_enabled(ENCODER_FFMPEG T_CHECK)
if(T_CHECK)
list(APPEND PROJECT_PRIVATE_SOURCE
# FFmpeg
"source/ffmpeg/avframe-queue.cpp"
"source/ffmpeg/avframe-queue.hpp"
"source/ffmpeg/swscale.hpp"
"source/ffmpeg/swscale.cpp"
"source/ffmpeg/tools.hpp"
"source/ffmpeg/tools.cpp"
"source/ffmpeg/hwapi/base.hpp"
"source/ffmpeg/hwapi/base.cpp"
"source/ffmpeg/hwapi/d3d11.hpp"
"source/ffmpeg/hwapi/d3d11.cpp"
# Encoders
"source/encoders/encoder-ffmpeg.hpp"
"source/encoders/encoder-ffmpeg.cpp"
# Encoders/Codecs
"source/encoders/codecs/hevc.hpp"
"source/encoders/codecs/hevc.cpp"
"source/encoders/codecs/h264.hpp"
"source/encoders/codecs/h264.cpp"
"source/encoders/codecs/prores.hpp"
"source/encoders/codecs/prores.cpp"
"source/encoders/codecs/dnxhr.hpp"
"source/encoders/codecs/dnxhr.cpp"
# Encoders/Handlers
"source/encoders/ffmpeg/handler.hpp"
"source/encoders/ffmpeg/handler.cpp"
"source/encoders/ffmpeg/debug.hpp"
"source/encoders/ffmpeg/debug.cpp"
)
list(APPEND PROJECT_DEFINITIONS
ENABLE_ENCODER_FFMPEG
)
# AMF
is_feature_enabled(ENCODER_FFMPEG_AMF T_CHECK)
if(T_CHECK)
list(APPEND PROJECT_PRIVATE_SOURCE
"source/encoders/ffmpeg/amf.hpp"
"source/encoders/ffmpeg/amf.cpp"
)
list(APPEND PROJECT_DEFINITIONS
ENABLE_ENCODER_FFMPEG_AMF
)
endif()
# NVENC
is_feature_enabled(ENCODER_FFMPEG_NVENC T_CHECK)
if(T_CHECK)
list(APPEND PROJECT_PRIVATE_SOURCE
"source/encoders/ffmpeg/nvenc.hpp"
"source/encoders/ffmpeg/nvenc.cpp"
)
list(APPEND PROJECT_DEFINITIONS
ENABLE_ENCODER_FFMPEG_NVENC
)
endif()
# ProRES
is_feature_enabled(ENCODER_FFMPEG_PRORES T_CHECK)
if(T_CHECK)
list(APPEND PROJECT_PRIVATE_SOURCE
"source/encoders/ffmpeg/prores_aw.hpp"
"source/encoders/ffmpeg/prores_aw.cpp"
)
list(APPEND PROJECT_DEFINITIONS
ENABLE_ENCODER_FFMPEG_PRORES
)
endif()
# DNxHR
is_feature_enabled(ENCODER_FFMPEG_DNXHR T_CHECK)
if(T_CHECK)
list(APPEND PROJECT_PRIVATE_SOURCE
"source/encoders/ffmpeg/dnxhd.hpp"
"source/encoders/ffmpeg/dnxhd.cpp"
)
list(APPEND PROJECT_DEFINITIONS
ENABLE_ENCODER_FFMPEG_DNXHR
)
endif()
# CineForm HD
is_feature_enabled(ENCODER_FFMPEG_CFHD T_CHECK)
if(T_CHECK)
list(APPEND PROJECT_PRIVATE_SOURCE
"source/encoders/ffmpeg/cfhd.hpp"
"source/encoders/ffmpeg/cfhd.cpp"
)
list(APPEND PROJECT_DEFINITIONS
ENABLE_ENCODER_FFMPEG_CFHD
)
endif()
endif()
# Filter/Auto-Framing # Filter/Auto-Framing
is_feature_enabled(FILTER_AUTOFRAMING T_CHECK) is_feature_enabled(FILTER_AUTOFRAMING T_CHECK)
if(T_CHECK) if(T_CHECK)
@ -1905,6 +1717,7 @@ function(streamfx_add_component COMPONENT_NAME)
# Allow disabling this component. # Allow disabling this component.
set(${COMPONENT_OPTION} ON CACHE BOOL "Enable the ${COMPONENT_NAME} component?") set(${COMPONENT_OPTION} ON CACHE BOOL "Enable the ${COMPONENT_NAME} component?")
set(${COMPONENT_OPTION}_DISABLED OFF CACHE INTERNAL "Disable the ${_NAME} component?" FORCE)
# Add common include directories # Add common include directories
target_include_directories(${COMPONENT_TARGET} target_include_directories(${COMPONENT_TARGET}
@ -1995,6 +1808,22 @@ function(streamfx_add_component_dependency _NAME)
set_target_properties(${COMPONENT_TARGET} PROPERTIES COMPONENT_DEPENDS "${DEPENDS}") set_target_properties(${COMPONENT_TARGET} PROPERTIES COMPONENT_DEPENDS "${DEPENDS}")
endfunction() endfunction()
function(streamfx_disable_component _NAME _REASON)
# If the component doesn't exist, skip it.
if(NOT TARGET ${_NAME})
message(WARNING "Not disabling invalid component '${COMPONENT}'.")
return()
endif()
get_target_property(_NAME ${COMPONENT} COMPONENT_LABEL)
get_target_property(_OPTION ${COMPONENT} COMPONENT_OPTION)
CacheSet(${_OPTION}_DISABLED ON)
if(_REASON)
message(STATUS "[${_NAME}] Disabled due to: ${_REASON}")
endif()
endfunction()
################################################################################ ################################################################################
# Register Library # Register Library
################################################################################ ################################################################################

View file

@ -0,0 +1,26 @@
## AUTOGENERATED COPYRIGHT HEADER START
# Copyright (C) NaN-NaN undefined
# AUTOGENERATED COPYRIGHT HEADER END
cmake_minimum_required(VERSION 3.26)
project("FFmpeg")
list(APPEND CMAKE_MESSAGE_INDENT "[${PROJECT_NAME}] ")
streamfx_add_component(${PROJECT_NAME})
find_package("FFmpeg"
COMPONENTS "avutil" "avcodec" "swscale"
)
if(NOT FFmpeg_FOUND)
streamfx_disable_component(${COMPONENT_TARGET} "FFmpeg is not available.")
return()
else()
target_link_libraries(${COMPONENT_TARGET}
PUBLIC
${FFMPEG_LIBRARIES}
)
target_include_directories(${COMPONENT_TARGET}
PUBLIC
${FFMPEG_INCLUDE_DIRS}
)
endif()

View file

@ -19,6 +19,7 @@ namespace streamfx::encoder::ffmpeg {
struct handler { struct handler {
handler(std::string codec); handler(std::string codec);
virtual ~handler(){};
virtual bool has_keyframes(ffmpeg_factory* factory); virtual bool has_keyframes(ffmpeg_factory* factory);
virtual bool has_threading(ffmpeg_factory* factory); virtual bool has_threading(ffmpeg_factory* factory);

View file

@ -88,7 +88,7 @@ extern "C" {
#define ST_KEY_H265_PROFILE "H265.Profile" #define ST_KEY_H265_PROFILE "H265.Profile"
#define ST_KEY_H265_TIER "H265.Tier" #define ST_KEY_H265_TIER "H265.Tier"
#define ST_KEY_H264_LEVEL "H265.Level" #define ST_KEY_H265_LEVEL "H265.Level"
using namespace streamfx::encoder::ffmpeg; using namespace streamfx::encoder::ffmpeg;
using namespace streamfx::encoder::codec; using namespace streamfx::encoder::codec;
@ -1045,7 +1045,7 @@ void nvenc_hevc::defaults(ffmpeg_factory* factory, obs_data_t* settings)
obs_data_set_default_string(settings, ST_KEY_H265_PROFILE, ""); obs_data_set_default_string(settings, ST_KEY_H265_PROFILE, "");
obs_data_set_default_string(settings, ST_KEY_H265_TIER, ""); obs_data_set_default_string(settings, ST_KEY_H265_TIER, "");
obs_data_set_default_string(settings, ST_KEY_H264_LEVEL, "auto"); obs_data_set_default_string(settings, ST_KEY_H265_LEVEL, "auto");
} }
void nvenc_hevc::properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props) void nvenc_hevc::properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props)
@ -1061,6 +1061,17 @@ void nvenc_hevc::migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs
{ {
nvenc::migrate(factory, instance, settings, version); nvenc::migrate(factory, instance, settings, version);
// Migrate:
// - all versions below 0.12.
// - all versions that are larger than 0.12, but smaller than 0.12.0.315.
// - no other version.
if ((version < STREAMFX_MAKE_VERSION(0, 12, 0, 0))
|| ((version > STREAMFX_MAKE_VERSION(0, 12, 0, 0)) && (version < STREAMFX_MAKE_VERSION(0, 12, 0, 315)))) {
// Accidentally had this stored int he wrong place. Oops.
obs_data_set_string(settings, ST_KEY_H265_LEVEL, obs_data_get_string(settings, ST_KEY_H264_LEVEL));
obs_data_unset_user_value(settings, ST_KEY_H264_LEVEL);
}
if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) { if (version < STREAMFX_MAKE_VERSION(0, 11, 1, 0)) {
// Profile // Profile
if (auto v = obs_data_get_int(settings, ST_KEY_H265_PROFILE); v != -1) { if (auto v = obs_data_get_int(settings, ST_KEY_H265_PROFILE); v != -1) {
@ -1092,7 +1103,7 @@ void nvenc_hevc::migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs
} }
// Level // Level
obs_data_set_string(settings, ST_KEY_H264_LEVEL, "auto"); obs_data_set_string(settings, ST_KEY_H265_LEVEL, "auto");
} }
} }
@ -1110,7 +1121,7 @@ void nvenc_hevc::update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_
if (const char* v = obs_data_get_string(settings, ST_KEY_H265_TIER); v && (v[0] != '\0')) { if (const char* v = obs_data_get_string(settings, ST_KEY_H265_TIER); v && (v[0] != '\0')) {
av_opt_set(context->priv_data, "tier", v, AV_OPT_SEARCH_CHILDREN); av_opt_set(context->priv_data, "tier", v, AV_OPT_SEARCH_CHILDREN);
} }
if (const char* v = obs_data_get_string(settings, ST_KEY_H264_LEVEL); v && (v[0] != '\0')) { if (const char* v = obs_data_get_string(settings, ST_KEY_H265_LEVEL); v && (v[0] != '\0')) {
av_opt_set(context->priv_data, "level", v, AV_OPT_SEARCH_CHILDREN); av_opt_set(context->priv_data, "level", v, AV_OPT_SEARCH_CHILDREN);
} }
} }
@ -1172,7 +1183,7 @@ void nvenc_hevc::properties_encoder(ffmpeg_factory* factory, ffmpeg_instance* in
}); });
} }
{ {
auto p = obs_properties_add_list(grp, ST_KEY_H264_LEVEL, D_TRANSLATE(S_CODEC_HEVC_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); auto p = obs_properties_add_list(grp, ST_KEY_H265_LEVEL, D_TRANSLATE(S_CODEC_HEVC_LEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "level", [&p](const AVOption* opt) { streamfx::ffmpeg::tools::avoption_list_add_entries(context->priv_data, "level", [&p](const AVOption* opt) {
if (opt->default_val.i64 == 0) { if (opt->default_val.i64 == 0) {