Compare commits
22 Commits
libvpx-vp9
...
0.2.0pre2
| Author | SHA1 | Date | |
|---|---|---|---|
| a5d14c87ff | |||
| de1a687b8d | |||
| 855b3571b1 | |||
| c053933c25 | |||
| e1fbfd707c | |||
| 69f7afef1f | |||
| 5ba4694890 | |||
| e579b10dcd | |||
| f530f9ee9f | |||
| 8b429db62e | |||
| 6851f2321a | |||
| 2472668f1d | |||
| 6eadcfe821 | |||
| 7663a25bb3 | |||
| 38f154531c | |||
| 666fe5fdfb | |||
| f744b1e9cb | |||
| 9552d12ee8 | |||
| f15769ddb7 | |||
| 8b80dc57ad | |||
| 83c9de95f9 | |||
| a298680e07 |
@@ -0,0 +1,3 @@
|
||||
issuehunt: xaymar
|
||||
patreon: xaymar
|
||||
custom: https://www.paypal.me/xaymar
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Want a new feature implemented?
|
||||
|
||||
---
|
||||
|
||||
<!--- Please fill out the following template, which will help other contributors review your Issue. -->
|
||||
<!--- Make sure you’ve read the contribution guidelines -->
|
||||
|
||||
### Description
|
||||
<!-- Describe the feature (and behavior) in as much detail as possible (yes, that means write an essay if you have to) -->
|
||||
<!-- Include images of what you expect from the feature -->
|
||||
|
||||
### Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] I have read the contribution guidelines.
|
||||
- [ ] This feature is necessary and can't be done through other means.
|
||||
- [ ] This feature does not break existing functionality.
|
||||
- [ ] I am willing to hire/pay someone to implement this.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: Question/Feedback
|
||||
about: Submit a question or some feedback! (Not for bugs, issues or crashes!)
|
||||
|
||||
---
|
||||
|
||||
<!--- Please fill out the following template, which will help other contributors review your Issue. -->
|
||||
<!--- Make sure you’ve read the contribution guidelines -->
|
||||
|
||||
### Description
|
||||
<!-- Describe the feature (and behavior) in as much detail as possible (yes, that means write an essay if you have to) -->
|
||||
<!-- Include images of what you expect from the feature -->
|
||||
|
||||
### System Information
|
||||
<!-- Include as much information about the system you're using as possible. -->
|
||||
- Software Version: [e. g. 1.0.0, 1.2.1, ... - NEVER LATEST]
|
||||
- Operating System: [e. g. Windows, Debian, Ubuntu, RedHat, FreeBSD, ...]
|
||||
- Kernel Version: [e. g. 1903/1809 (Windows), 4.12 (Linux), ...]
|
||||
- CPU: [e. g. Intel i7, AMD Zen2, Qualcomm, ...]
|
||||
- GPU: [e. g. Nvidia RTX 2xxx Series, AMD Radeone 5xxx Series, ...]
|
||||
- RAM: [e. g. 16GB, 32GB, 64GB, ...]
|
||||
|
||||
### Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] I have read the contribution guidelines.
|
||||
- [ ] This is not a bug, crash or generic issue.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: Issue/Bug report
|
||||
about: Encountered a problem, a bug or a crash?
|
||||
|
||||
---
|
||||
|
||||
<!--- Please fill out the following template, which will help other contributors review your Issue. -->
|
||||
<!--- Make sure you’ve read the contribution guidelines -->
|
||||
|
||||
### Description
|
||||
<!-- Describe the bug (and behavior) in as much detail as necessary -->
|
||||
<!-- Include screenshots and attach (crash) logs if possible -->
|
||||
|
||||
### Expected Behavior
|
||||
<!-- What is the expected behavior in this case? -->
|
||||
|
||||
### Reproduction Steps
|
||||
<!-- Describe the steps required to get this to happen from a cleanly installed obs-studio -->
|
||||
<!-- Leave out detail that is not relevant to -->
|
||||
1. Open a portal to the Infinite Void
|
||||
2. Summon an ancient God
|
||||
3. Realize your mistake
|
||||
|
||||
### System Information
|
||||
<!-- Include as much information about the system you're using as possible. -->
|
||||
- Software Version: [e. g. 1.0.0, 1.2.1, ... - NEVER LATEST]
|
||||
- Operating System: [e. g. Windows, Debian, Ubuntu, RedHat, FreeBSD, ...]
|
||||
- Kernel Version: [e. g. 1903/1809 (Windows), 4.12 (Linux), ...]
|
||||
- CPU: [e. g. Intel i7, AMD Zen2, Qualcomm, ...]
|
||||
- GPU: [e. g. Nvidia RTX 2xxx Series, AMD Radeone 5xxx Series, ...]
|
||||
- RAM: [e. g. 16GB, 32GB, 64GB, ...]
|
||||
|
||||
### Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] I have read the contribution guidelines.
|
||||
- [ ] I can reproduce the issue with the exact reproduction steps I have provided.
|
||||
- [ ] The issue appears on all of my systems that can run this software.
|
||||
@@ -0,0 +1,35 @@
|
||||
<!--- Please fill out the following template, which will help other contributors review your Pull Request. -->
|
||||
|
||||
<!--- Make sure you’ve read the contribution guidelines -->
|
||||
|
||||
### Description
|
||||
<!--- Describe your changes in detail. -->
|
||||
<!--- If this change includes UI elements, please include screenshots. -->
|
||||
|
||||
### Motivation and Context
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
<!--- If it fixes an open Mantis issue, or implements feature request -->
|
||||
<!--- from the Ideas page, please link to the issue here. -->
|
||||
|
||||
### How Has This Been Tested?
|
||||
<!--- Please describe in detail how you tested your changes. -->
|
||||
<!--- Include details of your testing environment (hardware, OS version, etc.),-->
|
||||
<!--- and the tests you ran, including how it may affect other areas of code. -->
|
||||
|
||||
### Types of changes
|
||||
<!--- What types of changes does your PR introduce? Uncomment all that apply -->
|
||||
<!--- - Bug fix (non-breaking change which fixes an issue) -->
|
||||
<!--- - New feature (non-breaking change which adds functionality) -->
|
||||
<!--- - Performance enhancement (non-breaking change which improves efficiency) -->
|
||||
<!--- - Code cleanup (non-breaking change which makes code smaller or more readable) -->
|
||||
<!--- - Breaking change (fix or feature that would cause existing functionality to change) -->
|
||||
<!--- - Documentation (a change to documentation pages) -->
|
||||
|
||||
### Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] My code has been run through [clang-format](https://github.com/obsproject/obs-studio/blob/master/.clang-format).
|
||||
- [ ] I have read the [**contributing** document](https://github.com/obsproject/obs-studio/blob/master/CONTRIBUTING.rst).
|
||||
- [ ] My code is not on the master branch.
|
||||
- [ ] The code has been tested.
|
||||
- [ ] All commit messages are properly formatted and commits squashed where appropriate.
|
||||
@@ -264,6 +264,8 @@ set(PROJECT_PRIVATE
|
||||
"${PROJECT_SOURCE_DIR}/source/utility.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/utility.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/strings.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/codecs/hevc.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/codecs/hevc.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/encoders/generic.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/encoders/generic.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/encoders/prores_aw.hpp"
|
||||
@@ -280,6 +282,10 @@ set(PROJECT_PRIVATE
|
||||
"${PROJECT_SOURCE_DIR}/source/ui/debug_handler.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/ui/prores_aw_handler.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/ui/prores_aw_handler.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/ui/nvenc_shared.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/ui/nvenc_shared.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/ui/nvenc_hevc_handler.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/source/ui/nvenc_hevc_handler.cpp"
|
||||
)
|
||||
|
||||
# Source Grouping
|
||||
|
||||
+100
-20
@@ -1,11 +1,9 @@
|
||||
# ProRes
|
||||
ProRes.Profile.Proxy="Proxy (PXY)"
|
||||
ProRes.Profile.Light="Light (LT)"
|
||||
ProRes.Profile.Standard="Standard"
|
||||
ProRes.Profile.HighQuality="High Quality (HQ)"
|
||||
|
||||
# Generic
|
||||
Automatic="Automatic"
|
||||
State.Automatic="Automatic"
|
||||
State.Default="Default"
|
||||
State.Disabled="Disabled"
|
||||
State.Enabled="Enabled"
|
||||
State.Manual="Manual"
|
||||
|
||||
# FFmpeg
|
||||
FFmpeg="FFmpeg Options"
|
||||
@@ -25,19 +23,29 @@ FFmpeg.StandardCompliance.Experimental="Experimental"
|
||||
|
||||
# Rate Control
|
||||
RateControl="Rate Control"
|
||||
RateControl.Method="Method"
|
||||
RateControl.Method.ConstantBitrate="Constant Bitrate (CBR)"
|
||||
RateControl.Method.AverageBitrate="Average Bitrate (ABR)"
|
||||
RateControl.Method.VariableBitrate="Variable Bitrate (VBR)"
|
||||
RateControl.Method.ConstantQuantizationParameter="Constant Quantization Parameter (CQP)"
|
||||
RateControl.Method.ConstantRateFactor="Constant Rate Factor (CRF)"
|
||||
RateControl.Method.ConstantQuality="Constant Quality (CQ)"
|
||||
RateControl.Method.VariableQuality="Variable Quality (VQ)"
|
||||
RateControl.Method.Lossless="Lossless (LL)"
|
||||
RateControl.Bitrate.Target="Target Bitrate (kbit/s)"
|
||||
RateControl.Bitrate.Minimum="Minimum Bitrate (kbit/s)"
|
||||
RateControl.Bitrate.Maximum="Maximum Bitrate (kbit/s)"
|
||||
RateControl.BufferSize="Buffer Size (kbit/s)"
|
||||
RateControl.Mode="Method"
|
||||
RateControl.Mode.ConstantBitrate="Constant Bitrate"
|
||||
RateControl.Mode.AverageBitrate="Average Bitrate"
|
||||
RateControl.Mode.VariableBitrate="Variable Bitrate"
|
||||
RateControl.Mode.ConstantQuantizationParameter="Constant Quantization Parameter"
|
||||
RateControl.Mode.ConstantRateFactor="Constant Rate Factor"
|
||||
RateControl.Mode.ConstantQuality="Constant Quality"
|
||||
RateControl.Mode.VariableQuality="Variable Quality"
|
||||
RateControl.Mode.Lossless="Lossless"
|
||||
RateControl.Bitrate.Target="Target Bitrate"
|
||||
RateControl.Bitrate.Minimum="Minimum Bitrate"
|
||||
RateControl.Bitrate.Maximum="Maximum Bitrate"
|
||||
RateControl.Quality.Target="Target Quality"
|
||||
RateControl.Quality.Minimum="Minimum Quality"
|
||||
RateControl.Quality.Maximum="Maximum Quality"
|
||||
RateControl.BufferSize="Buffer Size"
|
||||
|
||||
# Key Frames
|
||||
KeyFrames="Key Frames"
|
||||
KeyFrames.IntervalType="Interval Type"
|
||||
KeyFrames.IntervalType.Frames="Frames"
|
||||
KeyFrames.IntervalType.Seconds="Seconds"
|
||||
KeyFrames.Interval="Interval"
|
||||
|
||||
# Apple ProRes
|
||||
AppleProRes.Profile="Profile"
|
||||
@@ -46,3 +54,75 @@ AppleProRes.Profile.APCS="LT"
|
||||
AppleProRes.Profile.APCN="Standard Definition"
|
||||
AppleProRes.Profile.APCH="High Quality"
|
||||
AppleProRes.Profile.AP4H="4444"
|
||||
|
||||
# ProRes
|
||||
ProRes.Profile.Proxy="Proxy (PXY)"
|
||||
ProRes.Profile.Light="Light (LT)"
|
||||
ProRes.Profile.Standard="Standard"
|
||||
ProRes.Profile.HighQuality="High Quality (HQ)"
|
||||
|
||||
# Codec: HEVC
|
||||
Codec.HEVC="HEVC"
|
||||
Codec.HEVC.Profile="Profile"
|
||||
Codec.HEVC.Profile.main="Main"
|
||||
Codec.HEVC.Profile.main10="Main 10-bit"
|
||||
Codec.HEVC.Profile.rext="Range Extended"
|
||||
Codec.HEVC.Tier="Tier"
|
||||
Codec.HEVC.Tier.main="Main"
|
||||
Codec.HEVC.Tier.high="High"
|
||||
Codec.HEVC.Level="Level"
|
||||
|
||||
# NVENC
|
||||
NVENC.Preset="Preset"
|
||||
NVENC.Preset.Default="Default"
|
||||
NVENC.Preset.Slow="Slow"
|
||||
NVENC.Preset.Medium="Medium"
|
||||
NVENC.Preset.Fast="Fast"
|
||||
NVENC.Preset.HighPerformance="High Performance"
|
||||
NVENC.Preset.HighQuality="High Quality"
|
||||
NVENC.Preset.BluRayDisc="BluRay Disc"
|
||||
NVENC.Preset.LowLatency="Low Latency"
|
||||
NVENC.Preset.LowLatencyHighPerformance="Low Latency High Performance"
|
||||
NVENC.Preset.LowLatencyHighQuality="Low Latency High Quality"
|
||||
NVENC.Preset.Lossless="Lossless"
|
||||
NVENC.Preset.LosslessHighPerformance="Lossless High Performance"
|
||||
NVENC.RateControl="Rate Control Options"
|
||||
NVENC.RateControl.Mode="Mode"
|
||||
NVENC.RateControl.Mode.CQP="Constant Quantization Parameter"
|
||||
NVENC.RateControl.Mode.VBR="Variable Bitrate"
|
||||
NVENC.RateControl.Mode.VBR_HQ="High Quality Variable Bitrate"
|
||||
NVENC.RateControl.Mode.CBR="Constant Bitrate"
|
||||
NVENC.RateControl.Mode.CBR_HQ="High Quality Constant Bitrate"
|
||||
NVENC.RateControl.Mode.CBR_LD_HQ="Low Delay High Quality Constant Bitrate"
|
||||
NVENC.RateControl.LookAhead="Look Ahead"
|
||||
NVENC.RateControl.LookAhead.Description="Look ahead this many frames while encoding to better distribute bitrate.\nImproves quality slightly at the cost of some GPU time.\nSet to 0 to disable."
|
||||
NVENC.RateControl.AdaptiveI="Enable adaptive I-Frame insertion"
|
||||
NVENC.RateControl.AdaptiveI.Description="Enables adaptive I-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0."
|
||||
NVENC.RateControl.AdaptiveB="Enable adaptive B-Frame insertion"
|
||||
NVENC.RateControl.AdaptiveB.Description="Enables adaptive B-Frame insertion.\nOnly has an effect when look ahead is set to a value other than 0."
|
||||
NVENC.RateControl.TwoPass="Enable Two Pass"
|
||||
NVENC.RateControl.TwoPass.Description="Enable a secondary pass for encoding, which can help with quality and bitrate stability.\nImproves quality slightly at the cost of some GPU time.\nNvidia Turing hardware might actually see a quality degrade from this."
|
||||
NVENC.RateControl.Bitrate="Bitrate Limits"
|
||||
NVENC.RateControl.Bitrate.Target="Target Bitrate"
|
||||
NVENC.RateControl.Bitrate.Maximum="Maximum Bitrate"
|
||||
NVENC.RateControl.Quality="Enable Quality Limits"
|
||||
NVENC.RateControl.Quality.Minimum="Minimum"
|
||||
NVENC.RateControl.Quality.Minimum.Description="Minimum quality to achieve, with values closer to 0 being better quality."
|
||||
NVENC.RateControl.Quality.Maximum="Maximum"
|
||||
NVENC.RateControl.Quality.Maximum.Description="Maximum quality to achieve, with values closer to 0 being better quality.\nSet to -1 to disable the maximum restriction."
|
||||
NVENC.AQ="Adaptive Quantization"
|
||||
NVENC.AQ.Spatial="Enable Spatial Adaptive Quantization"
|
||||
NVENC.AQ.Strength="Spatial AQ Strength"
|
||||
NVENC.AQ.Strength.Description="Strength of the spatial adaptive quantization.\nValues closer to 15 mean more aggressive, while values closer to 1 mean more relaxed."
|
||||
NVENC.AQ.Temporal="Enable Temporal Adaptive Quantization"
|
||||
NVENC.Other="Other Options"
|
||||
NVENC.Other.BFrames="Maximum B-Frames"
|
||||
NVENC.Other.BFrameReferenceMode="B-Frame Reference Mode"
|
||||
NVENC.Other.BFrameReferenceMode.Each="Each B-Frame will be used for references"
|
||||
NVENC.Other.BFrameReferenceMode.Middle="Only (# of B-Frames)/2 will be used for references"
|
||||
NVENC.Other.ZeroLatency="Enable Zero Latency"
|
||||
NVENC.Other.ZeroLatency.Description="Enable zero latency operation, which ensures that there is no reordering delay."
|
||||
NVENC.Other.WeightedPrediction="Enable Weighted Prediction"
|
||||
NVENC.Other.WeightedPrediction.Description="Enable weighted prediction for encoding.\nCan't be used with B-Frames."
|
||||
NVENC.Other.NonReferencePFrames="Enable non-reference P-Frames"
|
||||
NVENC.Other.NonReferencePFrames.Description="Enable the automatic insertion of non-reference P-Frames."
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (C) 2018 - 2019 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 "hevc.hpp"
|
||||
|
||||
using namespace obsffmpeg::codecs::hevc;
|
||||
|
||||
std::map<profile, std::string> obsffmpeg::codecs::hevc::profiles{
|
||||
{profile::MAIN, "main"},
|
||||
{profile::MAIN10, "main10"},
|
||||
{profile::RANGE_EXTENDED, "rext"},
|
||||
};
|
||||
|
||||
std::map<tier, std::string> obsffmpeg::codecs::hevc::profile_tiers{
|
||||
{tier::MAIN, "main"},
|
||||
{tier::HIGH, "high"},
|
||||
};
|
||||
|
||||
std::map<level, std::string> obsffmpeg::codecs::hevc::levels{
|
||||
{level::L1_0, "1.0"}, {level::L2_0, "2.0"}, {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"},
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (C) 2018 - 2019 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 <map>
|
||||
|
||||
// Codec: HEVC
|
||||
#define P_HEVC "Codec.HEVC"
|
||||
#define P_HEVC_PROFILE "Codec.HEVC.Profile"
|
||||
#define P_HEVC_TIER "Codec.HEVC.Tier"
|
||||
#define P_HEVC_LEVEL "Codec.HEVC.Level"
|
||||
|
||||
namespace obsffmpeg {
|
||||
namespace codecs {
|
||||
namespace hevc {
|
||||
enum class profile {
|
||||
MAIN,
|
||||
MAIN10,
|
||||
RANGE_EXTENDED,
|
||||
UNKNOWN = -1,
|
||||
};
|
||||
|
||||
enum class tier {
|
||||
MAIN,
|
||||
HIGH,
|
||||
UNKNOWN = -1,
|
||||
};
|
||||
|
||||
enum class level {
|
||||
L1_0 = 30,
|
||||
L2_0 = 60,
|
||||
L3_0 = 90,
|
||||
L3_1 = 93,
|
||||
L4_0 = 120,
|
||||
L4_1 = 123,
|
||||
L5_0 = 150,
|
||||
L5_1 = 153,
|
||||
L5_2 = 156,
|
||||
L6_0 = 180,
|
||||
L6_1 = 183,
|
||||
L6_2 = 186,
|
||||
UNKNOWN = -1,
|
||||
};
|
||||
|
||||
extern std::map<profile, std::string> profiles;
|
||||
|
||||
extern std::map<tier, std::string> profile_tiers;
|
||||
|
||||
extern std::map<level, std::string> levels;
|
||||
|
||||
} // namespace hevc
|
||||
} // namespace codecs
|
||||
} // namespace obsffmpeg
|
||||
+3
-3
@@ -39,8 +39,8 @@ namespace obsffmpeg {
|
||||
protected:
|
||||
obs_encoder_t* self = nullptr;
|
||||
|
||||
AVCodec* avcodec = nullptr;
|
||||
AVCodecContext* avcontext = nullptr;
|
||||
AVCodec* avcodec = nullptr;
|
||||
AVCodecContext* avcontext = nullptr;
|
||||
AVDictionary* avdictionary = nullptr;
|
||||
ffmpeg::swscale swscale;
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace obsffmpeg {
|
||||
{ \
|
||||
_source##_info.id = "obs-ffmpeg-encoder-" #_source; \
|
||||
_source##_info.type = OBS_ENCODER_VIDEO; \
|
||||
_source##_info.caps = 0; \
|
||||
_source##_info.caps = OBS_ENCODER_CAP_DEPRECATED; \
|
||||
_source##_info.codec = _codec; \
|
||||
_source##_info.create = _source##_create; \
|
||||
_source##_info.destroy = _source##_destroy; \
|
||||
|
||||
+47
-33
@@ -28,9 +28,10 @@ extern "C" {
|
||||
#include <obs-module.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/frame.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include <libavutil/dict.h>
|
||||
#include <libavutil/frame.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
@@ -64,11 +65,11 @@ void encoder::generic_factory::register_encoder()
|
||||
// TODO: Figure out a way to translate from names to other names.
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "[FFmpeg] " << (avcodec_ptr->long_name ? avcodec_ptr->long_name : avcodec_ptr->name) << " ("
|
||||
sstr << (avcodec_ptr->long_name ? avcodec_ptr->long_name : avcodec_ptr->name) << " ("
|
||||
<< avcodec_ptr->name << ")";
|
||||
std::string caps = ffmpeg::tools::translate_encoder_capabilities(avcodec_ptr->capabilities);
|
||||
if (caps.length() != 0) {
|
||||
sstr << " (" << caps << ")";
|
||||
sstr << " [" << caps << "]";
|
||||
}
|
||||
this->info.readable_name = sstr.str();
|
||||
}
|
||||
@@ -85,6 +86,13 @@ void encoder::generic_factory::register_encoder()
|
||||
this->info.oei.id = this->info.uid.c_str();
|
||||
this->info.oei.codec = this->info.codec.c_str();
|
||||
|
||||
// Is this a deprecated encoder?
|
||||
#ifndef _DEBUG
|
||||
if (!obsffmpeg::has_codec_handler(avcodec_ptr->name)) {
|
||||
this->info.oei.caps |= OBS_ENCODER_CAP_DEPRECATED;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Detect encoder type (only Video and Audio supported)
|
||||
if (avcodec_ptr->type == AVMediaType::AVMEDIA_TYPE_VIDEO) {
|
||||
this->info.oei.type = obs_encoder_type::OBS_ENCODER_VIDEO;
|
||||
@@ -271,8 +279,8 @@ void encoder::generic_factory::register_encoder()
|
||||
this->info.oei.type_data = this;
|
||||
|
||||
obs_register_encoder(&this->info.oei);
|
||||
PLOG_INFO("Registered encoder #%llX with name '%s' and long name '%s' and caps %llX", avcodec_ptr,
|
||||
avcodec_ptr->name, avcodec_ptr->long_name, avcodec_ptr->capabilities);
|
||||
PLOG_DEBUG("Registered encoder #%llX with name '%s' and long name '%s' and caps %llX", avcodec_ptr,
|
||||
avcodec_ptr->name, avcodec_ptr->long_name, avcodec_ptr->capabilities);
|
||||
}
|
||||
|
||||
const char* encoder::generic_factory::get_name()
|
||||
@@ -308,15 +316,20 @@ void encoder::generic_factory::get_properties(obs_properties_t* props)
|
||||
}
|
||||
|
||||
{
|
||||
auto prs = obs_properties_create();
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
auto prs = obs_properties_create();
|
||||
obs_properties_add_group(props, P_FFMPEG, TRANSLATE(P_FFMPEG), OBS_GROUP_NORMAL, prs);
|
||||
}
|
||||
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_text(prs, P_FFMPEG_CUSTOMSETTINGS, TRANSLATE(P_FFMPEG_CUSTOMSETTINGS),
|
||||
obs_properties_add_text(grp, P_FFMPEG_CUSTOMSETTINGS, TRANSLATE(P_FFMPEG_CUSTOMSETTINGS),
|
||||
obs_text_type::OBS_TEXT_DEFAULT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_FFMPEG_CUSTOMSETTINGS)));
|
||||
}
|
||||
if (this->avcodec_ptr->pix_fmts) {
|
||||
auto p = obs_properties_add_list(prs, P_FFMPEG_COLORFORMAT, TRANSLATE(P_FFMPEG_COLORFORMAT),
|
||||
auto p = obs_properties_add_list(grp, P_FFMPEG_COLORFORMAT, TRANSLATE(P_FFMPEG_COLORFORMAT),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_FFMPEG_COLORFORMAT)));
|
||||
obs_property_list_add_int(p, TRANSLATE(P_AUTOMATIC), static_cast<int64_t>(AV_PIX_FMT_NONE));
|
||||
@@ -325,13 +338,13 @@ void encoder::generic_factory::get_properties(obs_properties_t* props)
|
||||
static_cast<int64_t>(*ptr));
|
||||
}
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(prs, P_FFMPEG_THREADS, TRANSLATE(P_FFMPEG_THREADS), 0,
|
||||
if (this->avcodec_ptr->capabilities & (AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)) {
|
||||
auto p = obs_properties_add_int_slider(grp, P_FFMPEG_THREADS, TRANSLATE(P_FFMPEG_THREADS), 0,
|
||||
std::thread::hardware_concurrency() * 2, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_FFMPEG_THREADS)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(prs, P_FFMPEG_STANDARDCOMPLIANCE,
|
||||
auto p = obs_properties_add_list(grp, P_FFMPEG_STANDARDCOMPLIANCE,
|
||||
TRANSLATE(P_FFMPEG_STANDARDCOMPLIANCE), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_FFMPEG_STANDARDCOMPLIANCE)));
|
||||
@@ -346,7 +359,6 @@ void encoder::generic_factory::get_properties(obs_properties_t* props)
|
||||
obs_property_list_add_int(p, TRANSLATE(P_FFMPEG_STANDARDCOMPLIANCE ".Experimental"),
|
||||
FF_COMPLIANCE_EXPERIMENTAL);
|
||||
}
|
||||
obs_properties_add_group(props, P_FFMPEG, TRANSLATE(P_FFMPEG), OBS_GROUP_NORMAL, prs);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -380,20 +392,22 @@ encoder::generic::generic(obs_data_t* settings, obs_encoder_t* encoder)
|
||||
static_cast<int>(obs_data_get_int(settings, P_FFMPEG_STANDARDCOMPLIANCE));
|
||||
this->context->debug = 0;
|
||||
/// Threading
|
||||
if (this->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
|
||||
this->context->thread_type = FF_THREAD_SLICE;
|
||||
} else if (this->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
|
||||
this->context->thread_type = FF_THREAD_FRAME;
|
||||
} else {
|
||||
this->context->thread_type = 0;
|
||||
}
|
||||
int64_t threads = obs_data_get_int(settings, P_FFMPEG_THREADS);
|
||||
if (threads > 0) {
|
||||
this->context->thread_count = static_cast<int>(threads);
|
||||
this->lag_in_frames = this->context->thread_count;
|
||||
} else {
|
||||
this->context->thread_count = std::thread::hardware_concurrency();
|
||||
this->lag_in_frames = this->context->thread_count;
|
||||
if (this->codec->capabilities
|
||||
& (AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)) {
|
||||
if (this->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
|
||||
this->context->thread_type |= FF_THREAD_FRAME;
|
||||
}
|
||||
if (this->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
|
||||
this->context->thread_type |= FF_THREAD_SLICE;
|
||||
}
|
||||
int64_t threads = obs_data_get_int(settings, P_FFMPEG_THREADS);
|
||||
if (threads > 0) {
|
||||
this->context->thread_count = static_cast<int>(threads);
|
||||
this->lag_in_frames = this->context->thread_count;
|
||||
} else {
|
||||
this->context->thread_count = std::thread::hardware_concurrency();
|
||||
this->lag_in_frames = this->context->thread_count;
|
||||
}
|
||||
}
|
||||
|
||||
// Video and Audio exclusive setup
|
||||
@@ -446,8 +460,8 @@ encoder::generic::generic(obs_data_t* settings, obs_encoder_t* encoder)
|
||||
}
|
||||
|
||||
// Framerate
|
||||
this->context->time_base.num = voi->fps_num;
|
||||
this->context->time_base.den = voi->fps_den;
|
||||
this->context->time_base.num = voi->fps_den;
|
||||
this->context->time_base.den = voi->fps_num;
|
||||
this->context->ticks_per_frame = 1;
|
||||
} else if (this->codec->type == AVMEDIA_TYPE_AUDIO) {
|
||||
}
|
||||
@@ -528,8 +542,8 @@ bool encoder::generic::update(obs_data_t* settings)
|
||||
|
||||
{ // FFmpeg
|
||||
// Apply custom options.
|
||||
av_opt_set_from_string(this->context, obs_data_get_string(settings, P_FFMPEG_CUSTOMSETTINGS), nullptr,
|
||||
";", "=");
|
||||
av_opt_set_from_string(this->context->priv_data, obs_data_get_string(settings, P_FFMPEG_CUSTOMSETTINGS),
|
||||
nullptr, "=", ";");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -678,7 +692,7 @@ int encoder::generic::receive_packet(bool* received_packet, struct encoder_packe
|
||||
if (res == 0) {
|
||||
packet->type = OBS_ENCODER_VIDEO;
|
||||
packet->pts = this->current_packet->pts;
|
||||
packet->dts = this->current_packet->pts;
|
||||
packet->dts = this->current_packet->dts;
|
||||
packet->data = this->current_packet->data;
|
||||
packet->size = this->current_packet->size;
|
||||
packet->keyframe = !!(this->current_packet->flags & AV_PKT_FLAG_KEY);
|
||||
|
||||
@@ -26,7 +26,7 @@ std::shared_ptr<AVFrame> ffmpeg::avframe_queue::create_frame()
|
||||
frame->height = this->resolution.second;
|
||||
frame->format = this->format;
|
||||
|
||||
int res = av_frame_get_buffer(frame.get(), 0);
|
||||
int res = av_frame_get_buffer(frame.get(), 32);
|
||||
if (res < 0) {
|
||||
throw std::exception(ffmpeg::tools::get_error_description(res));
|
||||
}
|
||||
@@ -105,7 +105,8 @@ std::shared_ptr<AVFrame> ffmpeg::avframe_queue::pop()
|
||||
ret = create_frame();
|
||||
} else {
|
||||
frames.pop_front();
|
||||
if ((ret->width != this->resolution.first) || (ret->height != this->resolution.second)
|
||||
if ((static_cast<uint32_t>(ret->width) != this->resolution.first)
|
||||
|| (static_cast<uint32_t>(ret->height) != this->resolution.second)
|
||||
|| (ret->format != this->format)) {
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ std::string ffmpeg::tools::translate_encoder_capabilities(int capabilities)
|
||||
|
||||
// Quality
|
||||
{AV_CODEC_CAP_LOSSLESS, "Lossless"},
|
||||
{AV_CODEC_CAP_INTRA_ONLY, "I-Frames only"},
|
||||
//{AV_CODEC_CAP_INTRA_ONLY, "I-Frames only"},
|
||||
|
||||
// Threading
|
||||
{AV_CODEC_CAP_FRAME_THREADS, "Frame-Threading"},
|
||||
{AV_CODEC_CAP_SLICE_THREADS, "Slice-Threading"},
|
||||
{AV_CODEC_CAP_AUTO_THREADS, "Automatic-Threading"},
|
||||
//{AV_CODEC_CAP_FRAME_THREADS, "Frame-Threading"},
|
||||
//{AV_CODEC_CAP_SLICE_THREADS, "Slice-Threading"},
|
||||
//{AV_CODEC_CAP_AUTO_THREADS, "Automatic-Threading"},
|
||||
|
||||
// Features
|
||||
{AV_CODEC_CAP_PARAM_CHANGE, "Dynamic Parameter Change"},
|
||||
@@ -49,7 +49,7 @@ std::string ffmpeg::tools::translate_encoder_capabilities(int capabilities)
|
||||
{AV_CODEC_CAP_VARIABLE_FRAME_SIZE, "Variable Frame Size"},
|
||||
{AV_CODEC_CAP_SMALL_LAST_FRAME, "Small Final Frame"},
|
||||
//{AV_CODEC_CAP_DR1, "Uses get_buffer"},
|
||||
{AV_CODEC_CAP_DELAY, "Requires Flush"},
|
||||
//{AV_CODEC_CAP_DELAY, "Requires Flush"},
|
||||
|
||||
// Other
|
||||
{AV_CODEC_CAP_TRUNCATED, "Truncated"},
|
||||
|
||||
@@ -54,6 +54,12 @@ std::shared_ptr<obsffmpeg::ui::handler> obsffmpeg::find_codec_handler(std::strin
|
||||
return found->second;
|
||||
}
|
||||
|
||||
bool obsffmpeg::has_codec_handler(std::string codec)
|
||||
{
|
||||
auto found = codec_to_handler_map.find(codec);
|
||||
return (found != codec_to_handler_map.end());
|
||||
}
|
||||
|
||||
static std::map<AVCodec*, std::shared_ptr<encoder::generic_factory>> generic_factories;
|
||||
|
||||
MODULE_EXPORT bool obs_module_load(void)
|
||||
|
||||
@@ -31,6 +31,8 @@ namespace obsffmpeg {
|
||||
|
||||
std::shared_ptr<obsffmpeg::ui::handler> find_codec_handler(std::string codec);
|
||||
|
||||
bool has_codec_handler(std::string codec);
|
||||
|
||||
} // namespace obsffmpeg
|
||||
|
||||
MODULE_EXPORT bool obs_module_load(void);
|
||||
|
||||
+29
-7
@@ -18,10 +18,32 @@
|
||||
#pragma once
|
||||
#include "utility.hpp"
|
||||
|
||||
#define P_RATECONTROL "RateControl"
|
||||
#define P_RATECONTROL_METHOD "RateControl.Method"
|
||||
#define P_RATECONTROL_METHOD_(x) "RateControl.Method." D_VSTR(x)
|
||||
#define P_RATECONTROL_BITRATE_TARGET "RateControl.Bitrate.Target"
|
||||
#define P_RATECONTROL_BITRATE_MINIMUM "RateControl.Bitrate.Minimum"
|
||||
#define P_RATECONTROL_BITRATE_MAXIMUM "RateControl.Bitrate.Maximum"
|
||||
#define P_RATECONTROL_BUFFERSIZE "RateControl.BufferSize"
|
||||
#define G_STATE_DEFAULT "State.Default"
|
||||
#define G_STATE_DISABLED "State.Disabled"
|
||||
#define G_STATE_ENABLED "State.Enabled"
|
||||
#define G_STATE_AUTOMATIC "State.Automatic"
|
||||
#define G_STATE_MANUAL "State.Manual"
|
||||
|
||||
#define G_RATECONTROL "RateControl"
|
||||
#define G_RATECONTROL_MODE "RateControl.Mode"
|
||||
#define G_RATECONTROL_MODE_(x) "RateControl.Mode." D_VSTR(x)
|
||||
#define G_RATECONTROL_BITRATE_TARGET "RateControl.Bitrate.Target"
|
||||
#define G_RATECONTROL_BITRATE_MINIMUM "RateControl.Bitrate.Minimum"
|
||||
#define G_RATECONTROL_BITRATE_MAXIMUM "RateControl.Bitrate.Maximum"
|
||||
#define G_RATECONTROL_BUFFERSIZE "RateControl.BufferSize"
|
||||
#define G_RATECONTROL_QUALITY_TARGET "RateControl.Quality.Target"
|
||||
#define G_RATECONTROL_QUALITY_MINIMUM "RateControl.Quality.Minimum"
|
||||
#define G_RATECONTROL_QUALITY_MAXIMUM "RateControl.Quality.Maximum"
|
||||
#define G_RATECONTROL_QP_I "RateControl.QP.I"
|
||||
#define G_RATECONTROL_QP_P "RateControl.QP.P"
|
||||
#define G_RATECONTROL_QP_B "RateControl.QP.B"
|
||||
#define G_RATECONTROL_QP_I_INITIAL "RateControl.QP.I.Initial"
|
||||
#define G_RATECONTROL_QP_P_INITIAL "RateControl.QP.P.Initial"
|
||||
#define G_RATECONTROL_QP_B_INITIAL "RateControl.QP.B.Initial"
|
||||
|
||||
#define G_KEYFRAMES "KeyFrames"
|
||||
#define G_KEYFRAMES_INTERVALTYPE "KeyFrames.IntervalType"
|
||||
#define G_KEYFRAMES_INTERVALTYPE_(x) "KeyFrames.IntervalType." D_VSTR(x)
|
||||
#define G_KEYFRAMES_INTERVAL "KeyFrames.Interval"
|
||||
#define G_KEYFRAMES_INTERVAL_SECONDS "KeyFrames.Interval.Seconds"
|
||||
#define G_KEYFRAMES_INTERVAL_FRAMES "KeyFrames.Interval.Frames"
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C" {
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
void obsffmpeg::ui::debug_handler::get_defaults(obs_data_t* settings, AVCodec* codec, AVCodecContext* context) {}
|
||||
void obsffmpeg::ui::debug_handler::get_defaults(obs_data_t*, AVCodec*, AVCodecContext*) {}
|
||||
|
||||
template<typename T>
|
||||
std::string to_string(T value){};
|
||||
@@ -60,14 +60,16 @@ std::string to_string(double_t value)
|
||||
return std::string(buf.data(), buf.data() + buf.size());
|
||||
}
|
||||
|
||||
void obsffmpeg::ui::debug_handler::get_properties(obs_properties_t* props, AVCodec* codec, AVCodecContext* context)
|
||||
void obsffmpeg::ui::debug_handler::get_properties(obs_properties_t*, AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
if (context)
|
||||
return;
|
||||
|
||||
AVCodecContext* ctx = avcodec_alloc_context3(codec);
|
||||
if (!ctx->priv_data)
|
||||
if (!ctx->priv_data) {
|
||||
avcodec_free_context(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
PLOG_INFO("Options for '%s':", codec->name);
|
||||
|
||||
@@ -200,4 +202,4 @@ void obsffmpeg::ui::debug_handler::get_properties(obs_properties_t* props, AVCod
|
||||
}
|
||||
}
|
||||
|
||||
void obsffmpeg::ui::debug_handler::update(obs_data_t* settings, AVCodec* codec, AVCodecContext* context) {}
|
||||
void obsffmpeg::ui::debug_handler::update(obs_data_t*, AVCodec*, AVCodecContext*) {}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (C) 2018 - 2019 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 "nvenc_hevc_handler.hpp"
|
||||
#include "codecs/hevc.hpp"
|
||||
#include "nvenc_shared.hpp"
|
||||
#include "plugin.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <obs-module.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include <libavutil/opt.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
/* Missing Options:
|
||||
|
||||
Seem to be covered by initQP_* instead.
|
||||
- [obs-ffmpeg-encoder] Option 'cq' with help 'Set target quality level (0 to 51, 0 means automatic) for constant quality mode in VBR rate control' of type 'Float' with default value '0.000000', minimum '0.000000' and maximum '51.000000'.
|
||||
- [obs-ffmpeg-encoder] Option 'qp' with help 'Constant quantization parameter rate control method' of type 'Int' with default value '-1', minimum '-1.000000' and maximum '51.000000'.
|
||||
|
||||
Not sure what there are useful for.
|
||||
[obs-ffmpeg-encoder] Option 'aud' with help 'Use access unit delimiters' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'.
|
||||
[obs-ffmpeg-encoder] Option 'surfaces' with help 'Number of concurrent surfaces' of type 'Int' with default value '0', minimum '0.000000' and maximum '64.000000'.
|
||||
[obs-ffmpeg-encoder] Option 'delay' with help 'Delay frame output by the given amount of frames' of type 'Int' with default value '2147483647', minimum '0.000000' and maximum '2147483647.000000'.
|
||||
|
||||
Should probably add this.
|
||||
[obs-ffmpeg-encoder] Option 'gpu' with unit (gpu) with help 'Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on.' of type 'Int' with default value '-1', minimum '-2.000000' and maximum '2147483647.000000'.
|
||||
[obs-ffmpeg-encoder] [gpu] Constant 'any' and help text 'Pick the first device available' with value '-1'.
|
||||
[obs-ffmpeg-encoder] [gpu] Constant 'list' and help text 'List the available devices' with value '-2'.
|
||||
|
||||
Useless except for strict_gop maybe?
|
||||
[obs-ffmpeg-encoder] Option 'forced-idr' with help 'If forcing keyframes, force them as IDR frames.' of type 'Bool' with default value 'false', minimum '-1.000000' and maximum '1.000000'.
|
||||
[obs-ffmpeg-encoder] Option 'strict_gop' with help 'Set 1 to minimize GOP-to-GOP rate fluctuations' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'.
|
||||
[obs-ffmpeg-encoder] Option 'bluray-compat' with help 'Bluray compatibility workarounds' of type 'Bool' with default value 'false', minimum '0.000000' and maximum '1.000000'.
|
||||
*/
|
||||
|
||||
INITIALIZER(nvenc_hevc_handler_init)
|
||||
{
|
||||
obsffmpeg::initializers.push_back([]() {
|
||||
obsffmpeg::register_codec_handler("hevc_nvenc", std::make_shared<obsffmpeg::ui::nvenc_hevc_handler>());
|
||||
});
|
||||
};
|
||||
|
||||
void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::get_defaults(settings, codec, context);
|
||||
|
||||
obs_data_set_default_int(settings, P_HEVC_PROFILE, static_cast<int64_t>(codecs::hevc::profile::MAIN));
|
||||
obs_data_set_default_int(settings, P_HEVC_TIER, static_cast<int64_t>(codecs::hevc::profile::MAIN));
|
||||
obs_data_set_default_int(settings, P_HEVC_LEVEL, static_cast<int64_t>(codecs::hevc::level::UNKNOWN));
|
||||
}
|
||||
|
||||
void obsffmpeg::ui::nvenc_hevc_handler::get_properties(obs_properties_t* props, AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
if (!context) {
|
||||
this->get_encoder_properties(props, codec);
|
||||
} else {
|
||||
this->get_runtime_properties(props, codec, context);
|
||||
}
|
||||
}
|
||||
|
||||
void obsffmpeg::ui::nvenc_hevc_handler::update(obs_data_t* settings, AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
nvenc::update(settings, codec, context);
|
||||
|
||||
{ // HEVC Options
|
||||
codecs::hevc::profile profile =
|
||||
static_cast<codecs::hevc::profile>(obs_data_get_int(settings, P_HEVC_PROFILE));
|
||||
switch (profile) {
|
||||
case codecs::hevc::profile::MAIN:
|
||||
case codecs::hevc::profile::MAIN10:
|
||||
case codecs::hevc::profile::RANGE_EXTENDED:
|
||||
av_opt_set_int(context->priv_data, "profile", static_cast<int64_t>(profile), 0);
|
||||
break;
|
||||
default:
|
||||
av_opt_set_int(context->priv_data, "profile", static_cast<int64_t>(codecs::hevc::profile::MAIN),
|
||||
0);
|
||||
break;
|
||||
}
|
||||
|
||||
codecs::hevc::tier tier = static_cast<codecs::hevc::tier>(obs_data_get_int(settings, P_HEVC_TIER));
|
||||
switch (tier) {
|
||||
case codecs::hevc::tier::MAIN:
|
||||
case codecs::hevc::tier::HIGH:
|
||||
av_opt_set_int(context->priv_data, "tier", static_cast<int64_t>(tier), 0);
|
||||
break;
|
||||
default:
|
||||
av_opt_set_int(context->priv_data, "tier", static_cast<int64_t>(codecs::hevc::tier::MAIN), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
codecs::hevc::level level = static_cast<codecs::hevc::level>(obs_data_get_int(settings, P_HEVC_LEVEL));
|
||||
if (level != codecs::hevc::level::UNKNOWN) {
|
||||
av_opt_set_int(context->priv_data, "level", static_cast<int64_t>(level), 0);
|
||||
} else {
|
||||
av_opt_set_int(context->priv_data, "level", static_cast<int64_t>(0), 0); // Automatic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obsffmpeg::ui::nvenc_hevc_handler::get_encoder_properties(obs_properties_t* props, AVCodec* codec)
|
||||
{
|
||||
nvenc::get_properties_pre(props, codec);
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, P_HEVC, TRANSLATE(P_HEVC), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, P_HEVC_PROFILE, TRANSLATE(P_HEVC_PROFILE),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_HEVC_PROFILE)));
|
||||
obs_property_list_add_int(p, TRANSLATE(G_STATE_DEFAULT),
|
||||
static_cast<int64_t>(codecs::hevc::profile::UNKNOWN));
|
||||
for (auto kv : codecs::hevc::profiles) {
|
||||
std::string trans = std::string(P_HEVC_PROFILE) + "." + kv.second;
|
||||
obs_property_list_add_int(p, TRANSLATE(trans.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, P_HEVC_TIER, TRANSLATE(P_HEVC_TIER), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_HEVC_TIER)));
|
||||
obs_property_list_add_int(p, TRANSLATE(G_STATE_DEFAULT),
|
||||
static_cast<int64_t>(codecs::hevc::tier::UNKNOWN));
|
||||
for (auto kv : codecs::hevc::profile_tiers) {
|
||||
std::string trans = std::string(P_HEVC_TIER) + "." + kv.second;
|
||||
obs_property_list_add_int(p, TRANSLATE(trans.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, P_HEVC_LEVEL, TRANSLATE(P_HEVC_LEVEL),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_HEVC_LEVEL)));
|
||||
obs_property_list_add_int(p, TRANSLATE(G_STATE_AUTOMATIC),
|
||||
static_cast<int64_t>(codecs::hevc::level::UNKNOWN));
|
||||
for (auto kv : codecs::hevc::levels) {
|
||||
obs_property_list_add_int(p, kv.second.c_str(), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nvenc::get_properties_post(props, codec);
|
||||
}
|
||||
|
||||
void obsffmpeg::ui::nvenc_hevc_handler::get_runtime_properties(obs_properties_t* props, AVCodec* codec,
|
||||
AVCodecContext* context)
|
||||
{
|
||||
nvenc::get_runtime_properties(props, codec, context);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (C) 2018 - 2019 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" {
|
||||
#include <obs-properties.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include <libavcodec/avcodec.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
namespace obsffmpeg {
|
||||
namespace ui {
|
||||
class nvenc_hevc_handler : public handler {
|
||||
public:
|
||||
virtual void get_defaults(obs_data_t* settings, AVCodec* codec,
|
||||
AVCodecContext* context) override;
|
||||
|
||||
virtual void get_properties(obs_properties_t* props, AVCodec* codec,
|
||||
AVCodecContext* context) override;
|
||||
|
||||
virtual void update(obs_data_t* settings, AVCodec* codec, AVCodecContext* context) override;
|
||||
|
||||
private:
|
||||
void get_encoder_properties(obs_properties_t* props, AVCodec* codec);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, AVCodec* codec, AVCodecContext* context);
|
||||
};
|
||||
} // namespace ui
|
||||
} // namespace obsffmpeg
|
||||
@@ -0,0 +1,665 @@
|
||||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (C) 2018 - 2019 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 "nvenc_shared.hpp"
|
||||
#include "codecs/hevc.hpp"
|
||||
#include "plugin.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <obs-module.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include <libavutil/opt.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
#define P_PRESET "NVENC.Preset"
|
||||
#define P_PRESET_(x) P_PRESET "." D_VSTR(x)
|
||||
|
||||
#define P_RATECONTROL "NVENC.RateControl"
|
||||
#define P_RATECONTROL_MODE P_RATECONTROL ".Mode"
|
||||
#define P_RATECONTROL_MODE_(x) P_RATECONTROL_MODE "." D_VSTR(x)
|
||||
#define P_RATECONTROL_TWOPASS P_RATECONTROL ".TwoPass"
|
||||
#define P_RATECONTROL_LOOKAHEAD P_RATECONTROL ".LookAhead"
|
||||
#define P_RATECONTROL_ADAPTIVEI P_RATECONTROL ".AdaptiveI"
|
||||
#define P_RATECONTROL_ADAPTIVEB P_RATECONTROL ".AdaptiveB"
|
||||
|
||||
#define P_RATECONTROL_BITRATE P_RATECONTROL ".Bitrate"
|
||||
#define P_RATECONTROL_BITRATE_TARGET P_RATECONTROL_BITRATE ".Target"
|
||||
#define P_RATECONTROL_BITRATE_MAXIMUM P_RATECONTROL_BITRATE ".Maximum"
|
||||
|
||||
#define P_RATECONTROL_QUALITY P_RATECONTROL ".Quality"
|
||||
#define P_RATECONTROL_QUALITY_MINIMUM P_RATECONTROL_QUALITY ".Minimum"
|
||||
#define P_RATECONTROL_QUALITY_MAXIMUM P_RATECONTROL_QUALITY ".Maximum"
|
||||
|
||||
#define P_AQ "NVENC.AQ"
|
||||
#define P_AQ_SPATIAL P_AQ ".Spatial"
|
||||
#define P_AQ_TEMPORAL P_AQ ".Temporal"
|
||||
#define P_AQ_STRENGTH P_AQ ".Strength"
|
||||
|
||||
#define P_OTHER "NVENC.Other"
|
||||
#define P_OTHER_BFRAMES P_OTHER ".BFrames"
|
||||
#define P_OTHER_BFRAME_REFERENCEMODE P_OTHER ".BFrameReferenceMode"
|
||||
#define P_OTHER_ZEROLATENCY P_OTHER ".ZeroLatency"
|
||||
#define P_OTHER_WEIGHTED_PREDICTION P_OTHER ".WeightedPrediction"
|
||||
#define P_OTHER_NONREFERENCE_PFRAMES P_OTHER ".NonReferencePFrames"
|
||||
|
||||
using namespace obsffmpeg::nvenc;
|
||||
|
||||
std::map<preset, std::string> obsffmpeg::nvenc::presets{
|
||||
{preset::DEFAULT, P_PRESET_(Default)},
|
||||
{preset::SLOW, P_PRESET_(Slow)},
|
||||
{preset::MEDIUM, P_PRESET_(Medium)},
|
||||
{preset::FAST, P_PRESET_(Fast)},
|
||||
{preset::HIGH_PERFORMANCE, P_PRESET_(HighPerformance)},
|
||||
{preset::HIGH_QUALITY, P_PRESET_(HighQuality)},
|
||||
{preset::BLURAYDISC, P_PRESET_(BluRayDisc)},
|
||||
{preset::LOW_LATENCY, P_PRESET_(LowLatency)},
|
||||
{preset::LOW_LATENCY_HIGH_PERFORMANCE, P_PRESET_(LowLatencyHighPerformance)},
|
||||
{preset::LOW_LATENCY_HIGH_QUALITY, P_PRESET_(LowLatencyHighQuality)},
|
||||
{preset::LOSSLESS, P_PRESET_(Lossless)},
|
||||
{preset::LOSSLESS_HIGH_PERFORMANCE, P_PRESET_(LosslessHighPerformance)},
|
||||
};
|
||||
|
||||
std::map<preset, std::string> obsffmpeg::nvenc::preset_to_opt{
|
||||
{preset::DEFAULT, "default"},
|
||||
{preset::SLOW, "slow"},
|
||||
{preset::MEDIUM, "medium"},
|
||||
{preset::FAST, "fast"},
|
||||
{preset::HIGH_PERFORMANCE, "hp"},
|
||||
{preset::HIGH_QUALITY, "hq"},
|
||||
{preset::BLURAYDISC, "bd"},
|
||||
{preset::LOW_LATENCY, "ll"},
|
||||
{preset::LOW_LATENCY_HIGH_PERFORMANCE, "llhp"},
|
||||
{preset::LOW_LATENCY_HIGH_QUALITY, "llhq"},
|
||||
{preset::LOSSLESS, "lossless"},
|
||||
{preset::LOSSLESS_HIGH_PERFORMANCE, "losslesshp"},
|
||||
};
|
||||
|
||||
std::map<ratecontrolmode, std::string> obsffmpeg::nvenc::ratecontrolmodes{
|
||||
{ratecontrolmode::CQP, P_RATECONTROL_MODE_(CQP)},
|
||||
{ratecontrolmode::VBR, P_RATECONTROL_MODE_(VBR)},
|
||||
{ratecontrolmode::VBR_HQ, P_RATECONTROL_MODE_(VBR_HQ)},
|
||||
{ratecontrolmode::CBR, P_RATECONTROL_MODE_(CBR)},
|
||||
{ratecontrolmode::CBR_HQ, P_RATECONTROL_MODE_(CBR_HQ)},
|
||||
{ratecontrolmode::CBR_LD_HQ, P_RATECONTROL_MODE_(CBR_LD_HQ)},
|
||||
};
|
||||
|
||||
std::map<ratecontrolmode, std::string> obsffmpeg::nvenc::ratecontrolmode_to_opt{
|
||||
{ratecontrolmode::CQP, "const_qp"}, {ratecontrolmode::VBR, "vbr"}, {ratecontrolmode::VBR_HQ, "vbr_hq"},
|
||||
{ratecontrolmode::CBR, "cbr"}, {ratecontrolmode::CBR_HQ, "cbr_hq"}, {ratecontrolmode::CBR_LD_HQ, "cbr_ld_hq"},
|
||||
};
|
||||
|
||||
std::map<b_ref_mode, std::string> obsffmpeg::nvenc::b_ref_modes{
|
||||
{b_ref_mode::DISABLED, G_STATE_DISABLED},
|
||||
{b_ref_mode::EACH, P_OTHER_BFRAME_REFERENCEMODE ".Each"},
|
||||
{b_ref_mode::MIDDLE, P_OTHER_BFRAME_REFERENCEMODE ".Middle"},
|
||||
};
|
||||
|
||||
std::map<b_ref_mode, std::string> obsffmpeg::nvenc::b_ref_mode_to_opt{
|
||||
{b_ref_mode::DISABLED, "disabled"},
|
||||
{b_ref_mode::EACH, "each"},
|
||||
{b_ref_mode::MIDDLE, "middle"},
|
||||
};
|
||||
|
||||
void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, AVCodec*, AVCodecContext*)
|
||||
{
|
||||
obs_data_set_default_int(settings, P_PRESET, static_cast<int64_t>(preset::DEFAULT));
|
||||
|
||||
obs_data_set_default_int(settings, P_RATECONTROL_MODE, static_cast<int64_t>(ratecontrolmode::CBR_HQ));
|
||||
obs_data_set_default_int(settings, P_RATECONTROL_TWOPASS, -1);
|
||||
obs_data_set_default_int(settings, P_RATECONTROL_LOOKAHEAD, 0);
|
||||
obs_data_set_default_bool(settings, P_RATECONTROL_ADAPTIVEI, true);
|
||||
obs_data_set_default_bool(settings, P_RATECONTROL_ADAPTIVEB, true);
|
||||
|
||||
obs_data_set_default_int(settings, P_RATECONTROL_BITRATE_TARGET, 6000);
|
||||
obs_data_set_default_int(settings, P_RATECONTROL_BITRATE_MAXIMUM, 6000);
|
||||
obs_data_set_default_int(settings, G_RATECONTROL_BUFFERSIZE, 12000);
|
||||
|
||||
obs_data_set_default_int(settings, P_RATECONTROL_QUALITY_MINIMUM, 51);
|
||||
obs_data_set_default_int(settings, P_RATECONTROL_QUALITY_MAXIMUM, -1);
|
||||
|
||||
obs_data_set_default_int(settings, G_RATECONTROL_QP_I, 21);
|
||||
obs_data_set_default_int(settings, G_RATECONTROL_QP_P, 21);
|
||||
obs_data_set_default_int(settings, G_RATECONTROL_QP_B, 21);
|
||||
obs_data_set_default_int(settings, G_RATECONTROL_QP_I_INITIAL, -1);
|
||||
obs_data_set_default_int(settings, G_RATECONTROL_QP_P_INITIAL, -1);
|
||||
obs_data_set_default_int(settings, G_RATECONTROL_QP_B_INITIAL, -1);
|
||||
|
||||
obs_data_set_default_int(settings, G_KEYFRAMES_INTERVALTYPE, 0);
|
||||
obs_data_set_default_double(settings, G_KEYFRAMES_INTERVAL_SECONDS, 2.0);
|
||||
obs_data_set_default_int(settings, G_KEYFRAMES_INTERVAL_FRAMES, 300);
|
||||
|
||||
obs_data_set_default_bool(settings, P_AQ_SPATIAL, true);
|
||||
obs_data_set_default_int(settings, P_AQ_STRENGTH, 8);
|
||||
obs_data_set_default_bool(settings, P_AQ_TEMPORAL, true);
|
||||
|
||||
obs_data_set_default_int(settings, P_OTHER_BFRAMES, 2);
|
||||
obs_data_set_default_int(settings, P_OTHER_BFRAME_REFERENCEMODE, static_cast<int64_t>(b_ref_mode::DISABLED));
|
||||
obs_data_set_default_bool(settings, P_OTHER_ZEROLATENCY, false);
|
||||
obs_data_set_default_bool(settings, P_OTHER_WEIGHTED_PREDICTION, false);
|
||||
obs_data_set_default_bool(settings, P_OTHER_NONREFERENCE_PFRAMES, false);
|
||||
}
|
||||
|
||||
static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_data_t* settings)
|
||||
{
|
||||
using namespace obsffmpeg::nvenc;
|
||||
|
||||
bool have_bitrate = false;
|
||||
bool have_bitrate_max = false;
|
||||
bool have_quality = false;
|
||||
bool have_qp = false;
|
||||
bool have_qp_init = false;
|
||||
|
||||
ratecontrolmode rc = static_cast<ratecontrolmode>(obs_data_get_int(settings, P_RATECONTROL_MODE));
|
||||
switch (rc) {
|
||||
case ratecontrolmode::CQP:
|
||||
have_qp = true;
|
||||
break;
|
||||
case ratecontrolmode::CBR:
|
||||
case ratecontrolmode::CBR_HQ:
|
||||
case ratecontrolmode::CBR_LD_HQ:
|
||||
have_bitrate = true;
|
||||
break;
|
||||
case ratecontrolmode::VBR:
|
||||
case ratecontrolmode::VBR_HQ:
|
||||
have_bitrate = true;
|
||||
have_bitrate_max = true;
|
||||
have_quality = true;
|
||||
have_qp_init = true;
|
||||
break;
|
||||
}
|
||||
|
||||
obs_property_set_visible(obs_properties_get(props, P_RATECONTROL_BITRATE), have_bitrate || have_bitrate_max);
|
||||
obs_property_set_visible(obs_properties_get(props, P_RATECONTROL_BITRATE_TARGET), have_bitrate);
|
||||
obs_property_set_visible(obs_properties_get(props, P_RATECONTROL_BITRATE_MAXIMUM), have_bitrate_max);
|
||||
obs_property_set_visible(obs_properties_get(props, G_RATECONTROL_BUFFERSIZE), have_bitrate || have_bitrate_max);
|
||||
|
||||
obs_property_set_visible(obs_properties_get(props, P_RATECONTROL_QUALITY), have_quality);
|
||||
obs_property_set_visible(obs_properties_get(props, P_RATECONTROL_QUALITY_MINIMUM), have_quality);
|
||||
obs_property_set_visible(obs_properties_get(props, P_RATECONTROL_QUALITY_MAXIMUM), have_quality);
|
||||
|
||||
obs_property_set_visible(obs_properties_get(props, G_RATECONTROL_QP_I), have_qp);
|
||||
obs_property_set_visible(obs_properties_get(props, G_RATECONTROL_QP_P), have_qp);
|
||||
obs_property_set_visible(obs_properties_get(props, G_RATECONTROL_QP_B), have_qp);
|
||||
obs_property_set_visible(obs_properties_get(props, G_RATECONTROL_QP_I_INITIAL), have_qp_init);
|
||||
obs_property_set_visible(obs_properties_get(props, G_RATECONTROL_QP_P_INITIAL), have_qp_init);
|
||||
obs_property_set_visible(obs_properties_get(props, G_RATECONTROL_QP_B_INITIAL), have_qp_init);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool modified_quality(obs_properties_t* props, obs_property_t*, obs_data_t* settings)
|
||||
{
|
||||
bool enabled = obs_data_get_bool(settings, P_RATECONTROL_QUALITY);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_QUALITY_MINIMUM), enabled);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_QUALITY_MAXIMUM), enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool modified_keyframes(obs_properties_t* props, obs_property_t*, obs_data_t* settings)
|
||||
{
|
||||
bool is_seconds = obs_data_get_int(settings, G_KEYFRAMES_INTERVALTYPE) == 0;
|
||||
obs_property_set_visible(obs_properties_get(props, G_KEYFRAMES_INTERVAL_FRAMES), !is_seconds);
|
||||
obs_property_set_visible(obs_properties_get(props, G_KEYFRAMES_INTERVAL_SECONDS), is_seconds);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool modified_aq(obs_properties_t* props, obs_property_t*, obs_data_t* settings)
|
||||
{
|
||||
bool spatial_aq = obs_data_get_bool(settings, P_AQ_SPATIAL);
|
||||
obs_property_set_visible(obs_properties_get(props, P_AQ_STRENGTH), spatial_aq);
|
||||
return true;
|
||||
}
|
||||
|
||||
void obsffmpeg::nvenc::get_properties_pre(obs_properties_t* props, AVCodec*)
|
||||
{
|
||||
{
|
||||
auto p = obs_properties_add_list(props, P_PRESET, TRANSLATE(P_PRESET), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_PRESET)));
|
||||
for (auto kv : presets) {
|
||||
obs_property_list_add_int(p, TRANSLATE(kv.second.c_str()), static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, AVCodec* codec)
|
||||
{
|
||||
{ // Rate Control
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, P_RATECONTROL, TRANSLATE(P_RATECONTROL), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, P_RATECONTROL_MODE, TRANSLATE(P_RATECONTROL_MODE),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_MODE)));
|
||||
obs_property_set_modified_callback(p, modified_ratecontrol);
|
||||
for (auto kv : ratecontrolmodes) {
|
||||
obs_property_list_add_int(p, TRANSLATE(kv.second.c_str()),
|
||||
static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, P_RATECONTROL_TWOPASS, TRANSLATE(P_RATECONTROL_TWOPASS),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_TWOPASS)));
|
||||
obs_property_list_add_int(p, TRANSLATE(G_STATE_DEFAULT), -1);
|
||||
obs_property_list_add_int(p, TRANSLATE(G_STATE_DISABLED), 0);
|
||||
obs_property_list_add_int(p, TRANSLATE(G_STATE_ENABLED), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, P_RATECONTROL_LOOKAHEAD,
|
||||
TRANSLATE(P_RATECONTROL_LOOKAHEAD), 0, 60, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_LOOKAHEAD)));
|
||||
obs_property_int_set_suffix(p, " frames");
|
||||
}
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_bool(grp, P_RATECONTROL_ADAPTIVEI, TRANSLATE(P_RATECONTROL_ADAPTIVEI));
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_ADAPTIVEI)));
|
||||
}
|
||||
if (strcmp(codec->name, "h264_nvenc") == 0) {
|
||||
auto p =
|
||||
obs_properties_add_bool(grp, P_RATECONTROL_ADAPTIVEB, TRANSLATE(P_RATECONTROL_ADAPTIVEB));
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_ADAPTIVEB)));
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, G_RATECONTROL_QP_I, TRANSLATE(G_RATECONTROL_QP_I),
|
||||
0, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_RATECONTROL_QP_I)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, G_RATECONTROL_QP_I_INITIAL,
|
||||
TRANSLATE(G_RATECONTROL_QP_I_INITIAL), -1, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_RATECONTROL_QP_I_INITIAL)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, G_RATECONTROL_QP_P, TRANSLATE(G_RATECONTROL_QP_P),
|
||||
0, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_RATECONTROL_QP_P)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, G_RATECONTROL_QP_P_INITIAL,
|
||||
TRANSLATE(G_RATECONTROL_QP_P_INITIAL), -1, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_RATECONTROL_QP_P_INITIAL)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, G_RATECONTROL_QP_B, TRANSLATE(G_RATECONTROL_QP_B),
|
||||
0, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_RATECONTROL_QP_B)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, G_RATECONTROL_QP_B_INITIAL,
|
||||
TRANSLATE(G_RATECONTROL_QP_B_INITIAL), -1, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_RATECONTROL_QP_B_INITIAL)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, P_RATECONTROL_BITRATE, TRANSLATE(P_RATECONTROL_BITRATE),
|
||||
OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int(grp, P_RATECONTROL_BITRATE_TARGET,
|
||||
TRANSLATE(P_RATECONTROL_BITRATE_TARGET), 1,
|
||||
std::numeric_limits<int32_t>::max(), 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_BITRATE_TARGET)));
|
||||
obs_property_int_set_suffix(p, " kbit/s");
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int(grp, P_RATECONTROL_BITRATE_MAXIMUM,
|
||||
TRANSLATE(P_RATECONTROL_BITRATE_MAXIMUM), 0,
|
||||
std::numeric_limits<int32_t>::max(), 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_BITRATE_MAXIMUM)));
|
||||
obs_property_int_set_suffix(p, " kbit/s");
|
||||
}
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_int(grp, G_RATECONTROL_BUFFERSIZE, TRANSLATE(G_RATECONTROL_BUFFERSIZE),
|
||||
0, std::numeric_limits<int32_t>::max(), 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_RATECONTROL_BUFFERSIZE)));
|
||||
obs_property_int_set_suffix(p, " kbit");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
auto p = obs_properties_add_group(props, P_RATECONTROL_QUALITY,
|
||||
TRANSLATE(P_RATECONTROL_QUALITY), OBS_GROUP_CHECKABLE, grp);
|
||||
obs_property_set_modified_callback(p, modified_quality);
|
||||
} else {
|
||||
auto p =
|
||||
obs_properties_add_bool(props, P_RATECONTROL_QUALITY, TRANSLATE(P_RATECONTROL_QUALITY));
|
||||
obs_property_set_modified_callback(p, modified_quality);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, P_RATECONTROL_QUALITY_MINIMUM,
|
||||
TRANSLATE(P_RATECONTROL_QUALITY_MINIMUM), 0, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_QUALITY_MINIMUM)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, P_RATECONTROL_QUALITY_MAXIMUM,
|
||||
TRANSLATE(P_RATECONTROL_QUALITY_MAXIMUM), -1, 51, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_RATECONTROL_QUALITY_MAXIMUM)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, G_KEYFRAMES, TRANSLATE(G_KEYFRAMES), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_list(grp, G_KEYFRAMES_INTERVALTYPE, TRANSLATE(G_KEYFRAMES_INTERVALTYPE),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_KEYFRAMES_INTERVALTYPE)));
|
||||
obs_property_set_modified_callback(p, modified_keyframes);
|
||||
obs_property_list_add_int(p, TRANSLATE(G_KEYFRAMES_INTERVALTYPE_(Seconds)), 0);
|
||||
obs_property_list_add_int(p, TRANSLATE(G_KEYFRAMES_INTERVALTYPE_(Frames)), 1);
|
||||
}
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_float(grp, G_KEYFRAMES_INTERVAL_SECONDS, TRANSLATE(G_KEYFRAMES_INTERVAL),
|
||||
0.00, std::numeric_limits<int16_t>::max(), 0.01);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_KEYFRAMES_INTERVAL)));
|
||||
obs_property_float_set_suffix(p, " seconds");
|
||||
}
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_int(grp, G_KEYFRAMES_INTERVAL_FRAMES, TRANSLATE(G_KEYFRAMES_INTERVAL), 0,
|
||||
std::numeric_limits<int32_t>::max(), 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(G_KEYFRAMES_INTERVAL)));
|
||||
obs_property_int_set_suffix(p, " frames");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, P_AQ, TRANSLATE(P_AQ), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_bool(grp, P_AQ_SPATIAL, TRANSLATE(P_AQ_SPATIAL));
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_AQ_SPATIAL)));
|
||||
obs_property_set_modified_callback(p, modified_aq);
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_int_slider(grp, P_AQ_STRENGTH, TRANSLATE(P_AQ_STRENGTH), 1, 15, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_AQ_STRENGTH)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_bool(grp, P_AQ_TEMPORAL, TRANSLATE(P_AQ_TEMPORAL));
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_AQ_TEMPORAL)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
obs_properties_t* grp = props;
|
||||
if (!obsffmpeg::are_property_groups_broken()) {
|
||||
grp = obs_properties_create();
|
||||
obs_properties_add_group(props, P_OTHER, TRANSLATE(P_OTHER), OBS_GROUP_NORMAL, grp);
|
||||
}
|
||||
|
||||
{
|
||||
auto p =
|
||||
obs_properties_add_int_slider(grp, P_OTHER_BFRAMES, TRANSLATE(P_OTHER_BFRAMES), 0, 4, 1);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_OTHER_BFRAMES)));
|
||||
obs_property_int_set_suffix(p, " frames");
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_list(grp, P_OTHER_BFRAME_REFERENCEMODE,
|
||||
TRANSLATE(P_OTHER_BFRAME_REFERENCEMODE), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_OTHER_BFRAME_REFERENCEMODE)));
|
||||
for (auto kv : b_ref_modes) {
|
||||
obs_property_list_add_int(p, TRANSLATE(kv.second.c_str()),
|
||||
static_cast<int64_t>(kv.first));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_bool(grp, P_OTHER_ZEROLATENCY, TRANSLATE(P_OTHER_ZEROLATENCY));
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_OTHER_ZEROLATENCY)));
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_bool(grp, P_OTHER_WEIGHTED_PREDICTION,
|
||||
TRANSLATE(P_OTHER_WEIGHTED_PREDICTION));
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_OTHER_WEIGHTED_PREDICTION)));
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_bool(grp, P_OTHER_NONREFERENCE_PFRAMES,
|
||||
TRANSLATE(P_OTHER_NONREFERENCE_PFRAMES));
|
||||
obs_property_set_long_description(p, TRANSLATE(DESC(P_OTHER_NONREFERENCE_PFRAMES)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obsffmpeg::nvenc::get_runtime_properties(obs_properties_t* props, AVCodec*, AVCodecContext*)
|
||||
{
|
||||
obs_property_set_enabled(obs_properties_get(props, P_PRESET), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_MODE), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_TWOPASS), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_LOOKAHEAD), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_ADAPTIVEI), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_ADAPTIVEB), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_BITRATE), true);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_BITRATE_TARGET), true);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_BITRATE_MAXIMUM), true);
|
||||
obs_property_set_enabled(obs_properties_get(props, G_RATECONTROL_BUFFERSIZE), true);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_QUALITY), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_QUALITY_MINIMUM), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_RATECONTROL_QUALITY_MAXIMUM), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, G_KEYFRAMES), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, G_KEYFRAMES_INTERVALTYPE), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, G_KEYFRAMES_INTERVAL_SECONDS), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, G_KEYFRAMES_INTERVAL_FRAMES), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_AQ), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_AQ_SPATIAL), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_AQ_STRENGTH), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_AQ_TEMPORAL), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_OTHER), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_OTHER_BFRAMES), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_OTHER_BFRAME_REFERENCEMODE), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_OTHER_ZEROLATENCY), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_OTHER_WEIGHTED_PREDICTION), false);
|
||||
obs_property_set_enabled(obs_properties_get(props, P_OTHER_NONREFERENCE_PFRAMES), false);
|
||||
}
|
||||
|
||||
void obsffmpeg::nvenc::update(obs_data_t* settings, AVCodec* codec, AVCodecContext* context)
|
||||
{
|
||||
{
|
||||
preset c_preset = static_cast<preset>(obs_data_get_int(settings, P_PRESET));
|
||||
auto found = preset_to_opt.find(c_preset);
|
||||
if (found != preset_to_opt.end()) {
|
||||
av_opt_set(context->priv_data, "preset", found->second.c_str(), 0);
|
||||
} else {
|
||||
av_opt_set(context->priv_data, "preset", nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Rate Control
|
||||
bool have_bitrate = false;
|
||||
bool have_bitrate_max = false;
|
||||
bool have_quality_min = false;
|
||||
bool have_quality_max = false;
|
||||
bool have_qp = false;
|
||||
bool have_qp_init = false;
|
||||
|
||||
ratecontrolmode rc = static_cast<ratecontrolmode>(obs_data_get_int(settings, P_RATECONTROL_MODE));
|
||||
auto rcopt = nvenc::ratecontrolmode_to_opt.find(rc);
|
||||
if (rcopt != nvenc::ratecontrolmode_to_opt.end()) {
|
||||
av_opt_set(context->priv_data, "rc", rcopt->second.c_str(), 0);
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case ratecontrolmode::CQP:
|
||||
have_qp = true;
|
||||
break;
|
||||
case ratecontrolmode::CBR:
|
||||
case ratecontrolmode::CBR_HQ:
|
||||
case ratecontrolmode::CBR_LD_HQ:
|
||||
have_bitrate = true;
|
||||
av_opt_set_int(context->priv_data, "cbr", 1, 0);
|
||||
break;
|
||||
case ratecontrolmode::VBR:
|
||||
case ratecontrolmode::VBR_HQ:
|
||||
have_bitrate_max = true;
|
||||
have_bitrate = true;
|
||||
have_quality_min = true;
|
||||
have_quality_max = true;
|
||||
have_qp_init = true;
|
||||
break;
|
||||
}
|
||||
|
||||
int tp = static_cast<int>(obs_data_get_int(settings, P_RATECONTROL_TWOPASS));
|
||||
if (tp >= 0) {
|
||||
av_opt_set_int(context->priv_data, "2pass", tp ? 1 : 0, 0);
|
||||
}
|
||||
|
||||
int la = static_cast<int>(obs_data_get_int(settings, P_RATECONTROL_LOOKAHEAD));
|
||||
av_opt_set_int(context->priv_data, "lookahead", la, 0);
|
||||
if (la > 0) {
|
||||
bool adapt_i = obs_data_get_bool(settings, P_RATECONTROL_ADAPTIVEI);
|
||||
av_opt_set_int(context->priv_data, "no-scenecut", !adapt_i ? 1 : 0, 0);
|
||||
|
||||
if (strcmp(codec->name, "h264_nvenc")) {
|
||||
bool adapt_b = obs_data_get_bool(settings, P_RATECONTROL_ADAPTIVEB);
|
||||
av_opt_set_int(context->priv_data, "b_adapt", adapt_b ? 1 : 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (have_bitrate)
|
||||
context->bit_rate =
|
||||
static_cast<int>(obs_data_get_int(settings, P_RATECONTROL_BITRATE_TARGET) * 1000);
|
||||
if (have_bitrate_max)
|
||||
context->rc_max_rate =
|
||||
static_cast<int>(obs_data_get_int(settings, P_RATECONTROL_BITRATE_MAXIMUM) * 1000);
|
||||
if (have_bitrate || have_bitrate_max)
|
||||
context->rc_buffer_size =
|
||||
static_cast<int>(obs_data_get_int(settings, G_RATECONTROL_BUFFERSIZE) * 1000);
|
||||
|
||||
if (have_quality_min && obs_data_get_bool(settings, P_RATECONTROL_QUALITY)) {
|
||||
int qmin = static_cast<int>(obs_data_get_int(settings, P_RATECONTROL_QUALITY_MINIMUM));
|
||||
context->qmin = qmin;
|
||||
if ((qmin >= 0) && (have_quality_max)) {
|
||||
context->qmax =
|
||||
static_cast<int>(obs_data_get_int(settings, P_RATECONTROL_QUALITY_MAXIMUM));
|
||||
}
|
||||
}
|
||||
|
||||
if (have_qp) {
|
||||
av_opt_set_int(context->priv_data, "init_qpI",
|
||||
static_cast<int>(obs_data_get_int(settings, G_RATECONTROL_QP_I)), 0);
|
||||
av_opt_set_int(context->priv_data, "init_qpP",
|
||||
static_cast<int>(obs_data_get_int(settings, G_RATECONTROL_QP_P)), 0);
|
||||
av_opt_set_int(context->priv_data, "init_qpB",
|
||||
static_cast<int>(obs_data_get_int(settings, G_RATECONTROL_QP_B)), 0);
|
||||
}
|
||||
if (have_qp_init) {
|
||||
av_opt_set_int(context->priv_data, "init_qpI",
|
||||
obs_data_get_int(settings, G_RATECONTROL_QP_I_INITIAL), 0);
|
||||
av_opt_set_int(context->priv_data, "init_qpP",
|
||||
obs_data_get_int(settings, G_RATECONTROL_QP_P_INITIAL), 0);
|
||||
av_opt_set_int(context->priv_data, "init_qpB",
|
||||
obs_data_get_int(settings, G_RATECONTROL_QP_B_INITIAL), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Key Frames
|
||||
obs_video_info ovi;
|
||||
if (!obs_get_video_info(&ovi)) {
|
||||
throw std::runtime_error("no video info");
|
||||
}
|
||||
|
||||
int64_t kf_type = obs_data_get_int(settings, G_KEYFRAMES_INTERVALTYPE);
|
||||
bool is_seconds = (kf_type == 0);
|
||||
|
||||
if (is_seconds) {
|
||||
context->gop_size = static_cast<int>(obs_data_get_double(settings, G_KEYFRAMES_INTERVAL_SECONDS)
|
||||
* (ovi.fps_num / ovi.fps_den));
|
||||
} else {
|
||||
context->gop_size = static_cast<int>(obs_data_get_int(settings, G_KEYFRAMES_INTERVAL_FRAMES));
|
||||
}
|
||||
context->keyint_min = context->gop_size;
|
||||
}
|
||||
|
||||
{ // AQ
|
||||
bool saq = obs_data_get_bool(settings, P_AQ_SPATIAL);
|
||||
int saqs = static_cast<int>(obs_data_get_int(settings, P_AQ_STRENGTH));
|
||||
bool taq = obs_data_get_bool(settings, P_AQ_TEMPORAL);
|
||||
|
||||
if (strcmp(codec->name, "h264_nvenc")) {
|
||||
av_opt_set_int(context->priv_data, "spatial-aq", saq ? 1 : 0, 0);
|
||||
av_opt_set_int(context->priv_data, "temporal-aq", taq ? 1 : 0, 0);
|
||||
} else {
|
||||
av_opt_set_int(context->priv_data, "spatial_aq", saq ? 1 : 0, 0);
|
||||
av_opt_set_int(context->priv_data, "temporal_aq", taq ? 1 : 0, 0);
|
||||
}
|
||||
av_opt_set_int(context->priv_data, "aq-strength", saqs, 0);
|
||||
}
|
||||
|
||||
{ // Other
|
||||
bool zl = obs_data_get_bool(settings, P_OTHER_ZEROLATENCY);
|
||||
bool wp = obs_data_get_bool(settings, P_OTHER_WEIGHTED_PREDICTION);
|
||||
bool nrp = obs_data_get_bool(settings, P_OTHER_NONREFERENCE_PFRAMES);
|
||||
|
||||
context->max_b_frames = static_cast<int>(obs_data_get_int(settings, P_OTHER_BFRAMES));
|
||||
|
||||
av_opt_set_int(context->priv_data, "zerolatency", zl ? 1 : 0, 0);
|
||||
av_opt_set_int(context->priv_data, "nonref_p", nrp ? 1 : 0, 0);
|
||||
|
||||
if ((context->max_b_frames != 0) && wp) {
|
||||
PLOG_WARNING(
|
||||
"Automatically disabled weighted prediction due to being incompatible with B-Frames.");
|
||||
} else {
|
||||
av_opt_set_int(context->priv_data, "weighted_pred", wp ? 1 : 0, 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto found = b_ref_mode_to_opt.find(
|
||||
static_cast<b_ref_mode>(obs_data_get_int(settings, P_OTHER_BFRAME_REFERENCEMODE)));
|
||||
if (found != b_ref_mode_to_opt.end()) {
|
||||
av_opt_set(context->priv_data, "b_ref_mode", found->second.c_str(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// FFMPEG Video Encoder Integration for OBS Studio
|
||||
// Copyright (C) 2018 - 2019 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 <map>
|
||||
#include "utility.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <obs-properties.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#include <libavcodec/avcodec.h>
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
namespace obsffmpeg {
|
||||
namespace nvenc {
|
||||
enum class preset : int64_t {
|
||||
DEFAULT,
|
||||
SLOW,
|
||||
MEDIUM,
|
||||
FAST,
|
||||
HIGH_PERFORMANCE,
|
||||
HIGH_QUALITY,
|
||||
BLURAYDISC,
|
||||
LOW_LATENCY,
|
||||
LOW_LATENCY_HIGH_PERFORMANCE,
|
||||
LOW_LATENCY_HIGH_QUALITY,
|
||||
LOSSLESS,
|
||||
LOSSLESS_HIGH_PERFORMANCE,
|
||||
};
|
||||
|
||||
enum class ratecontrolmode : int64_t {
|
||||
CQP,
|
||||
VBR,
|
||||
VBR_HQ,
|
||||
CBR,
|
||||
CBR_HQ,
|
||||
CBR_LD_HQ,
|
||||
};
|
||||
|
||||
enum class b_ref_mode : int64_t {
|
||||
DISABLED,
|
||||
EACH,
|
||||
MIDDLE,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
extern std::map<b_ref_mode, std::string> b_ref_modes;
|
||||
|
||||
extern std::map<b_ref_mode, std::string> b_ref_mode_to_opt;
|
||||
|
||||
void get_defaults(obs_data_t* settings, AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void get_properties_pre(obs_properties_t* props, AVCodec* codec);
|
||||
|
||||
void get_properties_post(obs_properties_t* props, AVCodec* codec);
|
||||
|
||||
void get_runtime_properties(obs_properties_t* props, AVCodec* codec, AVCodecContext* context);
|
||||
|
||||
void update(obs_data_t* settings, AVCodec* codec, AVCodecContext* context);
|
||||
} // namespace nvenc
|
||||
} // namespace obsffmpeg
|
||||
@@ -19,6 +19,11 @@
|
||||
|
||||
#include "version.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <obs-config.h>
|
||||
#include <obs.h>
|
||||
}
|
||||
|
||||
// Logging
|
||||
#define PLOG(level, ...) blog(level, "[obs-ffmpeg-encoder] " __VA_ARGS__);
|
||||
#define PLOG_ERROR(...) PLOG(LOG_ERROR, __VA_ARGS__)
|
||||
@@ -71,3 +76,11 @@
|
||||
static void f(void) __attribute__((constructor)); \
|
||||
static void f(void)
|
||||
#endif
|
||||
|
||||
// Helpers
|
||||
namespace obsffmpeg {
|
||||
bool inline are_property_groups_broken()
|
||||
{
|
||||
return obs_get_version() < MAKE_SEMANTIC_VERSION(24, 0, 0);
|
||||
}
|
||||
} // namespace obsffmpeg
|
||||
|
||||
Reference in New Issue
Block a user