mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-12-28 18:41:14 +00:00
encoders/ffmpeg: Implement AMF H.264 and H.265 handlers
Adds support for the AMD Advanced Media Framework H.264 and H.265 encoders via FFmpeg. The majority of settings are supported, and the UI/UX experience mimics that of the NVENC implementation. Various settings are left out due to their complexity and should be controlled via the custom parameters field.
This commit is contained in:
parent
569fa56b1d
commit
ff3f8cff03
9 changed files with 1232 additions and 0 deletions
|
@ -916,6 +916,12 @@ if(NOT ${PREFIX}DISABLE_ENCODER_FFMPEG)
|
|||
"source/encoders/handlers/nvenc_h264_handler.cpp"
|
||||
"source/encoders/handlers/nvenc_hevc_handler.hpp"
|
||||
"source/encoders/handlers/nvenc_hevc_handler.cpp"
|
||||
"source/encoders/handlers/amf_shared.hpp"
|
||||
"source/encoders/handlers/amf_shared.cpp"
|
||||
"source/encoders/handlers/amf_h264_handler.hpp"
|
||||
"source/encoders/handlers/amf_h264_handler.cpp"
|
||||
"source/encoders/handlers/amf_hevc_handler.hpp"
|
||||
"source/encoders/handlers/amf_hevc_handler.cpp"
|
||||
)
|
||||
list(APPEND PROJECT_DEFINITIONS
|
||||
ENABLE_ENCODER_FFMPEG
|
||||
|
|
|
@ -419,6 +419,53 @@ FFmpegEncoder.KeyFrames.IntervalType.Description="Keyframe interval type"
|
|||
FFmpegEncoder.KeyFrames.Interval.Description="Distance between key frames, in frames or seconds."
|
||||
FFmpegEncoder.KeyFrames.Interval="Interval"
|
||||
|
||||
# Encoder: AMF
|
||||
FFmpegEncoder.AMF.Preset="Preset"
|
||||
FFmpegEncoder.AMF.Preset.Description="The preset to use for encoding, which sets up internal values in the driver for encoding.\nThe names roughly match the expected encoding speed, but quality varies.\nIt is entirely possible to get a better quality with Balanced than with Quality at low bitrates."
|
||||
FFmpegEncoder.AMF.Preset.Speed="Speed"
|
||||
FFmpegEncoder.AMF.Preset.Balanced="Balanced"
|
||||
FFmpegEncoder.AMF.Preset.Quality="Quality"
|
||||
FFmpegEncoder.AMF.RateControl="Rate Control Options"
|
||||
FFmpegEncoder.AMF.RateControl.Mode="Mode"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.Description="Rate control mode selection"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.CQP="Constant Quantization Parameter"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.CQP.Description="A flat compression ratio with no regard for bit rates."
|
||||
FFmpegEncoder.AMF.RateControl.Mode.VBR_PEAK="Variable Bitrate (Peak Constrained)"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.VBR_PEAK.Description="TODO"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.VBR_LATENCY="Variable Bitrate (Latency Constrained)"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.VBR_LATENCY.Description="TODO"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.CBR="Constant Bitrate"
|
||||
FFmpegEncoder.AMF.RateControl.Mode.CBR.Description="Compresses footage so that it matches the target bitrate over the duration of\none second. This comes at a cost in quality during high motion scenes or\nscenes with flickering brightness like often seen in RPGs."
|
||||
FFmpegEncoder.AMF.RateControl.LookAhead="Look Ahead"
|
||||
FFmpegEncoder.AMF.RateControl.LookAhead.Description="Look ahead in the encoding, slightly increasing latency but improving bitrate distribution over time."
|
||||
FFmpegEncoder.AMF.RateControl.FrameSkipping="Frame Skipping"
|
||||
FFmpegEncoder.AMF.RateControl.FrameSkipping.Description="Allow skipping frames to meet the bitrate target/maximum."
|
||||
FFmpegEncoder.AMF.RateControl.Limits="Limits"
|
||||
FFmpegEncoder.AMF.RateControl.Limits.BufferSize="Buffer Size"
|
||||
FFmpegEncoder.AMF.RateControl.Limits.BufferSize.Description="Specifies the buffer size used for bitrate constrained modes.\nIdeally set to (KeyFrame Interval In Seconds * Bitrate Target), so at 2 seconds and 6000 kbit it should be 12000."
|
||||
FFmpegEncoder.AMF.RateControl.Limits.Bitrate.Target="Target Bitrate"
|
||||
FFmpegEncoder.AMF.RateControl.Limits.Bitrate.Maximum="Maximum Bitrate"
|
||||
FFmpegEncoder.AMF.RateControl.QP="Quantization Parameters"
|
||||
FFmpegEncoder.AMF.RateControl.QP.I="I-Frame QP"
|
||||
FFmpegEncoder.AMF.RateControl.QP.I.Description="Quantization parameter for I-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality."
|
||||
FFmpegEncoder.AMF.RateControl.QP.P="P-Frame QP"
|
||||
FFmpegEncoder.AMF.RateControl.QP.P.Description="Quantization parameter for P-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality."
|
||||
FFmpegEncoder.AMF.RateControl.QP.B="B-Frame QP"
|
||||
FFmpegEncoder.AMF.RateControl.QP.B.Description="Quantization parameter for B-Frames.\nSmaller values mean better quality in exchange for higher bitrate, while higher values mean less bitrate in exchange for less quality."
|
||||
FFmpegEncoder.AMF.Other="Other Options"
|
||||
FFmpegEncoder.AMF.Other.BFrames="Maximum B-Frames"
|
||||
FFmpegEncoder.AMF.Other.BFrames.Description="Maximum number of B-Frames to insert into the encoded bitstream.\nActual number of B-Frames may be lower depending on content and lookahead settings.\nB-Frames may not be supported on all AMD GPUs."
|
||||
FFmpegEncoder.AMF.Other.BFrameReferences="B-Frame References"
|
||||
FFmpegEncoder.AMF.Other.BFrameReferences.Description="Enable references to B-Frames, which can improve quality but reduces encoder performance drastically."
|
||||
FFmpegEncoder.AMF.Other.ReferenceFrames="Reference Frames"
|
||||
FFmpegEncoder.AMF.Other.ReferenceFrames.Description="Maximum number of reference frames to create in the encoded footage.\nActual number may be lower and is decided by the encoder."
|
||||
FFmpegEncoder.AMF.Other.EnforceHRD="Enforce HRD"
|
||||
FFmpegEncoder.AMF.Other.EnforceHRD.Description="TODO"
|
||||
FFmpegEncoder.AMF.Other.VBAQ="VBAQ"
|
||||
FFmpegEncoder.AMF.Other.VBAQ.Description="Enable 'Variance (Based) Adaptive Quantization', which improves the bitrate distribution over the frame by focusing areas which need the detail, like edges and foliage.\nThis option is only available on newer AMD GPUs."
|
||||
FFmpegEncoder.AMF.Other.AccessUnitDelimiter="Access Unit Delimiter"
|
||||
FFmpegEncoder.AMF.Other.AccessUnitDelimiter.Description="Enable insertion of an Access Unit Delimiter."
|
||||
|
||||
# Encoder: NVENC
|
||||
FFmpegEncoder.NVENC.Preset="Preset"
|
||||
FFmpegEncoder.NVENC.Preset.Description="Presets are NVIDIA's preconfigured default settings.\nThe values set via the preset are overridden by parameters below, unless they are set to 'Default' or '-1'."
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <sstream>
|
||||
#include "codecs/hevc.hpp"
|
||||
#include "ffmpeg/tools.hpp"
|
||||
#include "handlers/amf_h264_handler.hpp"
|
||||
#include "handlers/amf_hevc_handler.hpp"
|
||||
#include "handlers/debug_handler.hpp"
|
||||
#include "handlers/nvenc_h264_handler.hpp"
|
||||
#include "handlers/nvenc_hevc_handler.hpp"
|
||||
|
@ -1115,6 +1117,8 @@ ffmpeg_manager::ffmpeg_manager() : _factories(), _handlers(), _debug_handler()
|
|||
register_handler("prores_aw", ::std::make_shared<handler::prores_aw_handler>());
|
||||
register_handler("h264_nvenc", ::std::make_shared<handler::nvenc_h264_handler>());
|
||||
register_handler("hevc_nvenc", ::std::make_shared<handler::nvenc_hevc_handler>());
|
||||
register_handler("h264_amf", ::std::make_shared<handler::amf_h264_handler>());
|
||||
register_handler("hevc_amf", ::std::make_shared<handler::amf_hevc_handler>());
|
||||
}
|
||||
|
||||
ffmpeg_manager::~ffmpeg_manager()
|
||||
|
|
187
source/encoders/handlers/amf_h264_handler.cpp
Normal file
187
source/encoders/handlers/amf_h264_handler.cpp
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2020 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "amf_h264_handler.hpp"
|
||||
#include "../codecs/h264.hpp"
|
||||
#include "../encoder-ffmpeg.hpp"
|
||||
#include "amf_shared.hpp"
|
||||
#include "ffmpeg/tools.hpp"
|
||||
|
||||
extern "C" {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4242 4244 4365)
|
||||
#endif
|
||||
#include <libavutil/opt.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Settings
|
||||
#define KEY_PROFILE "H264.Profile"
|
||||
#define KEY_LEVEL "H264.Level"
|
||||
|
||||
using namespace streamfx::encoder::ffmpeg::handler;
|
||||
using namespace streamfx::encoder::codec::h264;
|
||||
|
||||
static std::map<profile, std::string> profiles{
|
||||
{profile::CONSTRAINED_BASELINE, "constrained_baseline"},
|
||||
{profile::MAIN, "main"},
|
||||
{profile::HIGH, "high"},
|
||||
};
|
||||
|
||||
static std::map<level, std::string> levels{
|
||||
{level::L1_0, "1.0"}, {level::L1_0b, "1.0b"}, {level::L1_1, "1.1"}, {level::L1_2, "1.2"}, {level::L1_3, "1.3"},
|
||||
{level::L2_0, "2.0"}, {level::L2_1, "2.1"}, {level::L2_2, "2.2"}, {level::L3_0, "3.0"}, {level::L3_1, "3.1"},
|
||||
{level::L3_2, "3.2"}, {level::L4_0, "4.0"}, {level::L4_1, "4.1"}, {level::L4_2, "4.2"}, {level::L5_0, "5.0"},
|
||||
{level::L5_1, "5.1"}, {level::L5_2, "5.2"}, {level::L6_0, "6.0"}, {level::L6_1, "6.1"}, {level::L6_2, "6.2"},
|
||||
};
|
||||
|
||||
void amf_h264_handler::adjust_info(ffmpeg_factory* factory, const AVCodec* codec, std::string& id, std::string& name,
|
||||
std::string& codec_id)
|
||||
{
|
||||
name = "AMD AMF H.264/AVC (via FFmpeg)";
|
||||
if (!amf::is_available())
|
||||
factory->get_info()->caps |= OBS_ENCODER_CAP_DEPRECATED;
|
||||
}
|
||||
|
||||
void amf_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode)
|
||||
{
|
||||
amf::get_defaults(settings, codec, context);
|
||||
|
||||
obs_data_set_default_int(settings, KEY_PROFILE, static_cast<int64_t>(profile::HIGH));
|
||||
obs_data_set_default_int(settings, KEY_LEVEL, static_cast<int64_t>(level::UNKNOWN));
|
||||
}
|
||||
|
||||
bool amf_h264_handler::has_keyframe_support(ffmpeg_factory* instance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool amf_h264_handler::is_hardware_encoder(ffmpeg_factory* instance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool amf_h264_handler::has_threading_support(ffmpeg_factory* instance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool amf_h264_handler::has_pixel_format_support(ffmpeg_factory* instance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void amf_h264_handler::get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context,
|
||||
bool hw_encode)
|
||||
{
|
||||
if (!context) {
|
||||
this->get_encoder_properties(props, codec);
|
||||
} else {
|
||||
this->get_runtime_properties(props, codec, context);
|
||||
}
|
||||
}
|
||||
|
||||
void amf_h264_handler::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
amf::update(settings, codec, context);
|
||||
|
||||
{
|
||||
auto found = profiles.find(static_cast<profile>(obs_data_get_int(settings, KEY_PROFILE)));
|
||||
if (found != profiles.end()) {
|
||||
av_opt_set(context->priv_data, "profile", found->second.c_str(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto found = levels.find(static_cast<level>(obs_data_get_int(settings, KEY_LEVEL)));
|
||||
if (found != levels.end()) {
|
||||
av_opt_set(context->priv_data, "level", found->second.c_str(), 0);
|
||||
} else {
|
||||
av_opt_set(context->priv_data, "level", "auto", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void amf_h264_handler::override_update(ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
amf::override_update(instance, settings);
|
||||
}
|
||||
|
||||
void amf_h264_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
amf::log_options(settings, codec, context);
|
||||
|
||||
DLOG_INFO("[%s] H.264/AVC:", codec->name);
|
||||
::ffmpeg::tools::print_av_option_string2(context, context->priv_data, "profile", " Profile",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::ffmpeg::tools::print_av_option_string2(context, context->priv_data, "level", " Level",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
}
|
||||
|
||||
void amf_h264_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec)
|
||||
{
|
||||
amf::get_properties_pre(props, codec);
|
||||
|
||||
{
|
||||
obs_properties_t* grp = obs_properties_create();
|
||||
obs_properties_add_group(props, P_H264, D_TRANSLATE(P_H264), OBS_GROUP_NORMAL, grp);
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, KEY_PROFILE, D_TRANSLATE(P_H264_PROFILE), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(P_H264_PROFILE)));
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), static_cast<int64_t>(profile::UNKNOWN));
|
||||
for (auto const kv : profiles) {
|
||||
std::string trans = std::string(P_H264_PROFILE) + "." + kv.second;
|
||||
obs_property_list_add_int(p, D_TRANSLATE(trans.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, KEY_LEVEL, D_TRANSLATE(P_H264_LEVEL), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(P_H264_LEVEL)));
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_AUTOMATIC), static_cast<int64_t>(level::UNKNOWN));
|
||||
for (auto const kv : levels) {
|
||||
obs_property_list_add_int(p, kv.second.c_str(), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amf::get_properties_post(props, codec);
|
||||
}
|
||||
|
||||
void amf_h264_handler::get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
amf::get_runtime_properties(props, codec, context);
|
||||
}
|
||||
|
||||
void amf_h264_handler::migrate(obs_data_t* settings, std::uint64_t version, const AVCodec* codec,
|
||||
AVCodecContext* context)
|
||||
{
|
||||
amf::migrate(settings, version, codec, context);
|
||||
}
|
||||
|
||||
void amf_h264_handler::override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec,
|
||||
AVCodecContext* context)
|
||||
{
|
||||
target_format = AV_PIX_FMT_NV12;
|
||||
}
|
74
source/encoders/handlers/amf_h264_handler.hpp
Normal file
74
source/encoders/handlers/amf_h264_handler.hpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2020 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "common.hpp"
|
||||
#include "handler.hpp"
|
||||
|
||||
extern "C" {
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include <libavcodec/avcodec.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
namespace streamfx::encoder::ffmpeg::handler {
|
||||
class amf_h264_handler : public handler {
|
||||
public:
|
||||
virtual ~amf_h264_handler(){};
|
||||
|
||||
public /*factory*/:
|
||||
void adjust_info(ffmpeg_factory* factory, const AVCodec* codec, std::string& id, std::string& name,
|
||||
std::string& codec_id) override;
|
||||
|
||||
void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode) override;
|
||||
|
||||
public /*support tests*/:
|
||||
bool has_keyframe_support(ffmpeg_factory* instance) override;
|
||||
|
||||
bool is_hardware_encoder(ffmpeg_factory* instance) override;
|
||||
|
||||
bool has_threading_support(ffmpeg_factory* instance) override;
|
||||
|
||||
bool has_pixel_format_support(ffmpeg_factory* instance) override;
|
||||
|
||||
public /*settings*/:
|
||||
void get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context,
|
||||
bool hw_encode) override;
|
||||
|
||||
void migrate(obs_data_t* settings, std::uint64_t version, const AVCodec* codec,
|
||||
AVCodecContext* context) override;
|
||||
|
||||
void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) override;
|
||||
|
||||
void override_update(ffmpeg_instance* instance, obs_data_t* settings) override;
|
||||
|
||||
void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) override;
|
||||
|
||||
public /*instance*/:
|
||||
|
||||
void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec,
|
||||
AVCodecContext* context) override;
|
||||
|
||||
private:
|
||||
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);
|
||||
};
|
||||
} // namespace streamfx::encoder::ffmpeg::handler
|
200
source/encoders/handlers/amf_hevc_handler.cpp
Normal file
200
source/encoders/handlers/amf_hevc_handler.cpp
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2017-2018 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "amf_hevc_handler.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "../codecs/hevc.hpp"
|
||||
#include "../encoder-ffmpeg.hpp"
|
||||
#include "amf_shared.hpp"
|
||||
#include "ffmpeg/tools.hpp"
|
||||
#include "plugin.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <obs-module.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4242 4244 4365)
|
||||
#include <libavutil/opt.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
// Settings
|
||||
#define KEY_PROFILE "H265.Profile"
|
||||
#define KEY_TIER "H265.Tier"
|
||||
#define KEY_LEVEL "H265.Level"
|
||||
|
||||
using namespace streamfx::encoder::ffmpeg::handler;
|
||||
using namespace streamfx::encoder::codec::hevc;
|
||||
|
||||
static std::map<profile, std::string> profiles{
|
||||
{profile::MAIN, "main"},
|
||||
};
|
||||
|
||||
static std::map<tier, std::string> tiers{
|
||||
{tier::MAIN, "main"},
|
||||
{tier::HIGH, "high"},
|
||||
};
|
||||
|
||||
static std::map<level, std::string> levels{
|
||||
{level::L1_0, "1.0"}, {level::L2_0, "2.0"}, {level::L2_1, "2.1"}, {level::L3_0, "3.0"}, {level::L3_1, "3.1"},
|
||||
{level::L4_0, "4.0"}, {level::L4_1, "4.1"}, {level::L5_0, "5.0"}, {level::L5_1, "5.1"}, {level::L5_2, "5.2"},
|
||||
{level::L6_0, "6.0"}, {level::L6_1, "6.1"}, {level::L6_2, "6.2"},
|
||||
};
|
||||
|
||||
void amf_hevc_handler::adjust_info(ffmpeg_factory* factory, const AVCodec* codec, std::string& id, std::string& name,
|
||||
std::string& codec_id)
|
||||
{
|
||||
name = "AMD AMF H.265/HEVC (via FFmpeg)";
|
||||
if (!amf::is_available())
|
||||
factory->get_info()->caps |= OBS_ENCODER_CAP_DEPRECATED;
|
||||
}
|
||||
|
||||
void amf_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool)
|
||||
{
|
||||
amf::get_defaults(settings, codec, context);
|
||||
|
||||
obs_data_set_default_int(settings, KEY_PROFILE, static_cast<int64_t>(profile::MAIN));
|
||||
obs_data_set_default_int(settings, KEY_TIER, static_cast<int64_t>(profile::MAIN));
|
||||
obs_data_set_default_int(settings, KEY_LEVEL, static_cast<int64_t>(level::UNKNOWN));
|
||||
}
|
||||
|
||||
bool amf_hevc_handler::has_keyframe_support(ffmpeg_factory*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool amf_hevc_handler::is_hardware_encoder(ffmpeg_factory* instance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool amf_hevc_handler::has_threading_support(ffmpeg_factory* instance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool amf_hevc_handler::has_pixel_format_support(ffmpeg_factory* instance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void amf_hevc_handler::get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context, bool)
|
||||
{
|
||||
if (!context) {
|
||||
this->get_encoder_properties(props, codec);
|
||||
} else {
|
||||
this->get_runtime_properties(props, codec, context);
|
||||
}
|
||||
}
|
||||
|
||||
void amf_hevc_handler::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
amf::update(settings, codec, context);
|
||||
|
||||
{ // HEVC Options
|
||||
auto found = profiles.find(static_cast<profile>(obs_data_get_int(settings, KEY_PROFILE)));
|
||||
if (found != profiles.end()) {
|
||||
av_opt_set(context->priv_data, "profile", found->second.c_str(), 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto found = tiers.find(static_cast<tier>(obs_data_get_int(settings, KEY_TIER)));
|
||||
if (found != tiers.end()) {
|
||||
av_opt_set(context->priv_data, "tier", found->second.c_str(), 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto found = levels.find(static_cast<level>(obs_data_get_int(settings, KEY_LEVEL)));
|
||||
if (found != levels.end()) {
|
||||
av_opt_set(context->priv_data, "level", found->second.c_str(), 0);
|
||||
} else {
|
||||
av_opt_set(context->priv_data, "level", "auto", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void amf_hevc_handler::override_update(ffmpeg_instance* instance, obs_data_t* settings)
|
||||
{
|
||||
amf::override_update(instance, settings);
|
||||
}
|
||||
|
||||
void amf_hevc_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
amf::log_options(settings, codec, context);
|
||||
|
||||
DLOG_INFO("[%s] H.265/HEVC:", codec->name);
|
||||
::ffmpeg::tools::print_av_option_string2(context, "profile", " Profile",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::ffmpeg::tools::print_av_option_string2(context, "level", " Level",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
::ffmpeg::tools::print_av_option_string2(context, "tier", " Tier",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
}
|
||||
|
||||
void amf_hevc_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec)
|
||||
{
|
||||
amf::get_properties_pre(props, codec);
|
||||
|
||||
{
|
||||
obs_properties_t* grp = obs_properties_create();
|
||||
obs_properties_add_group(props, P_HEVC, D_TRANSLATE(P_HEVC), OBS_GROUP_NORMAL, grp);
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, KEY_PROFILE, D_TRANSLATE(P_HEVC_PROFILE), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(P_HEVC_PROFILE)));
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), static_cast<int64_t>(profile::UNKNOWN));
|
||||
for (auto const kv : profiles) {
|
||||
std::string trans = std::string(P_HEVC_PROFILE) + "." + kv.second;
|
||||
obs_property_list_add_int(p, D_TRANSLATE(trans.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, KEY_TIER, D_TRANSLATE(P_HEVC_TIER), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(P_HEVC_TIER)));
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DEFAULT), static_cast<int64_t>(tier::UNKNOWN));
|
||||
for (auto const kv : tiers) {
|
||||
std::string trans = std::string(P_HEVC_TIER) + "." + kv.second;
|
||||
obs_property_list_add_int(p, D_TRANSLATE(trans.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, KEY_LEVEL, D_TRANSLATE(P_HEVC_LEVEL), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(P_HEVC_LEVEL)));
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_AUTOMATIC), static_cast<int64_t>(level::UNKNOWN));
|
||||
for (auto const kv : levels) {
|
||||
obs_property_list_add_int(p, kv.second.c_str(), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amf::get_properties_post(props, codec);
|
||||
}
|
||||
|
||||
void amf_hevc_handler::get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
amf::get_runtime_properties(props, codec, context);
|
||||
}
|
||||
|
||||
void streamfx::encoder::ffmpeg::handler::amf_hevc_handler::migrate(obs_data_t* settings, std::uint64_t version,
|
||||
const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
amf::migrate(settings, version, codec, context);
|
||||
}
|
68
source/encoders/handlers/amf_hevc_handler.hpp
Normal file
68
source/encoders/handlers/amf_hevc_handler.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2017-2018 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "handler.hpp"
|
||||
|
||||
extern "C" {
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include <libavcodec/avcodec.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
namespace streamfx::encoder::ffmpeg::handler {
|
||||
class amf_hevc_handler : public handler {
|
||||
public:
|
||||
virtual ~amf_hevc_handler(){};
|
||||
|
||||
public /*factory*/:
|
||||
virtual void adjust_info(ffmpeg_factory* factory, const AVCodec* codec, std::string& id, std::string& name,
|
||||
std::string& codec_id);
|
||||
|
||||
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode);
|
||||
|
||||
public /*support tests*/:
|
||||
virtual bool has_keyframe_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool is_hardware_encoder(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool has_threading_support(ffmpeg_factory* instance);
|
||||
|
||||
virtual bool has_pixel_format_support(ffmpeg_factory* instance);
|
||||
|
||||
public /*settings*/:
|
||||
virtual void get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context,
|
||||
bool hw_encode);
|
||||
|
||||
virtual void migrate(obs_data_t* settings, std::uint64_t version, const AVCodec* codec,
|
||||
AVCodecContext* context);
|
||||
|
||||
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
virtual void override_update(ffmpeg_instance* instance, obs_data_t* settings);
|
||||
|
||||
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
private:
|
||||
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);
|
||||
};
|
||||
} // namespace streamfx::encoder::ffmpeg::handler
|
517
source/encoders/handlers/amf_shared.cpp
Normal file
517
source/encoders/handlers/amf_shared.cpp
Normal file
|
@ -0,0 +1,517 @@
|
|||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (c) 2020 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "amf_shared.hpp"
|
||||
#include "ffmpeg/tools.hpp"
|
||||
|
||||
extern "C" {
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include <libavutil/opt.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
// Translation
|
||||
#define ST_I18N "FFmpegEncoder.AMF"
|
||||
#define ST_I18N_PRESET ST_I18N ".Preset"
|
||||
#define ST_I18N_PRESET_(x) ST_I18N_PRESET "." x
|
||||
#define ST_I18N_RATECONTROL "FFmpegEncoder.AMF.RateControl"
|
||||
#define ST_I18N_RATECONTROL_MODE ST_I18N_RATECONTROL ".Mode"
|
||||
#define ST_I18N_RATECONTROL_MODE_(x) ST_I18N_RATECONTROL_MODE "." x
|
||||
#define ST_I18N_RATECONTROL_LOOKAHEAD ST_I18N_RATECONTROL ".LookAhead"
|
||||
#define ST_I18N_RATECONTROL_FRAMESKIPPING ST_I18N_RATECONTROL ".FrameSkipping"
|
||||
#define ST_I18N_RATECONTROL_LIMITS ST_I18N_RATECONTROL ".Limits"
|
||||
#define ST_I18N_RATECONTROL_LIMITS_BUFFERSIZE ST_I18N_RATECONTROL_LIMITS ".BufferSize"
|
||||
#define ST_I18N_RATECONTROL_LIMITS_BITRATE ST_I18N_RATECONTROL_LIMITS ".Bitrate"
|
||||
#define ST_I18N_RATECONTROL_LIMITS_BITRATE_TARGET ST_I18N_RATECONTROL_LIMITS_BITRATE ".Target"
|
||||
#define ST_I18N_RATECONTROL_LIMITS_BITRATE_MAXIMUM ST_I18N_RATECONTROL_LIMITS_BITRATE ".Maximum"
|
||||
#define ST_I18N_RATECONTROL_QP ST_I18N_RATECONTROL ".QP"
|
||||
#define ST_I18N_RATECONTROL_QP_I ST_I18N_RATECONTROL_QP ".I"
|
||||
#define ST_I18N_RATECONTROL_QP_P ST_I18N_RATECONTROL_QP ".P"
|
||||
#define ST_I18N_RATECONTROL_QP_B ST_I18N_RATECONTROL_QP ".B"
|
||||
#define ST_I18N_OTHER ST_I18N ".Other"
|
||||
#define ST_I18N_OTHER_BFRAMES ST_I18N_OTHER ".BFrames"
|
||||
#define ST_I18N_OTHER_BFRAMEREFERENCES ST_I18N_OTHER ".BFrameReferences"
|
||||
#define ST_I18N_OTHER_REFERENCEFRAMES ST_I18N_OTHER ".ReferenceFrames"
|
||||
#define ST_I18N_OTHER_ENFORCEHRD ST_I18N_OTHER ".EnforceHRD"
|
||||
#define ST_I18N_OTHER_VBAQ ST_I18N_OTHER ".VBAQ"
|
||||
#define ST_I18N_OTHER_ACCESSUNITDELIMITER ST_I18N_OTHER ".AccessUnitDelimiter"
|
||||
|
||||
// Settings
|
||||
#define ST_KEY_PRESET "Preset"
|
||||
#define ST_KEY_RATECONTROL_MODE "RateControl.Mode"
|
||||
#define ST_KEY_RATECONTROL_LOOKAHEAD "RateControl.LookAhead"
|
||||
#define ST_KEY_RATECONTROL_FRAMESKIPPING "RateControl.FrameSkipping"
|
||||
#define ST_KEY_RATECONTROL_LIMITS_BUFFERSIZE "RateControl.Limits.BufferSize"
|
||||
#define ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET "RateControl.Limits.Bitrate.Target"
|
||||
#define ST_KEY_RATECONTROL_LIMITS_BITRATE_MAXIMUM "RateControl.Limits.Bitrate.Maximum"
|
||||
#define ST_KEY_RATECONTROL_QP_I "RateControl.QP.I"
|
||||
#define ST_KEY_RATECONTROL_QP_P "RateControl.QP.P"
|
||||
#define ST_KEY_RATECONTROL_QP_B "RateControl.QP.B"
|
||||
#define ST_KEY_OTHER_BFRAMES "Other.BFrames"
|
||||
#define ST_KEY_OTHER_BFRAMEREFERENCES "Other.BFrameReferences"
|
||||
#define ST_KEY_OTHER_REFERENCEFRAMES "Other.ReferenceFrames"
|
||||
#define ST_KEY_OTHER_ENFORCEHRD "Other.EnforceHRD"
|
||||
#define ST_KEY_OTHER_VBAQ "Other.VBAQ"
|
||||
#define ST_KEY_OTHER_ACCESSUNITDELIMITER "Other.AccessUnitDelimiter"
|
||||
|
||||
using namespace streamfx::encoder::ffmpeg::handler;
|
||||
|
||||
std::map<amf::preset, std::string> amf::presets{
|
||||
{amf::preset::SPEED, ST_I18N_PRESET_("Speed")},
|
||||
{amf::preset::BALANCED, ST_I18N_PRESET_("Balanced")},
|
||||
{amf::preset::QUALITY, ST_I18N_PRESET_("Quality")},
|
||||
};
|
||||
|
||||
std::map<amf::preset, std::string> amf::preset_to_opt{
|
||||
{amf::preset::SPEED, "speed"},
|
||||
{amf::preset::BALANCED, "balanced"},
|
||||
{amf::preset::QUALITY, "quality"},
|
||||
};
|
||||
|
||||
std::map<amf::ratecontrolmode, std::string> amf::ratecontrolmodes{
|
||||
{amf::ratecontrolmode::CQP, ST_I18N_RATECONTROL_MODE_("CQP")},
|
||||
{amf::ratecontrolmode::CBR, ST_I18N_RATECONTROL_MODE_("CBR")},
|
||||
{amf::ratecontrolmode::VBR_PEAK, ST_I18N_RATECONTROL_MODE_("VBR_PEAK")},
|
||||
{amf::ratecontrolmode::VBR_LATENCY, ST_I18N_RATECONTROL_MODE_("VBR_LATENCY")},
|
||||
};
|
||||
|
||||
std::map<amf::ratecontrolmode, std::string> amf::ratecontrolmode_to_opt{
|
||||
{amf::ratecontrolmode::CQP, "cqp"},
|
||||
{amf::ratecontrolmode::CBR, "cbr"},
|
||||
{amf::ratecontrolmode::VBR_PEAK, "vbr_peak"},
|
||||
{amf::ratecontrolmode::VBR_LATENCY, "vbr_latency"},
|
||||
};
|
||||
|
||||
bool streamfx::encoder::ffmpeg::handler::amf::is_available()
|
||||
{
|
||||
#if defined(D_PLATFORM_WINDOWS)
|
||||
#if defined(D_PLATFORM_64BIT)
|
||||
std::filesystem::path lib_name = std::filesystem::u8path("amfrt64.dll");
|
||||
#else
|
||||
std::filesystem::path lib_name = std::filesystem::u8path("amfrt32.dll");
|
||||
#endif
|
||||
#elif defined(D_PLATFORM_LINUX)
|
||||
#if defined(D_PLATFORM_64BIT)
|
||||
std::filesystem::path lib_name = std::filesystem::u8path("libamfrt64.so.1");
|
||||
#else
|
||||
std::filesystem::path lib_name = std::filesystem::u8path("libamfrt32.so.1");
|
||||
#endif
|
||||
#endif
|
||||
try {
|
||||
util::library::load(lib_name);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void amf::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
obs_data_set_default_int(settings, ST_KEY_PRESET, static_cast<int64_t>(amf::preset::BALANCED));
|
||||
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_MODE, static_cast<int64_t>(ratecontrolmode::CBR));
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LOOKAHEAD, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_FRAMESKIPPING, -1);
|
||||
//ob
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET, 6000);
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_MAXIMUM, 0);
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_LIMITS_BUFFERSIZE, 12000);
|
||||
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_QP_I, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_QP_P, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_RATECONTROL_QP_B, -1);
|
||||
|
||||
obs_data_set_default_int(settings, ST_KEY_OTHER_BFRAMES, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_OTHER_BFRAMEREFERENCES, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_OTHER_REFERENCEFRAMES, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_OTHER_ENFORCEHRD, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_OTHER_VBAQ, -1);
|
||||
obs_data_set_default_int(settings, ST_KEY_OTHER_ACCESSUNITDELIMITER, -1);
|
||||
|
||||
// Replay Buffer
|
||||
obs_data_set_default_int(settings, "bitrate", 0);
|
||||
}
|
||||
|
||||
static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_data_t* settings) noexcept
|
||||
{
|
||||
bool have_bitrate = false;
|
||||
bool have_bitrate_range = false;
|
||||
bool have_qp = false;
|
||||
|
||||
amf::ratecontrolmode rc = static_cast<amf::ratecontrolmode>(obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE));
|
||||
switch (rc) {
|
||||
case amf::ratecontrolmode::CQP:
|
||||
have_qp = true;
|
||||
break;
|
||||
case amf::ratecontrolmode::INVALID:
|
||||
case amf::ratecontrolmode::CBR:
|
||||
have_bitrate = true;
|
||||
break;
|
||||
case amf::ratecontrolmode::VBR_PEAK:
|
||||
case amf::ratecontrolmode::VBR_LATENCY:
|
||||
have_bitrate = true;
|
||||
have_bitrate_range = true;
|
||||
break;
|
||||
}
|
||||
|
||||
obs_property_set_visible(obs_properties_get(props, ST_I18N_RATECONTROL_LIMITS), have_bitrate);
|
||||
obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LIMITS_BUFFERSIZE), have_bitrate);
|
||||
obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET), have_bitrate);
|
||||
obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_LIMITS_BITRATE_MAXIMUM), have_bitrate_range);
|
||||
|
||||
obs_property_set_visible(obs_properties_get(props, ST_I18N_RATECONTROL_QP), have_qp);
|
||||
obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_QP_I), have_qp);
|
||||
obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_QP_P), have_qp);
|
||||
obs_property_set_visible(obs_properties_get(props, ST_KEY_RATECONTROL_QP_B), have_qp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void amf::get_properties_pre(obs_properties_t* props, const AVCodec* codec)
|
||||
{
|
||||
auto p = obs_properties_add_list(props, ST_KEY_PRESET, D_TRANSLATE(ST_I18N_PRESET), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_PRESET)));
|
||||
for (auto kv : presets) {
|
||||
obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
|
||||
void amf::get_properties_post(obs_properties_t* props, const AVCodec* codec)
|
||||
{
|
||||
{ // Rate Control
|
||||
obs_properties_t* grp = obs_properties_create();
|
||||
obs_properties_add_group(props, ST_I18N_RATECONTROL, D_TRANSLATE(ST_I18N_RATECONTROL), OBS_GROUP_NORMAL, grp);
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, ST_KEY_RATECONTROL_MODE, D_TRANSLATE(ST_I18N_RATECONTROL_MODE),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_RATECONTROL_MODE)));
|
||||
obs_property_set_modified_callback(p, modified_ratecontrol);
|
||||
for (auto kv : ratecontrolmodes) {
|
||||
obs_property_list_add_int(p, D_TRANSLATE(kv.second.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto p = util::obs_properties_add_tristate(grp, ST_KEY_RATECONTROL_LOOKAHEAD,
|
||||
D_TRANSLATE(ST_I18N_RATECONTROL_LOOKAHEAD));
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_RATECONTROL_LOOKAHEAD)));
|
||||
}
|
||||
|
||||
{
|
||||
auto p = util::obs_properties_add_tristate(grp, ST_KEY_RATECONTROL_FRAMESKIPPING,
|
||||
D_TRANSLATE(ST_I18N_RATECONTROL_FRAMESKIPPING));
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_RATECONTROL_FRAMESKIPPING)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = obs_properties_create();
|
||||
obs_properties_add_group(props, ST_I18N_RATECONTROL_LIMITS, D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS),
|
||||
OBS_GROUP_NORMAL, grp);
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int(grp, ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET,
|
||||
D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_BITRATE_TARGET), -1,
|
||||
std::numeric_limits<std::int32_t>::max(), 1);
|
||||
obs_property_int_set_suffix(p, " kbit/s");
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int(grp, ST_KEY_RATECONTROL_LIMITS_BITRATE_MAXIMUM,
|
||||
D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_BITRATE_MAXIMUM), -1,
|
||||
std::numeric_limits<std::int32_t>::max(), 1);
|
||||
obs_property_int_set_suffix(p, " kbit/s");
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int(grp, ST_KEY_RATECONTROL_LIMITS_BUFFERSIZE,
|
||||
D_TRANSLATE(ST_I18N_RATECONTROL_LIMITS_BUFFERSIZE), 0,
|
||||
std::numeric_limits<std::int32_t>::max(), 1);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_RATECONTROL_LIMITS_BUFFERSIZE)));
|
||||
obs_property_int_set_suffix(p, " kbit");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = obs_properties_create();
|
||||
obs_properties_add_group(props, ST_I18N_RATECONTROL_QP, D_TRANSLATE(ST_I18N_RATECONTROL_QP), OBS_GROUP_NORMAL,
|
||||
grp);
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, ST_KEY_RATECONTROL_QP_I, D_TRANSLATE(ST_I18N_RATECONTROL_QP_I),
|
||||
-1, 51, 1);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_RATECONTROL_QP_I)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, ST_KEY_RATECONTROL_QP_P, D_TRANSLATE(ST_I18N_RATECONTROL_QP_P),
|
||||
-1, 51, 1);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_RATECONTROL_QP_P)));
|
||||
}
|
||||
|
||||
if (std::string_view("amf_h264") == codec->name) {
|
||||
auto p = obs_properties_add_int_slider(grp, ST_KEY_RATECONTROL_QP_B, D_TRANSLATE(ST_I18N_RATECONTROL_QP_B),
|
||||
-1, 51, 1);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_RATECONTROL_QP_B)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = obs_properties_create();
|
||||
obs_properties_add_group(props, ST_I18N_OTHER, D_TRANSLATE(ST_I18N_OTHER), OBS_GROUP_NORMAL, grp);
|
||||
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_int_slider(grp, ST_KEY_OTHER_BFRAMES, D_TRANSLATE(ST_I18N_OTHER_BFRAMES), -1, 4, 1);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_OTHER_BFRAMES)));
|
||||
obs_property_int_set_suffix(p, " frames");
|
||||
}
|
||||
|
||||
{
|
||||
auto p = util::obs_properties_add_tristate(grp, ST_KEY_OTHER_BFRAMEREFERENCES,
|
||||
D_TRANSLATE(ST_I18N_OTHER_BFRAMEREFERENCES));
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_OTHER_BFRAMEREFERENCES)));
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, ST_KEY_OTHER_REFERENCEFRAMES,
|
||||
D_TRANSLATE(ST_I18N_OTHER_REFERENCEFRAMES), -1, 16, 1);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_OTHER_REFERENCEFRAMES)));
|
||||
obs_property_int_set_suffix(p, " frames");
|
||||
}
|
||||
|
||||
{
|
||||
auto p =
|
||||
util::obs_properties_add_tristate(grp, ST_KEY_OTHER_ENFORCEHRD, D_TRANSLATE(ST_I18N_OTHER_ENFORCEHRD));
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_OTHER_ENFORCEHRD)));
|
||||
}
|
||||
|
||||
{
|
||||
auto p = util::obs_properties_add_tristate(grp, ST_KEY_OTHER_VBAQ, D_TRANSLATE(ST_I18N_OTHER_VBAQ));
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_OTHER_VBAQ)));
|
||||
}
|
||||
|
||||
{
|
||||
auto p = util::obs_properties_add_tristate(grp, ST_KEY_OTHER_ACCESSUNITDELIMITER,
|
||||
D_TRANSLATE(ST_I18N_OTHER_ACCESSUNITDELIMITER));
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_I18N_OTHER_ACCESSUNITDELIMITER)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void amf::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
// Alway enable loop filter.
|
||||
context->flags |= AV_CODEC_FLAG_LOOP_FILTER;
|
||||
|
||||
// Always transcoding. Other usage options cause problems.
|
||||
av_opt_set(context->priv_data, "usage", "transcoding", AV_OPT_SEARCH_CHILDREN);
|
||||
|
||||
{ // Presets
|
||||
preset c_preset = static_cast<preset>(obs_data_get_int(settings, ST_KEY_PRESET));
|
||||
auto found = preset_to_opt.find(c_preset);
|
||||
if (found != preset_to_opt.end()) {
|
||||
av_opt_set(context->priv_data, "quality", found->second.c_str(), AV_OPT_SEARCH_CHILDREN);
|
||||
} else {
|
||||
av_opt_set(context->priv_data, "quality", nullptr, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Rate Control
|
||||
bool have_bitrate = false;
|
||||
bool have_bitrate_range = false;
|
||||
bool have_qp = false;
|
||||
|
||||
ratecontrolmode rc = static_cast<ratecontrolmode>(obs_data_get_int(settings, ST_KEY_RATECONTROL_MODE));
|
||||
auto rcopt = ratecontrolmode_to_opt.find(rc);
|
||||
if (rcopt != ratecontrolmode_to_opt.end()) {
|
||||
av_opt_set(context->priv_data, "rc", rcopt->second.c_str(), AV_OPT_SEARCH_CHILDREN);
|
||||
} else {
|
||||
have_bitrate = true;
|
||||
av_opt_set(context->priv_data, "rc", "cbr", AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
||||
av_opt_set_int(context->priv_data, "filler_data", 0, AV_OPT_SEARCH_CHILDREN);
|
||||
switch (rc) {
|
||||
case ratecontrolmode::CQP:
|
||||
have_qp = true;
|
||||
break;
|
||||
case ratecontrolmode::INVALID:
|
||||
case ratecontrolmode::CBR:
|
||||
have_bitrate = true;
|
||||
av_opt_set_int(context->priv_data, "filler_data", 1, AV_OPT_SEARCH_CHILDREN);
|
||||
break;
|
||||
case ratecontrolmode::VBR_PEAK:
|
||||
case ratecontrolmode::VBR_LATENCY:
|
||||
have_bitrate_range = true;
|
||||
have_bitrate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Look Ahead (Pre-analysis, single frame lookahead)
|
||||
if (int la = static_cast<int>(obs_data_get_int(settings, ST_KEY_RATECONTROL_LOOKAHEAD));
|
||||
!util::is_tristate_default(la)) {
|
||||
av_opt_set_int(context->priv_data, "preanalysis", la, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
||||
// Frame Skipping (Drop frames to maintain bitrate limits)
|
||||
if (int la = static_cast<int>(obs_data_get_int(settings, ST_KEY_RATECONTROL_FRAMESKIPPING));
|
||||
!util::is_tristate_default(la)) {
|
||||
if (std::string_view("amf_h264") == codec->name) {
|
||||
av_opt_set_int(context->priv_data, "frame_skipping", la, AV_OPT_SEARCH_CHILDREN);
|
||||
} else {
|
||||
av_opt_set_int(context->priv_data, "skip_frame", la, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
if (have_bitrate) {
|
||||
int64_t v = obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_TARGET);
|
||||
if (v > -1) {
|
||||
context->bit_rate = static_cast<int>(v * 1000);
|
||||
context->rc_max_rate = context->bit_rate;
|
||||
|
||||
// Support for Replay Buffer
|
||||
obs_data_set_int(settings, "bitrate", v);
|
||||
} else {
|
||||
obs_data_set_int(settings, "bitrate", context->bit_rate);
|
||||
}
|
||||
} else {
|
||||
context->bit_rate = 0;
|
||||
}
|
||||
if (have_bitrate_range) {
|
||||
if (int64_t max = obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_BITRATE_MAXIMUM); max > -1)
|
||||
context->rc_max_rate = static_cast<int>(max * 1000);
|
||||
} else {
|
||||
context->rc_max_rate = 0;
|
||||
}
|
||||
|
||||
// Buffer Size
|
||||
if (have_bitrate || have_bitrate_range) {
|
||||
if (int64_t v = obs_data_get_int(settings, ST_KEY_RATECONTROL_LIMITS_BUFFERSIZE); v > -1)
|
||||
context->rc_buffer_size = static_cast<int>(v * 1000);
|
||||
} else {
|
||||
context->rc_buffer_size = 0;
|
||||
}
|
||||
|
||||
// QP Settings
|
||||
if (have_qp) {
|
||||
if (int64_t qp = obs_data_get_int(settings, ST_KEY_RATECONTROL_QP_I); qp > -1) {
|
||||
av_opt_set_int(context->priv_data, "qp_i", static_cast<int>(qp), AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (int64_t qp = obs_data_get_int(settings, ST_KEY_RATECONTROL_QP_P); qp > -1) {
|
||||
av_opt_set_int(context->priv_data, "qp_p", static_cast<int>(qp), AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
if (std::string_view("amf_h264") == codec->name) {
|
||||
if (int64_t qp = obs_data_get_int(settings, ST_KEY_RATECONTROL_QP_B); qp > -1) {
|
||||
av_opt_set_int(context->priv_data, "qp_b", static_cast<int>(qp), AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Other
|
||||
if (std::string_view("amf_h264") == codec->name) {
|
||||
if (int64_t bf = obs_data_get_int(settings, ST_KEY_OTHER_BFRAMES); bf > -1) {
|
||||
context->max_b_frames = static_cast<int>(bf);
|
||||
}
|
||||
if (int64_t zl = obs_data_get_int(settings, ST_KEY_OTHER_BFRAMEREFERENCES);
|
||||
!util::is_tristate_default(zl)) {
|
||||
av_opt_set_int(context->priv_data, "bf_ref", zl, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
if (int64_t refs = obs_data_get_int(settings, ST_KEY_OTHER_REFERENCEFRAMES); refs > -1) {
|
||||
context->refs = static_cast<int>(refs);
|
||||
}
|
||||
|
||||
if (int64_t v = obs_data_get_int(settings, ST_KEY_OTHER_ENFORCEHRD); !util::is_tristate_default(v)) {
|
||||
av_opt_set_int(context->priv_data, "enforce_hrd", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
||||
if (int64_t v = obs_data_get_int(settings, ST_KEY_OTHER_VBAQ); !util::is_tristate_default(v)) {
|
||||
av_opt_set_int(context->priv_data, "vbaq", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
||||
if (int64_t v = obs_data_get_int(settings, ST_KEY_OTHER_ACCESSUNITDELIMITER); !util::is_tristate_default(v)) {
|
||||
av_opt_set_int(context->priv_data, "aud", v, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
|
||||
av_opt_set_int(context->priv_data, "me_half_pel", 1, AV_OPT_SEARCH_CHILDREN);
|
||||
av_opt_set_int(context->priv_data, "me_quarter_pel", 1, AV_OPT_SEARCH_CHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
void amf::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
using namespace ::ffmpeg;
|
||||
|
||||
DLOG_INFO("[%s] AMD AMF:", codec->name);
|
||||
tools::print_av_option_string2(context, "usage", " Usage",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
tools::print_av_option_string2(context, "quality", " Preset",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
tools::print_av_option_string2(context, "rc", " Rate Control",
|
||||
[](int64_t v, std::string_view o) { return std::string(o); });
|
||||
tools::print_av_option_bool(context, "preanalysis", " Look-Ahead");
|
||||
if (std::string_view("amf_h264") == codec->name) {
|
||||
tools::print_av_option_bool(context, "frame_skipping", " Frame Skipping");
|
||||
} else {
|
||||
tools::print_av_option_bool(context, "skip_frame", " Frame Skipping");
|
||||
}
|
||||
tools::print_av_option_bool(context, "filler_data", " Filler Data");
|
||||
|
||||
DLOG_INFO("[%s] Bitrate:", codec->name);
|
||||
tools::print_av_option_int(context, "b", " Target", "bits/sec");
|
||||
tools::print_av_option_int(context, "maxrate", " Maximum", "bits/sec");
|
||||
tools::print_av_option_int(context, "bufsize", " Buffer", "bits");
|
||||
DLOG_INFO("[%s] Quantization Parameters:", codec->name);
|
||||
tools::print_av_option_int(context, "qp_i", " I-Frame", "");
|
||||
tools::print_av_option_int(context, "qp_p", " P-Frame", "");
|
||||
if (std::string_view("amf_h264") == codec->name) { // B-Frames
|
||||
tools::print_av_option_int(context, "qp_b", " B-Frame", "");
|
||||
|
||||
tools::print_av_option_int(context, "bf", " B-Frames", "Frames");
|
||||
tools::print_av_option_int(context, "bf_delta_qp", " Delta QP", "");
|
||||
tools::print_av_option_bool(context, "bf_ref", " References");
|
||||
tools::print_av_option_int(context, "bf_ref_delta_qp", " Delta QP", "");
|
||||
}
|
||||
|
||||
DLOG_INFO("[%s] Other:", codec->name);
|
||||
tools::print_av_option_int(context, "refs", " Reference Frames", "Frames");
|
||||
tools::print_av_option_bool(context, "enforce_hrd", " Enforce HRD");
|
||||
tools::print_av_option_bool(context, "vbaq", " VBAQ");
|
||||
tools::print_av_option_bool(context, "aud", " Access Unit Delimiter");
|
||||
tools::print_av_option_int(context, "max_au_size", " Maximum Size", "");
|
||||
tools::print_av_option_bool(context, "me_half_pel", " Half-Pel Motion Estimation");
|
||||
tools::print_av_option_bool(context, "me_quarter_pel", " Quarter-Pel Motion Estimation");
|
||||
}
|
||||
|
||||
void streamfx::encoder::ffmpeg::handler::amf::get_runtime_properties(obs_properties_t* props, const AVCodec* codec,
|
||||
AVCodecContext* context)
|
||||
{}
|
||||
|
||||
void streamfx::encoder::ffmpeg::handler::amf::migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec,
|
||||
AVCodecContext* context)
|
||||
{}
|
||||
|
||||
void streamfx::encoder::ffmpeg::handler::amf::override_update(ffmpeg_instance* instance, obs_data_t* settings) {}
|
129
source/encoders/handlers/amf_shared.hpp
Normal file
129
source/encoders/handlers/amf_shared.hpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (c) 2020 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include "common.hpp"
|
||||
#include "handler.hpp"
|
||||
|
||||
extern "C" {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4242 4244 4365)
|
||||
#endif
|
||||
#include <libavcodec/avcodec.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace streamfx::encoder::ffmpeg::handler::amf {
|
||||
enum class preset : int32_t {
|
||||
SPEED,
|
||||
BALANCED,
|
||||
QUALITY,
|
||||
INVALID = -1,
|
||||
};
|
||||
|
||||
enum class ratecontrolmode : int64_t {
|
||||
CQP,
|
||||
CBR,
|
||||
VBR_PEAK,
|
||||
VBR_LATENCY,
|
||||
INVALID = -1,
|
||||
};
|
||||
|
||||
extern std::map<preset, std::string> presets;
|
||||
|
||||
extern std::map<preset, std::string> preset_to_opt;
|
||||
|
||||
extern std::map<ratecontrolmode, std::string> ratecontrolmodes;
|
||||
|
||||
extern std::map<ratecontrolmode, std::string> ratecontrolmode_to_opt;
|
||||
|
||||
bool is_available();
|
||||
|
||||
void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void get_properties_pre(obs_properties_t* props, const AVCodec* codec);
|
||||
|
||||
void get_properties_post(obs_properties_t* props, const AVCodec* codec);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void migrate(obs_data_t* settings, uint64_t version, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void override_update(ffmpeg_instance* instance, obs_data_t* settings);
|
||||
|
||||
void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
} // namespace streamfx::encoder::ffmpeg::handler::amf
|
||||
|
||||
/* Parameters by their codec specific name.
|
||||
* '#' denotes a parameter specified via the context itself.
|
||||
|
||||
H.264 H.265 Options Done?
|
||||
usage usage transcoding --
|
||||
preset preset speed,balanced,quality Defines
|
||||
profile profile <different> Defines
|
||||
level level <different> Defines
|
||||
tier main,high
|
||||
rc rc cqp,cbr,vbr_peak,vbr_latency Defines
|
||||
preanalysis preanalysis false,true Defines
|
||||
vbaq vbaq false,true Defines
|
||||
enforce_hrd enforce_hrd false,true Defines
|
||||
filler_data filler_data false,true --
|
||||
frame_skipping skip_frame false,true Defines
|
||||
qp_i qp_i range(-1 - 51) Defines
|
||||
qp_p qp_p range(-1 - 51) Defines
|
||||
qp_b range(-1 - 51) Defines
|
||||
#max_b_frames Defines
|
||||
bf_delta_qp range(-10 - 10) --
|
||||
bf_ref false,true Defines
|
||||
bf_ref_delta_qp range(-10 - 10) --
|
||||
me_half_pel me_half_pel false,true --
|
||||
me_quarter_pel me_quarter_pel false,true --
|
||||
aud aud false,true Defines
|
||||
max_au_size max_au_size range(0 - Inf) --
|
||||
#refs range(0 - 16?) Defines
|
||||
#color_range AVCOL_RANGE_JPEG FFmpeg
|
||||
#bit_rate Defines
|
||||
#rc_max_rate Defines
|
||||
#rc_buffer_size Defines
|
||||
#rc_initial_buffer_occupancy --
|
||||
#flags AV_CODEC_FLAG_LOOP_FILTER --
|
||||
#gop_size FFmpeg
|
||||
*/
|
||||
|
||||
// AMF H.264
|
||||
// intra_refresh_mb: 0 - Inf
|
||||
// header_spacing: -1 - 1000
|
||||
// coder: auto, cavlc, cabac
|
||||
// qmin, qmax (HEVC uses its own settings)
|
||||
|
||||
// AMF H.265
|
||||
// header_insertion_mode: none, gop, idr
|
||||
// gops_per_idr: 0 - Inf
|
||||
// min_qp_i: -1 - 51
|
||||
// max_qp_i: -1 - 51
|
||||
// min_qp_p: -1 - 51
|
||||
// max_qp_p: -1 - 51
|
Loading…
Reference in a new issue