From ffb7a6c5d77e37425d9e73f634bf4828ef94907b Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sat, 20 May 2023 19:27:51 +0200 Subject: [PATCH] code: Add GoPro CineForm to FFmpeg Encoders --- CMakeLists.txt | 16 ++++++ data/locale/en-US.ini | 16 ++++++ source/encoders/ffmpeg/cfhd.cpp | 89 +++++++++++++++++++++++++++++++++ source/encoders/ffmpeg/cfhd.hpp | 26 ++++++++++ 4 files changed, 147 insertions(+) create mode 100644 source/encoders/ffmpeg/cfhd.cpp create mode 100644 source/encoders/ffmpeg/cfhd.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 32e90737..186c32b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,6 +293,7 @@ set(${PREFIX}ENABLE_ENCODER_FFMPEG_AMF ${FEATURE_DEPRECATED} CACHE BOOL "Enable 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 set(${PREFIX}ENABLE_FILTER_AUTOFRAMING ${FEATURE_EXPERIMENTAL} CACHE BOOL "Enable Auto-Framing Filter") @@ -476,6 +477,9 @@ function(feature_encoder_ffmpeg RESOLVE) # 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) @@ -1202,6 +1206,18 @@ if(T_CHECK) 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 diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 5ac5ff33..6ef2d66d 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -235,6 +235,22 @@ Encoder.FFmpeg.NVENC.Other.NonReferencePFrames="Non-reference P-Frames" Encoder.FFmpeg.NVENC.Other.ReferenceFrames="Reference Frames" Encoder.FFmpeg.NVENC.Other.LowDelayKeyFrameScale="Low Delay Key-Frame Scale" +# Encoder/FFmpeg/CFHD +Encoder.FFmpeg.CineForm.Quality="Quality" +Encoder.FFmpeg.CineForm.Quality.low="Low" +Encoder.FFmpeg.CineForm.Quality.low+="Low+" +Encoder.FFmpeg.CineForm.Quality.medium="Medium" +Encoder.FFmpeg.CineForm.Quality.medium+="Medium+" +Encoder.FFmpeg.CineForm.Quality.high="High" +Encoder.FFmpeg.CineForm.Quality.high+="High+" +Encoder.FFmpeg.CineForm.Quality.film1="Film 1" +Encoder.FFmpeg.CineForm.Quality.film1+="Film 1+" +Encoder.FFmpeg.CineForm.Quality.film1.5="Film 1.5" +Encoder.FFmpeg.CineForm.Quality.film2="Film 2" +Encoder.FFmpeg.CineForm.Quality.film2+="Film 2+" +Encoder.FFmpeg.CineForm.Quality.film3="Film 3" +Encoder.FFmpeg.CineForm.Quality.film3+="Film 3+" + # Blur Blur.Type.Box="Box" Blur.Type.BoxLinear="Box Linear" diff --git a/source/encoders/ffmpeg/cfhd.cpp b/source/encoders/ffmpeg/cfhd.cpp new file mode 100644 index 00000000..05d7ecb0 --- /dev/null +++ b/source/encoders/ffmpeg/cfhd.cpp @@ -0,0 +1,89 @@ +// AUTOGENERATED COPYRIGHT HEADER START +// Copyright (C) 2023 Michael Fabian 'Xaymar' Dirks +// AUTOGENERATED COPYRIGHT HEADER END +// Copyright (C) 2020-2023 Michael Fabian 'Xaymar' Dirks +// Copyright (C) 2020 Daniel Molkentin + +#include "cfhd.hpp" +#include "common.hpp" +#include "encoders/encoder-ffmpeg.hpp" +#include "ffmpeg/tools.hpp" +#include "handler.hpp" +#include "plugin.hpp" + +#include "warning-disable.hpp" +#include +#include +#include +#include +extern "C" { +#include +} +#include "warning-enable.hpp" + +using namespace streamfx::encoder::ffmpeg; + +struct strings { + struct quality { + static constexpr const char* ffmpeg = "quality"; + static constexpr const char* obs = "Quality"; + static constexpr const char* i18n = "Encoder.FFmpeg.CineForm.Quality"; + }; +}; + +cfhd::cfhd() : handler("cfhd") {} + +bool cfhd::has_keyframes(ffmpeg_factory* factory) +{ + return false; +} + +void cfhd::properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props) +{ + // Try and acquire a valid context. + std::shared_ptr ctx; + if (instance) { + ctx = std::shared_ptr(instance->get_avcodeccontext(), [](AVCodecContext*) {}); + } else { // If we don't have a context, create a temporary one that is automatically freed. + ctx = std::shared_ptr(avcodec_alloc_context3(factory->get_avcodec()), [](AVCodecContext* v) { avcodec_free_context(&v); }); + if (!ctx->priv_data) { + return; + } + } + + { // Quality parameter + auto to_string = [](const char* v) { + char buffer[1024]; + snprintf(buffer, sizeof(buffer), "%s.%s", strings::quality::i18n, v); + return D_TRANSLATE(buffer); + }; + + auto p = obs_properties_add_list(props, strings::quality::obs, D_TRANSLATE(strings::quality::i18n), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); + streamfx::ffmpeg::tools::avoption_list_add_entries(ctx->priv_data, strings::quality::ffmpeg, [&p, &to_string](const AVOption* opt) { + // FFmpeg returns this list in the wrong order. We want to start at the lowest, and go to the highest. + // So simply always insert at the top, and this will reverse the list. + obs_property_list_insert_string(p, 0, to_string(opt->name), opt->name); + }); + } +} + +std::string cfhd::help(ffmpeg_factory* factory) +{ + return "https://github.com/Xaymar/obs-StreamFX/wiki/Encoder-FFmpeg-GoPro-CineForm"; +} + +void cfhd::defaults(ffmpeg_factory* factory, obs_data_t* settings) +{ + obs_data_set_string(settings, strings::quality::obs, "film3+"); +} + +void cfhd::migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version) {} + +void cfhd::update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) +{ + if (const char* v = obs_data_get_string(settings, strings::quality::obs); v && (v[0] != '\0')) { + av_opt_set(instance->get_avcodeccontext()->priv_data, strings::quality::ffmpeg, v, AV_OPT_SEARCH_CHILDREN); + } +} + +static cfhd handler = cfhd(); diff --git a/source/encoders/ffmpeg/cfhd.hpp b/source/encoders/ffmpeg/cfhd.hpp new file mode 100644 index 00000000..067b32da --- /dev/null +++ b/source/encoders/ffmpeg/cfhd.hpp @@ -0,0 +1,26 @@ +// AUTOGENERATED COPYRIGHT HEADER START +// Copyright (C) 2023 Michael Fabian 'Xaymar' Dirks +// AUTOGENERATED COPYRIGHT HEADER END + +#pragma once +#include "handler.hpp" + +namespace streamfx::encoder::ffmpeg { + class cfhd : public handler { + public: + cfhd(); + virtual ~cfhd(){}; + + bool has_keyframes(ffmpeg_factory* factory) override; + + std::string help(ffmpeg_factory* factory) override; + + void defaults(ffmpeg_factory* factory, obs_data_t* settings) override; + + void properties(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_properties_t* props) override; + + void migrate(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings, uint64_t version) override; + + void update(ffmpeg_factory* factory, ffmpeg_instance* instance, obs_data_t* settings) override; + }; +} // namespace streamfx::encoder::ffmpeg