58 Commits

Author SHA1 Message Date
Michael Fabian 'Xaymar' Dirks 3a75b9f963 cmake: Version 0.4.0 2019-11-16 23:46:52 +01:00
Michael Fabian 'Xaymar' Dirks 815152d024 encoder: Actually fix parsing this time 2019-11-16 23:46:20 +01:00
Michael Fabian 'Xaymar' Dirks e4474c29c4 ui/nvenc: Improve and fix some options and logging
Some of the options shown to the user were never actually being applied, which resulted in encoding that looked worse than it could have. With this these options are now applied and users may experience a sudden increase or decrease in quality if they had these options changed.

In addition to that, some options now use a triple state field, which allows them to also have a default/middle state instead of being On or Off.

Furthermore, log output is now read from the actual AVCodecContext, which contains the actual values used in the encoding, instead of relying on the OBS settings to be the actual values.
2019-11-16 21:44:03 +01:00
Michael Fabian 'Xaymar' Dirks 2a75d5fabd ffmpeg/tools: Add functions for easy logging 2019-11-16 21:19:30 +01:00
Michael Fabian 'Xaymar' Dirks a0bfac9319 encoder: Fix crash because of missing string parameter 2019-11-16 21:19:17 +01:00
Michael Fabian 'Xaymar' Dirks 65dddb5aa8 utility: Add functions to check the state of tristates 2019-11-16 21:18:58 +01:00
Michael Fabian 'Xaymar' Dirks 59e33a132b ui/nvenc: Remove "Encoder" from name
It's already known that this is an encoder.
2019-11-16 13:04:10 +01:00
Michael Fabian 'Xaymar' Dirks be7b2737b4 encoder, ui/handler: Massive Refactor
This refactor is primarily to make the entire interface more unified and capable of more than before.
2019-11-15 17:29:24 +01:00
Michael Fabian 'Xaymar' Dirks 8f20a45ee8 hwapi/d3d11: Remove unused variables 2019-11-15 17:20:37 +01:00
Michael Fabian 'Xaymar' Dirks 300531ad8a ffmpeg/tools: Extra name functions 2019-11-15 13:31:27 +01:00
Michael Fabian 'Xaymar' Dirks c775ae93b7 utility: Add helper for tristate property 2019-11-15 01:12:32 +01:00
Michael Fabian 'Xaymar' Dirks 18c50b3cbb ui/handler: Refactoring 2019-11-13 11:44:40 +01:00
Michael Fabian 'Xaymar' Dirks 04a22a13dc encoder: Fix incorrect command line parsing code 2019-11-12 13:36:02 +01:00
Michael Fabian 'Xaymar' Dirks d8eb38037b encoder: Improve custom options parsing drastically
Splits the parsing into two steps, one for quotes and escaping, the other for actual option parsing. This drastically lowers the chances of messing up, and makes the entire thing much safer than a really complex monolithic loop.
2019-11-12 01:05:29 +01:00
Michael Fabian 'Xaymar' Dirks 81164d0f43 encoder: Cleanup and refactor for stability 2019-11-11 23:24:19 +01:00
Michael Fabian 'Xaymar' Dirks 05d8e74088 encoder: Use ffmpeg::tools::get_error_description 2019-11-11 21:15:56 +01:00
Michael Fabian 'Xaymar' Dirks d233b52e1f ffmpeg/tools: Rewrite ffmpeg::tools::get_error_description 2019-11-11 21:15:38 +01:00
UserNaem e89ef57bda locale: Additional and improved descriptions for options 2019-11-11 20:58:43 +01:00
Cristobal E 2759153b0e encoder: Show proper warning messages for custom options 2019-11-11 20:57:55 +01:00
Cristobal E 629afe3661 encoder: Add field for GPU selection 2019-11-11 20:57:53 +01:00
Michael Fabian 'Xaymar' Dirks 21629f1e13 cmake: Update libOBS to 24.0.3 2019-11-07 22:18:32 +01:00
Michael Fabian 'Xaymar' Dirks 80d104bdeb encoder: Use new graphics lock and create_from_obs method 2019-11-07 22:09:58 +01:00
Michael Fabian 'Xaymar' Dirks ffb348b6c8 hwapi/d3d11: Implement create_from_obs
Allows zero-copy with zero-overhead hardware encoders in OBS Studio.
2019-11-07 22:09:34 +01:00
Michael Fabian 'Xaymar' Dirks b67f51df76 hwapi/base: Create from OBS context 2019-11-07 22:08:46 +01:00
Michael Fabian 'Xaymar' Dirks 24d92e4b92 utility: Managed OBS Graphics Context 2019-11-07 22:08:21 +01:00
Michael Fabian 'Xaymar' Dirks 412c9fc18b locale: Fix description for Custom Settings 2019-11-04 18:40:06 +01:00
Michael Fabian 'Xaymar' Dirks 2184e5bc71 project: Reapply formatting 2019-11-04 18:32:47 +01:00
Michael Fabian 'Xaymar' Dirks ad761834ee encoder: Improve parsing of custom settings
Implements a parsing mechanism similar to that of an FFmpeg on the command line. Instead of separating options by ';' (key=value;key=value) the custom settings now take things as '-key=value -key=value -key="value with space"'.

A partial escaping of characters is also supported, however it does not modify the actual string. Proper support for escaping may land in a future update.

Fixes #5
Related #12
2019-11-04 18:32:36 +01:00
Michael Fabian 'Xaymar' Dirks a0b667c26f encoder: Rename all encoders to fix name collisions
This is a breaking change that will make all previous configuration no longer work.
2019-11-04 15:02:13 +01:00
Michael Fabian 'Xaymar' Dirks 18024aaf12 project: Version 0.3.1
* Replaced AppVeyor with GitHub Actions.
* Fixed rescaling on the output tab not working.
2019-10-31 08:13:42 +01:00
Michael Fabian 'Xaymar' Dirks b2b5cd8fad encoder: Fix width and height to use rescaled resolution
The function video_output_get_info does not contain rescaling information from the output tab, so by replacing it with obs_encoder_get_width/height we can actually use the scaled resolution.
2019-10-31 06:34:58 +01:00
Michael Fabian 'Xaymar' Dirks b6e881b90f ci: Remove AppVeyor scripts 2019-10-31 05:53:34 +01:00
Michael Fabian 'Xaymar' Dirks bd60958b2f ci: Also build InnoSetup installer on Github Actions 2019-10-31 05:53:34 +01:00
Michael Fabian 'Xaymar' Dirks f9ad87a56d ci: Add packaging and artifacts to Github Actions
Github Actions is going to replace AppVeyor in the long term for all release archives, simply because it integrates better with GitHub.
2019-10-31 05:53:34 +01:00
Michael Fabian 'Xaymar' Dirks b07365cdc4 project: Version 0.3.0
* Updated the libOBS dependency to 24.0.0. You will need to use OBS Studio 24.0.0 or newer in order to run the plugin.
* Implemented full hardware encoding for all GPU capable encoders (NVENC H264, NVENC H265). This should be perform identical to the OBS included full hardware encoders.
* Reduced the latency for some encoders to be as low as 1 frame, if settings allow. For NVENC, latency is tied to (B-Frames + 1) and Lookahead Frames, whichever is bigger.
* Further improved performance by throwing even less memory away every frame. Almost all memory is now re-used if possible and only released when the encoding is stopped by any means.
* Apple ProRes encoded files should now be remuxable when stored in Matroska (MKV) and survive at least one remuxing. This bug was already fixed in current master FFmpeg, and thanks for discovering this bug go to FRANKIEonPC.
* All color metadata is now set for encoders that support this, such as NVENC. Video players and editors that support this kind of metadata should see an improvement in color quality, especially with 10-bit or higher output.
* Framerate is now set to be fixed, further improving compatibility with players. It was previously left to be guessed by the video player through the timing information.
* Settings are now output to the log file for easier debugging. Please remember to send a log file with any issue you have with the plugin.
2019-10-19 02:52:23 +02:00
Michael Fabian 'Xaymar' Dirks f21cbe9aba ui/nvenc_shared: Fix lag calculation for rc-lookahead 2019-10-19 02:40:50 +02:00
Michael Fabian 'Xaymar' Dirks 403b43e77b cmake: Also include template files in project generation 2019-10-17 08:17:06 +02:00
Michael Fabian 'Xaymar' Dirks 58d8713369 enocder: Use ffmpeg for pixel format again
Reverts an earlier change as this apparently works now.
2019-10-17 08:16:42 +02:00
Michael Fabian 'Xaymar' Dirks 2f8acc58cf encoder: Separate get_defaults and get_properties for SW/HW encoders 2019-10-04 19:27:45 +02:00
Michael Fabian 'Xaymar' Dirks e4e76dae8f ui/nvenc: Override lag in frames to use Max. B-Frames 2019-10-03 20:10:03 +02:00
Michael Fabian 'Xaymar' Dirks 4cac28a8a3 ui/handler, encoder: Allow overriding lag in frames
The lag in frames is not dictated by the number of threads being used by some encoders. At least for hardware encoders, the expected frame lag in real time encoding is 1 + the number of bframes
2019-10-03 20:09:34 +02:00
Michael Fabian 'Xaymar' Dirks d0dc4be985 encoder: Replace ffmpeg::avframe_queue with integrated implementation 2019-10-03 19:21:54 +02:00
Michael Fabian 'Xaymar' Dirks 4836f9dda6 hwapi/d3d11: Implement new HWAPI code 2019-10-03 19:19:20 +02:00
Michael Fabian 'Xaymar' Dirks 650b397ced hwapi/base: Improve frame allocation method
This allows us to cache existing frames, reducing the CPU and GPU memory load that appears due to constantly recreating frames.
2019-10-03 19:18:44 +02:00
Michael Fabian 'Xaymar' Dirks d3f7b15633 hwapi/base: Add missing #include <memory> 2019-09-29 19:33:51 +02:00
Michael Fabian 'Xaymar' Dirks 545dcd6d50 encoder: Add support for true hardware encoding
This is the last step towards truly efficient encoding on AMD, Nvidia and Intel GPUs. With this we have no software overhead and can directly encode the content that OBS gives us, without going through any intermediate CPU layer. This is effectively what @jp9000 did for the OBS-integrated nvenc, but thanks to FFmpeg it works on all encoders that support D3D11VA acceleration.

With the change, the encoding should now work flawlessly even in very constrained situations (unless OBS itself is being starved of resources). Especially people streaming and recording Ubisoft games will likely see a drastic increase in encoding capability, and thanks to the new options will also be able to get a much higher quality stream and recording with the same hardware.
2019-09-29 19:29:00 +02:00
Michael Fabian 'Xaymar' Dirks 0461b20e1b ui/handler: Allow Codec handlers to select the proper device 2019-09-29 19:16:26 +02:00
Michael Fabian 'Xaymar' Dirks b3a6dbb1b4 hwapi: Add API handlers to deal with some heavy lifting code
Makes our life easier when actually dealing with hardware encoding.
2019-09-29 19:15:45 +02:00
Michael Fabian 'Xaymar' Dirks fe71944199 ui/prores_aw_handler: Workaround for FFmpeg bug with ProRes in Matroska
In current FFmpeg, whenever Matroska with ProRes is demuxed it creates an atom that is just 8 bytes short of the true size necessary.

We can work around this by padding the actual packet by 8 0x00 bytes, which should result in older FFmpeg versions working fine.

An FFmpeg patch is available: http://ffmpeg.org/pipermail/ffmpeg-devel/2019-September/250724.html
2019-09-29 07:27:22 +02:00
Michael Fabian 'Xaymar' Dirks cbd39a8c2a encoder: Cache the UI handler and allow packet processing 2019-09-29 06:58:01 +02:00
Michael Fabian 'Xaymar' Dirks 62eae3827b ui/handler: Add function for packet processing 2019-09-29 06:55:42 +02:00
Michael Fabian 'Xaymar' Dirks 38e7639862 ffmpeg/tools: Actually use the score 2019-09-28 02:10:37 +02:00
Michael Fabian 'Xaymar' Dirks 6bc1cb9c88 ui/nvenc*: Print all settings to the log file 2019-09-28 01:54:28 +02:00
Michael Fabian 'Xaymar' Dirks c63900d575 encoder: Also log custom overrides 2019-09-28 01:48:56 +02:00
Michael Fabian 'Xaymar' Dirks 9efda8af8d ui/prores_aw_handler: Print profile to log 2019-09-27 16:29:01 +02:00
Michael Fabian 'Xaymar' Dirks 0c9764a15c encoder: Use codec name instead of encoder info 2019-09-27 16:28:44 +02:00
Michael Fabian 'Xaymar' Dirks 5c5a235502 ui/handler: Always have a no-op function 2019-09-27 16:16:39 +02:00
Michael Fabian 'Xaymar' Dirks 2ebf90ffd7 encoder, ffmpeg/tools: Fix and improve initialization behavior
Correctly sets all color settings for the context and frames, which should result in better playback in players that support these. Unfortunately it does not fix the bug that VLC and MPC-HC incorrectly assume that the ProRes encoded content is in Partial range, however most editing software does correctly detect it.
2019-09-27 16:16:14 +02:00
33 changed files with 1810 additions and 769 deletions
+24 -7
View File
@@ -3,32 +3,49 @@ name: CI
on: [push, pull_request]
jobs:
build:
windows:
strategy:
matrix:
os: [windows-2016, windows-2019]
include:
- os: windows-2016
generator_32: "Visual Studio 15 2017"
generator_64: "Visual Studio 15 2017 Win64"
generator_64: "Visual Studio 15 2017"
sysversion: "10.0.17763.0"
- os: windows-2019
generator_32:
generator_32: "Visual Studio 16 2019"
generator_64: "Visual Studio 16 2019"
sysversion: "10.0.18362.0"
runs-on: ${{ matrix.os }}
steps:
- name: Clone Repository
- name: "Clone Repository"
uses: actions/checkout@v1
- name: Update Submodules
run: git submodule update --init --force --recursive
- name: Install Node.JS 10.x
uses: actions/setup-node@v1
with:
node-version: 10
- name: Build
- name: Configure & Compile
env:
CMAKE_GENERATOR_32: ${{ matrix.generator_32 }}
CMAKE_GENERATOR_64: ${{ matrix.generator_64 }}
CMAKE_SYSTEM_VERSION: ${{ matrix.sysversion }}
run: node ./ci/builder.js
- name: Package
env:
CMAKE_GENERATOR_32: ${{ matrix.generator_32 }}
CMAKE_GENERATOR_64: ${{ matrix.generator_64 }}
run: |
mkdir build/package
node ./ci/packager.js
- name: "Package Installer (Prereqs)"
run: |
curl "-kL" "https://cdn.xaymar.com/ci/innosetup-6.0.3.exe" "-f" "--retry" "5" "-o" "inno.exe"
.\inno.exe /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART
- name: "Package Installer (Compile)"
run: |
& 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' /Qp ".\build\64\installer.iss"
- name: "Upload Artifacts"
uses: actions/upload-artifact@v1
with:
name: ${{ matrix.os }}
path: build/package
+21 -3
View File
@@ -25,7 +25,7 @@ Include("cmake/util.cmake")
# Automatic Versioning
set(VERSION_MAJOR 0)
set(VERSION_MINOR 2)
set(VERSION_MINOR 4)
set(VERSION_PATCH 0)
set(VERSION_TWEAK 0)
set(PROJECT_COMMIT "N/A")
@@ -116,18 +116,27 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
configure_file(
"${PROJECT_SOURCE_DIR}/cmake/version.hpp.in"
"${PROJECT_BINARY_DIR}/source/version.hpp"
@ONLY
)
configure_file(
"${PROJECT_SOURCE_DIR}/cmake/module.cpp.in"
"${PROJECT_BINARY_DIR}/source/module.cpp"
@ONLY
)
# Windows
if (WIN32)
## Installer (InnoSetup)
get_filename_component(ISS_FILES_DIR "${CMAKE_INSTALL_PREFIX}" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_FILES_DIR}" ISS_FILES_DIR)
get_filename_component(ISS_PACKAGE_DIR "${CMAKE_PACKAGE_PREFIX}" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_PACKAGE_DIR}" ISS_PACKAGE_DIR)
get_filename_component(ISS_SOURCE_DIR "${PROJECT_SOURCE_DIR}" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_SOURCE_DIR}" ISS_SOURCE_DIR)
configure_file(
"${PROJECT_SOURCE_DIR}/cmake/installer.iss.in"
"${PROJECT_BINARY_DIR}/installer.iss"
@ONLY
)
# Windows Specific Resource Definition
@@ -155,7 +164,7 @@ mark_as_advanced(FORCE OBS_NATIVE OBS_PACKAGE OBS_REFERENCE OBS_DOWNLOAD)
if(NOT TARGET libobs)
set(${PropertyPrefix}OBS_STUDIO_DIR "" CACHE PATH "OBS Studio Source/Package Directory")
set(${PropertyPrefix}OBS_DOWNLOAD_VERSION "24.0.0-rc2-ci" CACHE STRING "OBS Studio Version to download")
set(${PropertyPrefix}OBS_DOWNLOAD_VERSION "24.0.3-ci" CACHE STRING "OBS Studio Version to download")
endif()
if(NOT ${PropertyPrefix}OBS_NATIVE)
@@ -280,6 +289,8 @@ set(PROJECT_PRIVATE
"${PROJECT_SOURCE_DIR}/source/ffmpeg/swscale.cpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/tools.hpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/tools.cpp"
"${PROJECT_SOURCE_DIR}/source/hwapi/base.hpp"
"${PROJECT_SOURCE_DIR}/source/hwapi/base.cpp"
"${PROJECT_SOURCE_DIR}/source/ui/handler.hpp"
"${PROJECT_SOURCE_DIR}/source/ui/handler.cpp"
"${PROJECT_SOURCE_DIR}/source/ui/debug_handler.hpp"
@@ -293,6 +304,12 @@ set(PROJECT_PRIVATE
"${PROJECT_SOURCE_DIR}/source/ui/nvenc_hevc_handler.hpp"
"${PROJECT_SOURCE_DIR}/source/ui/nvenc_hevc_handler.cpp"
)
if(WIN32)
list(APPEND PROJECT_PRIVATE
"${PROJECT_SOURCE_DIR}/source/hwapi/d3d11.hpp"
"${PROJECT_SOURCE_DIR}/source/hwapi/d3d11.cpp"
)
endif()
# Source Grouping
source_group(TREE "${PROJECT_SOURCE_DIR}" PREFIX "Data Files" FILES ${PROJECT_DATA})
@@ -317,6 +334,7 @@ add_library(${PROJECT_NAME} MODULE
${PROJECT_GENERATED}
${PROJECT_PRIVATE}
${PROJECT_DATA}
${PROJECT_TEMPLATES}
)
# Include Directories
@@ -357,7 +375,7 @@ endif()
# Link Libraries
target_link_libraries(${PROJECT_NAME}
"${PROJECT_LIBRARIES}"
${PROJECT_LIBRARIES}
${FFMPEG_LIBRARIES}
)
-74
View File
@@ -1,74 +0,0 @@
# Generic Settings
version: '{build}-{branch}'
matrix:
fast_finish: true
# Build Image & Environment
platform: x64
# Build Tags only
skip_non_tags: true
image:
- Visual Studio 2017
environment:
CMAKE_SYSTEM_VERSION: 10.0.17134.0
CMAKE_GENERATOR_32: "Visual Studio 15 2017"
CMAKE_GENERATOR_64: "Visual Studio 15 2017 Win64"
PACKAGE_PREFIX: obs-ffmpeg-encoder
INNOSETUP_URL: http://www.jrsoftware.org/download.php/is.exe
CURL_VERSION: 7.39.0
# Resource Cache
cache:
- inno.exe
- build/32/libobs-download
- build/32/libobs-src
- build/64/libobs-download
- build/64/libobs-src
# Building
install:
- cmd: ci/appveyor-install.bat
build_script:
- cmd: node ci/builder.js
after_build:
- cmd: node ci/packager.js
- cmd: ci/appveyor-package.bat
# Testing
test: off
# Artifacts
artifacts:
- path: build/obs-ffmpeg-encoder-*.zip
- path: build/obs-ffmpeg-encoder-*.7z
- path: build/obs-ffmpeg-encoder-*.exe
# Deploying
deploy:
- provider: GitHub
auth_token:
secure: diGN1FzupARljI1iJsiAdZHut8aXODkUC6YDDi2oDRikEp5Ic8kQd8SSRDyA4pAJ
draft: true
prerelease: false
force_update: true
on:
appveyor_repo_tag: true
# Notifications
notifications:
- provider: Webhook
url:
secure: PTtt5ALhmK0q42jYyx4/Qa1Uf18+gLMXKGdzJjDISJt8IE/K0Zyp58UYmDDbbyLp4pBRf/Ylj8rn/zYL/mqBoDVRIH5zasPqIvBD0ZhtvNjTOxQ3QoRkAmxgpWeMowm3A3I1rLizA2H4EctPpoAJGrvQ1G2HEYn9tVsGYeetFTo=
on_build_success: false
on_build_failure: false
on_build_status_changed: true
body: >-
{
"content": "**Build {{status}}**: [{{commitId}}] {{commitMessage}}\nBy {{commitAuthor}} on {{commitDate}}\n{{buildUrl}}"
}
-9
View File
@@ -1,9 +0,0 @@
@ECHO OFF
git submodule update --init --force --recursive
IF EXIST inno.exe (
curl -kL "%INNOSETUP_URL%" -f --retry 5 -o inno.exe -z inno.exe
) else (
curl -kL "%INNOSETUP_URL%" -f --retry 5 -o inno.exe
)
inno.exe /VERYSILENT /NORETART /SP- /SUPPRESSMSGBOXES
-3
View File
@@ -1,3 +0,0 @@
@ECHO OFF
ECHO -- Building Installer --
"C:\Program Files (x86)\Inno Setup 5\ISCC.exe" /Qp ".\build\64\installer.iss" > nul
+5 -8
View File
@@ -13,7 +13,7 @@ if ((process.platform == "win32") || (process.platform == "win64")) {
`-DCMAKE_SYSTEM_VERSION=${process.env.CMAKE_SYSTEM_VERSION}`,
`-DCMAKE_PACKAGE_NAME=obs-ffmpeg-encoder`,
'-DCMAKE_INSTALL_PREFIX="build/distrib/"',
'-DCMAKE_PACKAGE_PREFIX="build/"',
'-DCMAKE_PACKAGE_PREFIX="build/package/"',
];
let extra_build = [
@@ -26,9 +26,8 @@ if ((process.platform == "win32") || (process.platform == "win64")) {
if ((process.env.CMAKE_GENERATOR_32 !== undefined) && (process.env.CMAKE_GENERATOR_32 !== "")) {
x32_steps.push(
[ 'cmake', [
'-H.',
'-Bbuild/32',
`-G"${process.env.CMAKE_GENERATOR_32}"`,
'-H.', '-Bbuild/32',
`-G"${process.env.CMAKE_GENERATOR_32}"`, '-AWin32', '-T"host=x64"',
].concat(extra_conf), env ]
);
x32_steps.push(
@@ -42,10 +41,8 @@ if ((process.platform == "win32") || (process.platform == "win64")) {
if ((process.env.CMAKE_GENERATOR_64 !== undefined) && (process.env.CMAKE_GENERATOR_64 !== "")) {
x64_steps.push(
[ 'cmake', [
'-H.',
'-Bbuild/64',
`-G"${process.env.CMAKE_GENERATOR_64}"`,
'-T"host=x64"'
'-H.', '-Bbuild/64',
`-G"${process.env.CMAKE_GENERATOR_64}"`, '-Ax64', '-T"host=x64"',
].concat(extra_conf), env ]
);
x64_steps.push(
+19 -13
View File
@@ -2,20 +2,8 @@
const process = require('process');
const runner = require('./runner.js');
function runRunners(runnerArray, name) {
return new Promise(async (resolve, reject) => {
let local = runnerArray.reverse();
while (local.length > 0) {
let task = local.pop();
let work = new runner(name, task[0], task[1], task[2]);
await work.run();
}
resolve(0);
});
}
let env = process.env;
let steps = [];
if ((process.env.CMAKE_GENERATOR_64 !== undefined) && (process.env.CMAKE_GENERATOR_64 !== "")) {
@@ -50,6 +38,24 @@ if ((process.env.CMAKE_GENERATOR_64 !== undefined) && (process.env.CMAKE_GENERAT
);
}
function runRunners(runnerArray, name) {
return new Promise(async (resolve, reject) => {
let local = runnerArray.reverse();
while (local.length > 0) {
try {
let task = local.pop();
let work = new runner(name, task[0], task[1], task[2]);
await work.run();
} catch (e) {
reject(e);
return;
}
}
resolve(0);
});
}
let promises = [];
promises.push(runRunners(steps, "32-Bit"));
Promise.all(promises).then(
+3 -3
View File
@@ -21,8 +21,8 @@ AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetDirName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
LicenseFile="@PROJECT_SOURCE_DIR@/LICENSE"
OutputDir="@CMAKE_INSTALL_PREFIX@/../"
LicenseFile="@ISS_SOURCE_DIR@/LICENSE"
OutputDir="@ISS_PACKAGE_DIR@"
OutputBaseFilename=obs-ffmpeg-encoder-{#MyAppVersion}
Compression=lzma
SolidCompression=yes
@@ -34,7 +34,7 @@ VersionInfoDescription={#MyAppName} Setup
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "@CMAKE_INSTALL_PREFIX@/*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "@ISS_FILES_DIR@/*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
+26 -10
View File
@@ -8,7 +8,7 @@ State.Manual="Manual"
# FFmpeg
FFmpeg="FFmpeg Options"
FFmpeg.CustomSettings="Custom Settings"
FFmpeg.CustomSettings.Description="Custom settings that override any detected options above, use with caution.\nThe input should be in the format 'key=value;key=value;...'."
FFmpeg.CustomSettings.Description="Override any options shown (or not shown) above with your own.\nThe format is similar to that of the FFmpeg command line:\n -key=value -key2=value2 -key3='quoted value'"
FFmpeg.Threads="Number of Threads"
FFmpeg.Threads.Description="The number of threads to use for encoding, if supported by the encoder.\nA value of 0 is equal to 'auto-detect' and may result in excessive CPU usage."
FFmpeg.ColorFormat="Override Color Format"
@@ -20,6 +20,9 @@ FFmpeg.StandardCompliance.Strict="Strict"
FFmpeg.StandardCompliance.Normal="Normal"
FFmpeg.StandardCompliance.Unofficial="Unofficial"
FFmpeg.StandardCompliance.Experimental="Experimental"
FFmpeg.GPU="GPU"
FFmpeg.GPU.Description="For multiple GPU systems, selects which GPU to use as the main encoder"
# Rate Control
RateControl="Rate Control"
@@ -46,6 +49,8 @@ KeyFrames="Key Frames"
KeyFrames.IntervalType="Interval Type"
KeyFrames.IntervalType.Frames="Frames"
KeyFrames.IntervalType.Seconds="Seconds"
KeyFrames.IntervalType.Description="Keyframe interval type"
KeyFrames.Interval.Description="Distance between key frames, in frames or seconds."
KeyFrames.Interval="Interval"
# Codec: H264
@@ -55,7 +60,9 @@ Codec.H264.Profile.baseline="Baseline"
Codec.H264.Profile.main="Main"
Codec.H264.Profile.high="High"
Codec.H264.Profile.high444p="High 4:4:4 Predictive"
Codec.H264.Profile.Description="H.264 profile determines which features of the codec can be used.\nHigh 4:4:4 Predictive is required for YUV 4:4:4 color space."
Codec.H264.Level="Level"
Codec.H264.Level.Description="Level determines the upper limits of resolution, frame rate and bitrate for the video."
# Codec: HEVC
Codec.HEVC="HEVC"
@@ -67,6 +74,7 @@ Codec.HEVC.Tier="Tier"
Codec.HEVC.Tier.main="Main"
Codec.HEVC.Tier.high="High"
Codec.HEVC.Level="Level"
Codec.HEVC.Level.Description="Level determines the upper limits of resolution, frame rate and bitrate for the video."
# Codec: Apple ProRes
Codec.ProRes.Profile="Profile"
@@ -79,6 +87,7 @@ Codec.ProRes.Profile.AP4X="4444 Extra Quality/XQ (AP4X)"
# NVENC
NVENC.Preset="Preset"
NVENC.Preset.Description="Presets are NVIDIA's preconfigured default settings."
NVENC.Preset.Default="Default"
NVENC.Preset.Slow="Slow"
NVENC.Preset.Medium="Medium"
@@ -93,19 +102,26 @@ NVENC.Preset.Lossless="Lossless"
NVENC.Preset.LosslessHighPerformance="Lossless High Performance"
NVENC.RateControl="Rate Control Options"
NVENC.RateControl.Mode="Mode"
NVENC.RateControl.Mode.Description="Rate control mode selection"
NVENC.RateControl.Mode.CQP="Constant Quantization Parameter"
NVENC.RateControl.Mode.CQP.Description="A flat compression ratio with no regard for bit rates."
NVENC.RateControl.Mode.VBR="Variable Bitrate"
NVENC.RateControl.Mode.VBR.Description="Sacrifices quality to stay below the upper bitrate limit,\nor saves bitrate where possible."
NVENC.RateControl.Mode.VBR_HQ="High Quality Variable Bitrate"
NVENC.RateControl.Mode.VBR_HQ.Description="Variable Bitrate with two-pass encoding enabled by default."
NVENC.RateControl.Mode.CBR="Constant Bitrate"
NVENC.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."
NVENC.RateControl.Mode.CBR_HQ="High Quality Constant Bitrate"
NVENC.RateControl.Mode.CBR_HQ.Description="Constant Bitrate with two-pass encoding enabled by default."
NVENC.RateControl.Mode.CBR_LD_HQ="Low Delay High Quality Constant Bitrate"
NVENC.RateControl.Mode.CBR_LD_HQ.Description="Constant Bitrate optimized for lowest encoding latency."
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="Adaptive I-Frames"
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="Adaptive B-Frames"
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="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"
@@ -131,21 +147,21 @@ NVENC.RateControl.QP.B.Description="Quantization parameter for B-Frames.\nSmalle
NVENC.RateControl.QP.B.Initial="Initial B-Frame QP"
NVENC.RateControl.QP.B.Initial.Description="Initial B-Frame quantization parameter.\nSet to -1 to use the automatically detected value instead."
NVENC.AQ="Adaptive Quantization"
NVENC.AQ.Spatial="Enable Spatial Adaptive Quantization"
NVENC.AQ.Spatial="Spatial Adaptive Quantization"
NVENC.AQ.Spatial.Description="Enable spatial adaptive quantization, also sometimes referred to as Psychovisual 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.AQ.Temporal="Temporal Adaptive Quantization"
NVENC.AQ.Temporal.Description="Enable temporal adaptive quantization."
NVENC.Other="Other Options"
NVENC.Other.BFrames="Maximum B-Frames"
NVENC.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."
NVENC.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.\nOnly Turing NVENC supports B-Frames for HEVC."
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="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="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="Non-reference P-Frames"
NVENC.Other.NonReferencePFrames.Description="Enable the automatic insertion of non-reference P-Frames."
+2 -2
View File
@@ -197,8 +197,8 @@ void progress_parse(uint8_t*& ptr, uint8_t* end, size_t& sz)
sz = get_nal_size(ptr, end);
}
void obsffmpeg::codecs::hevc::extract_header_sei(uint8_t* data, size_t sz_data,
std::vector<uint8_t>& header, std::vector<uint8_t>& sei)
void obsffmpeg::codecs::hevc::extract_header_sei(uint8_t* data, size_t sz_data, std::vector<uint8_t>& header,
std::vector<uint8_t>& sei)
{
uint8_t* ptr = data;
uint8_t* end = data + sz_data;
+2 -2
View File
@@ -61,8 +61,8 @@ namespace obsffmpeg {
UNKNOWN = -1,
};
void extract_header_sei(uint8_t* data, size_t sz_data,
std::vector<uint8_t>& header, std::vector<uint8_t>& sei);
void extract_header_sei(uint8_t* data, size_t sz_data, std::vector<uint8_t>& header,
std::vector<uint8_t>& sei);
} // namespace hevc
} // namespace codecs
+607 -231
View File
File diff suppressed because it is too large Load Diff
+43 -8
View File
@@ -23,10 +23,14 @@
#include <condition_variable>
#include <mutex>
#include <queue>
#include <stack>
#include <thread>
#include <vector>
#include "ffmpeg/avframe-queue.hpp"
#include "ffmpeg/swscale.hpp"
#include "hwapi/base.hpp"
#include "ui/handler.hpp"
extern "C" {
#include <obs-properties.h>
@@ -48,7 +52,7 @@ namespace obsffmpeg {
std::string uid;
std::string codec;
std::string readable_name;
obs_encoder_info oei;
obs_encoder_info oei = {0};
};
class encoder_factory {
@@ -56,15 +60,17 @@ namespace obsffmpeg {
encoder_info info_fallback;
const AVCodec* avcodec_ptr;
std::shared_ptr<obsffmpeg::ui::handler> _handler;
public:
encoder_factory(const AVCodec* codec);
virtual ~encoder_factory();
void register_encoder();
void get_defaults(obs_data_t* settings);
void get_defaults(obs_data_t* settings, bool hw_encoder = false);
void get_properties(obs_properties_t* props);
void get_properties(obs_properties_t* props, bool hw_encoder = false);
const AVCodec* get_avcodec();
@@ -80,26 +86,43 @@ namespace obsffmpeg {
const AVCodec* _codec;
AVCodecContext* _context;
ffmpeg::avframe_queue _frame_queue;
ffmpeg::avframe_queue _frame_queue_used;
std::shared_ptr<obsffmpeg::ui::handler> _handler;
std::shared_ptr<obsffmpeg::hwapi::base> _hwapi;
std::shared_ptr<obsffmpeg::hwapi::instance> _hwinst;
ffmpeg::swscale _swscale;
AVPacket _current_packet;
int64_t _lag_in_frames;
int64_t _count_send_frames;
size_t _lag_in_frames;
size_t _count_send_frames;
// Extra Data
bool _have_first_frame;
std::vector<uint8_t> _extra_data;
std::vector<uint8_t> _sei_data;
// Frame Stack and Queue
std::stack<std::shared_ptr<AVFrame>> _free_frames;
std::queue<std::shared_ptr<AVFrame>> _used_frames;
std::chrono::high_resolution_clock::time_point _free_frames_last_used;
void initialize_sw(obs_data_t* settings);
void initialize_hw(obs_data_t* settings);
void push_free_frame(std::shared_ptr<AVFrame> frame);
std::shared_ptr<AVFrame> pop_free_frame();
void push_used_frame(std::shared_ptr<AVFrame> frame);
std::shared_ptr<AVFrame> pop_used_frame();
public:
encoder(obs_data_t* settings, obs_encoder_t* encoder, bool is_texture_encode = false);
virtual ~encoder();
public: // OBS API
// Shared
void get_properties(obs_properties_t* props);
void get_properties(obs_properties_t* props, bool hw_encode = false);
bool update(obs_data_t* settings);
@@ -125,5 +148,17 @@ namespace obsffmpeg {
int receive_packet(bool* received_packet, struct encoder_packet* packet);
int send_frame(std::shared_ptr<AVFrame> frame);
bool encode_avframe(std::shared_ptr<AVFrame> frame, struct encoder_packet* packet,
bool* received_packet);
public: // Handler API
bool is_hardware_encode();
const AVCodec* get_avcodec();
const AVCodecContext* get_avcodeccontext();
void parse_ffmpeg_commandline(std::string text);
};
} // namespace obsffmpeg
+113 -140
View File
@@ -24,12 +24,15 @@
#include <map>
#include <sstream>
#include <stdexcept>
#include "plugin.hpp"
#include "utility.hpp"
extern "C" {
#pragma warning(push)
#pragma warning(disable : 4244)
#include <libavcodec/avcodec.h>
#include <libavutil/error.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#pragma warning(pop)
}
@@ -113,52 +116,11 @@ const char* ffmpeg::tools::get_color_space_name(AVColorSpace v)
const char* ffmpeg::tools::get_error_description(int error)
{
switch (error) {
case AVERROR(EPERM):
return "Permission Denied";
// case AVERROR(ENOENT):
// case AVERROR(ESRCH):
// case AVERROR(EINTR):
// case AVERROR(EIO):
// case AVERROR(ENXIO):
// case AVERROR(E2BIG):
// case AVERROR(ENOEXEC):
// case AVERROR(EBADF):
// case AVERROR(ECHILD):
// case AVERROR(EAGAIN):
case AVERROR(ENOMEM):
return "Out Of Memory";
// case AVERROR(EACCES):
// case AVERROR(EFAULT):
// case AVERROR(EBUSY):
// case AVERROR(EEXIST):
// case AVERROR(EXDEV):
// case AVERROR(ENODEV):
// case AVERROR(ENOTDIR):
// case AVERROR(EISDIR):
// case AVERROR(ENFILE):
// case AVERROR(EMFILE):
// case AVERROR(ENOTTY):
// case AVERROR(EFBIG):
// case AVERROR(ENOSPC):
// case AVERROR(ESPIPE):
// case AVERROR(EROFS):
// case AVERROR(EMLINK):
// case AVERROR(EPIPE):
// case AVERROR(EDOM):
// case AVERROR(EDEADLK):
// case AVERROR(ENAMETOOLONG):
// case AVERROR(ENOLCK):
// case AVERROR(ENOSYS):
// case AVERROR(ENOTEMPTY):
case AVERROR(EINVAL):
return "Invalid Value(s)";
case AVERROR(ERANGE):
return "Out of Range";
// case AVERROR(EILSEQ):
// case AVERROR(STRUNCATE):
thread_local char error_buf[AV_ERROR_MAX_STRING_SIZE + 1];
if (av_strerror(error, error_buf, AV_ERROR_MAX_STRING_SIZE) < 0) {
snprintf(error_buf, AV_ERROR_MAX_STRING_SIZE, "Unknown Error (%i)", error);
}
return "Not Translated Yet";
return error_buf;
}
static std::map<video_format, AVPixelFormat> obs_to_av_format_map = {
@@ -220,10 +182,10 @@ AVColorRange ffmpeg::tools::obs_videorangetype_to_avcolorrange(video_range_type
{
switch (v) {
case VIDEO_RANGE_DEFAULT:
case VIDEO_RANGE_FULL:
return AVCOL_RANGE_JPEG;
case VIDEO_RANGE_PARTIAL:
return AVCOL_RANGE_MPEG;
case VIDEO_RANGE_FULL:
return AVCOL_RANGE_JPEG;
}
throw std::invalid_argument("unknown range");
}
@@ -279,102 +241,113 @@ std::vector<AVPixelFormat> ffmpeg::tools::get_software_formats(const AVPixelForm
return std::move(fmts);
}
static std::map<std::pair<AVPixelFormat, AVPixelFormat>, double_t> format_compatibility = {
{{AV_PIX_FMT_NV12, AV_PIX_FMT_NV12}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_NV12, AV_PIX_FMT_NV21}, 65535.0},
{{AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P}, 65535.0},
{{AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P9}, 58981.5},
{{AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10}, 53083.35},
{{AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P12}, 47775.015},
{{AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P14}, 42997.5135},
{{AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16}, 38697.76215},
{{AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA420P}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA420P9}, 65535.0},
{{AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA420P10}, 58981.5},
{{AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA420P16}, 53083.35},
{{AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P}, 32767.0},
{{AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P}, 65535.0},
{{AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P9}, 58981.5},
{{AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10}, 53083.35},
{{AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P12}, 47775.015},
{{AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P14}, 42997.5135},
{{AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P16}, 38697.76215},
{{AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA422P}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P9}, 65535.0},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P10}, 58981.5},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P16}, 53083.35},
{{AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P}, 32767.0},
{{AV_PIX_FMT_YVYU422, AV_PIX_FMT_YVYU422}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YVYU422, AV_PIX_FMT_YUYV422}, 65535.0},
{{AV_PIX_FMT_UYVY422, AV_PIX_FMT_UYVY422}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_UYVY422, AV_PIX_FMT_YVYU422}, 65535.0},
{{AV_PIX_FMT_YUYV422, AV_PIX_FMT_YUYV422}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P}, 65535.0},
{{AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P9}, 58981.5},
{{AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10}, 53083.35},
{{AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P12}, 47775.015},
{{AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P14}, 42997.5135},
{{AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P16}, 38697.76215},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P9}, 65535.0},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10}, 58981.5},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P16}, 53083.35},
{{AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P}, 32767.0},
{{AV_PIX_FMT_RGBA, AV_PIX_FMT_RGBA}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB0}, 65535.0},
{{AV_PIX_FMT_RGBA, AV_PIX_FMT_0RGB}, 32767.0},
{{AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24}, 16384.0},
{{AV_PIX_FMT_BGRA, AV_PIX_FMT_BGRA}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR0}, 65535.0},
{{AV_PIX_FMT_BGRA, AV_PIX_FMT_0BGR}, 32767.0},
{{AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24}, 16384.0},
{{AV_PIX_FMT_BGR0, AV_PIX_FMT_BGR0}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_BGR0, AV_PIX_FMT_BGRA}, 65535.0},
{{AV_PIX_FMT_BGR0, AV_PIX_FMT_BGR24}, 32767.0},
{{AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9}, 65535.0},
{{AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10}, 58981.5},
{{AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY12}, 53083.35},
{{AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY14}, 47775.015},
{{AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16}, 42997.5135},
{{AV_PIX_FMT_BGR24, AV_PIX_FMT_BGR24}, std::numeric_limits<double_t>::max()},
{{AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24}, 32767.0},
};
AVPixelFormat ffmpeg::tools::get_best_compatible_format(const AVPixelFormat* list, AVPixelFormat source)
void ffmpeg::tools::setup_obs_color(video_colorspace colorspace, video_range_type range, AVCodecContext* context)
{
double_t score = std::numeric_limits<double_t>::min();
AVPixelFormat best = source;
std::map<video_colorspace, std::tuple<AVColorSpace, AVColorPrimaries, AVColorTransferCharacteristic>>
colorspaces = {
{VIDEO_CS_DEFAULT, {AVCOL_SPC_BT470BG, AVCOL_PRI_BT470BG, AVCOL_TRC_SMPTE170M}},
{VIDEO_CS_601, {AVCOL_SPC_BT470BG, AVCOL_PRI_BT470BG, AVCOL_TRC_SMPTE170M}},
{VIDEO_CS_709, {AVCOL_SPC_BT709, AVCOL_PRI_BT709, AVCOL_TRC_BT709}},
};
std::map<video_range_type, AVColorRange> colorranges = {
{VIDEO_RANGE_DEFAULT, AVCOL_RANGE_MPEG},
{VIDEO_RANGE_PARTIAL, AVCOL_RANGE_MPEG},
{VIDEO_RANGE_FULL, AVCOL_RANGE_JPEG},
};
for (auto fmt = list; fmt && (*fmt != AV_PIX_FMT_NONE); fmt++) {
auto found = format_compatibility.find(std::pair{source, *fmt});
if (found != format_compatibility.end()) {
score = found->second;
best = *fmt;
{
auto found = colorspaces.find(colorspace);
if (found != colorspaces.end()) {
context->colorspace = std::get<AVColorSpace>(found->second);
context->color_primaries = std::get<AVColorPrimaries>(found->second);
context->color_trc = std::get<AVColorTransferCharacteristic>(found->second);
}
}
{
auto found = colorranges.find(range);
if (found != colorranges.end()) {
context->color_range = found->second;
}
}
if (score <= 0) {
int data_loss = 0;
return avcodec_find_best_pix_fmt_of_list(list, source, 0, &data_loss);
}
return best;
// Downscaling should result in downscaling, not pixelation
context->chroma_sample_location = AVCHROMA_LOC_CENTER;
}
const char* ffmpeg::tools::get_std_compliance_name(int compliance)
{
switch (compliance) {
case FF_COMPLIANCE_VERY_STRICT:
return "Very Strict";
case FF_COMPLIANCE_STRICT:
return "Strict";
case FF_COMPLIANCE_NORMAL:
return "Normal";
case FF_COMPLIANCE_UNOFFICIAL:
return "Unofficial";
case FF_COMPLIANCE_EXPERIMENTAL:
return "Experimental";
}
return "Invalid";
}
const char* ffmpeg::tools::get_thread_type_name(int thread_type)
{
switch (thread_type) {
case FF_THREAD_FRAME | FF_THREAD_SLICE:
return "Slice & Frame";
case FF_THREAD_FRAME:
return "Frame";
case FF_THREAD_SLICE:
return "Slice";
default:
return "None";
}
}
void ffmpeg::tools::print_av_option_bool(AVCodecContext* context, const char* option, std::string text)
{
if (av_opt_is_set_to_default_by_name(context, option, AV_OPT_SEARCH_CHILDREN) == 0) {
int64_t v = 0;
if (av_opt_get_int(context, option, AV_OPT_SEARCH_CHILDREN, &v) == 0) {
PLOG_INFO("[%s] %s: %s", context->codec->name, text.c_str(), v == 0 ? "Disabled" : "Enabled");
} else {
PLOG_INFO("[%s] %s: <Error>", context->codec->name, text.c_str());
}
} else {
PLOG_INFO("[%s] %s: <Default>", context->codec->name, text.c_str());
}
}
void ffmpeg::tools::print_av_option_int(AVCodecContext* context, const char* option, std::string text,
std::string suffix)
{
if (av_opt_is_set_to_default_by_name(context, option, AV_OPT_SEARCH_CHILDREN) == 0) {
int64_t v = 0;
if (av_opt_get_int(context, option, AV_OPT_SEARCH_CHILDREN, &v) == 0) {
PLOG_INFO("[%s] %s: %lld %s", context->codec->name, text.c_str(), v, suffix.c_str());
} else {
PLOG_INFO("[%s] %s: <Error>", context->codec->name, text.c_str());
}
} else {
PLOG_INFO("[%s] %s: <Default>", context->codec->name, text.c_str());
}
}
void ffmpeg::tools::print_av_option_string(AVCodecContext* context, const char* option, std::string text,
std::function<std::string(int64_t)> decoder)
{
if (av_opt_is_set_to_default_by_name(context, option, AV_OPT_SEARCH_CHILDREN) == 0) {
int64_t v = 0;
if (av_opt_get_int(context, option, AV_OPT_SEARCH_CHILDREN, &v) == 0) {
std::string name = "<Unknown>";
if (decoder)
name = decoder(v);
PLOG_INFO("[%s] %s: %s", context->codec->name, text.c_str(), name.c_str());
} else {
PLOG_INFO("[%s] %s: <Error>", context->codec->name, text.c_str());
}
} else {
PLOG_INFO("[%s] %s: <Default>", context->codec->name, text.c_str());
}
}
+16 -2
View File
@@ -23,13 +23,14 @@
#define OBS_FFMPEG_FFMPEG_UTILITY
#pragma once
#include <functional>
#include <obs.h>
#include <string>
#include <vector>
extern "C" {
#include <libavutil/pixfmt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/pixfmt.h>
}
namespace ffmpeg {
@@ -56,7 +57,20 @@ namespace ffmpeg {
std::vector<AVPixelFormat> get_software_formats(const AVPixelFormat* list);
AVPixelFormat get_best_compatible_format(const AVPixelFormat* list, AVPixelFormat source);
void setup_obs_color(video_colorspace colorspace, video_range_type range, AVCodecContext* context);
const char* get_std_compliance_name(int compliance);
const char* get_thread_type_name(int thread_type);
void print_av_option_bool(AVCodecContext* context, const char* option, std::string text);
void print_av_option_int(AVCodecContext* context, const char* option, std::string text,
std::string suffix);
void print_av_option_string(AVCodecContext* context, const char* option, std::string text,
std::function<std::string(int64_t)> decoder);
} // namespace tools
} // namespace ffmpeg
+22
View File
@@ -0,0 +1,22 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (c) 2019 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 "base.hpp"
+70
View File
@@ -0,0 +1,70 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (c) 2019 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 <cinttypes>
#include <list>
#include <memory>
#include <string>
#include <utility>
extern "C" {
#pragma warning(push)
#pragma warning(disable : 4244)
#include <libavutil/frame.h>
#include <libavutil/hwcontext.h>
#pragma warning(pop)
}
namespace obsffmpeg {
namespace hwapi {
struct device {
std::pair<int64_t, int64_t> id;
std::string name;
};
class instance;
class base {
public:
virtual std::list<obsffmpeg::hwapi::device> enumerate_adapters() = 0;
virtual std::shared_ptr<obsffmpeg::hwapi::instance> create(obsffmpeg::hwapi::device target) = 0;
virtual std::shared_ptr<obsffmpeg::hwapi::instance> create_from_obs() = 0;
};
class instance {
public:
virtual AVBufferRef* create_device_context() = 0;
virtual std::shared_ptr<AVFrame> allocate_frame(AVBufferRef* frames) = 0;
virtual void copy_from_obs(AVBufferRef* frames, uint32_t handle, uint64_t lock_key,
uint64_t* next_lock_key, std::shared_ptr<AVFrame> frame) = 0;
virtual std::shared_ptr<AVFrame> avframe_from_obs(AVBufferRef* frames, uint32_t handle,
uint64_t lock_key,
uint64_t* next_lock_key) = 0;
};
} // namespace hwapi
} // namespace obsffmpeg
+245
View File
@@ -0,0 +1,245 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (c) 2019 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 "d3d11.hpp"
#include <sstream>
#include <vector>
#include "utility.hpp"
extern "C" {
#pragma warning(push)
#pragma warning(disable : 4244)
#include <graphics/graphics.h>
#include <libavutil/hwcontext_d3d11va.h>
#include <obs.h>
#pragma warning(pop)
}
obsffmpeg::hwapi::d3d11::d3d11() : _dxgi_module(0), _d3d11_module(0)
{
_dxgi_module = LoadLibraryW(L"dxgi.dll");
if (!_dxgi_module)
throw std::runtime_error("Unable to load DXGI");
_d3d11_module = LoadLibraryW(L"d3d11.dll");
if (!_d3d11_module)
throw std::runtime_error("Unable to load D3D11");
_CreateDXGIFactory = reinterpret_cast<CreateDXGIFactory_t>(GetProcAddress(_dxgi_module, "CreateDXGIFactory"));
_CreateDXGIFactory1 =
reinterpret_cast<CreateDXGIFactory1_t>(GetProcAddress(_dxgi_module, "CreateDXGIFactory1"));
_D3D11CreateDevice = reinterpret_cast<D3D11CreateDevice_t>(GetProcAddress(_d3d11_module, "D3D11CreateDevice"));
if (!_CreateDXGIFactory && !_CreateDXGIFactory1)
throw std::runtime_error("DXGI not supported");
if (!_D3D11CreateDevice)
throw std::runtime_error("D3D11 not supported");
HRESULT hr = _CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&_dxgifactory);
if (FAILED(hr)) {
std::stringstream sstr;
sstr << "Failed to create DXGI Factory (" << hr << ")";
throw std::runtime_error(sstr.str());
}
}
obsffmpeg::hwapi::d3d11::~d3d11()
{
FreeLibrary(_dxgi_module);
FreeLibrary(_d3d11_module);
}
std::list<obsffmpeg::hwapi::device> obsffmpeg::hwapi::d3d11::enumerate_adapters()
{
std::list<device> adapters;
// Enumerate Adapters
IDXGIAdapter1* dxgi_adapter = nullptr;
for (UINT idx = 0; !FAILED(_dxgifactory->EnumAdapters1(idx, &dxgi_adapter)); idx++) {
DXGI_ADAPTER_DESC1 desc = DXGI_ADAPTER_DESC1();
dxgi_adapter->GetDesc1(&desc);
std::vector<char> buf(1024);
size_t len = snprintf(buf.data(), buf.size(), "%ls (VEN_%04x/DEV_%04x/SUB_%04x/REV_%04x)",
desc.Description, desc.VendorId, desc.DeviceId, desc.SubSysId, desc.Revision);
device dev;
dev.name = std::string(buf.data(), buf.data() + len);
dev.id.first = desc.AdapterLuid.HighPart;
dev.id.second = desc.AdapterLuid.LowPart;
adapters.push_back(dev);
}
return std::move(adapters);
}
std::shared_ptr<obsffmpeg::hwapi::instance> obsffmpeg::hwapi::d3d11::create(obsffmpeg::hwapi::device target)
{
std::shared_ptr<d3d11_instance> inst;
ATL::CComPtr<ID3D11Device> device;
ATL::CComPtr<ID3D11DeviceContext> context;
IDXGIAdapter1* adapter = nullptr;
// Find the correct "Adapter" (device).
IDXGIAdapter1* dxgi_adapter = nullptr;
for (UINT idx = 0; !FAILED(_dxgifactory->EnumAdapters1(idx, &dxgi_adapter)); idx++) {
DXGI_ADAPTER_DESC1 desc = DXGI_ADAPTER_DESC1();
dxgi_adapter->GetDesc1(&desc);
if ((desc.AdapterLuid.LowPart == target.id.second) && (desc.AdapterLuid.HighPart == target.id.first)) {
adapter = dxgi_adapter;
break;
}
}
// Create a D3D11 Device
UINT device_flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
std::vector<D3D_FEATURE_LEVEL> feature_levels = {D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0,
D3D_FEATURE_LEVEL_11_1};
if (FAILED(_D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_HARDWARE, NULL, device_flags, feature_levels.data(),
static_cast<UINT>(feature_levels.size()), D3D11_SDK_VERSION, &device, NULL,
&context))) {
throw std::runtime_error("Failed to create D3D11 device for target.");
}
return std::make_shared<d3d11_instance>(device, context);
}
std::shared_ptr<obsffmpeg::hwapi::instance> obsffmpeg::hwapi::d3d11::create_from_obs()
{
auto gctx = obsffmpeg::obs_graphics();
if (GS_DEVICE_DIRECT3D_11 != gs_get_device_type()) {
throw std::runtime_error("OBS Device is not a D3D11 Device.");
}
ATL::CComPtr<ID3D11Device> device =
ATL::CComPtr<ID3D11Device>(reinterpret_cast<ID3D11Device*>(gs_get_device_obj()));
ATL::CComPtr<ID3D11DeviceContext> context;
device->GetImmediateContext(&context);
return std::make_shared<d3d11_instance>(device, context);
}
struct D3D11AVFrame {
ATL::CComPtr<ID3D11Texture2D> handle;
};
obsffmpeg::hwapi::d3d11_instance::d3d11_instance(ATL::CComPtr<ID3D11Device> device,
ATL::CComPtr<ID3D11DeviceContext> context)
{
_device = device;
_context = context;
}
obsffmpeg::hwapi::d3d11_instance::~d3d11_instance() {}
AVBufferRef* obsffmpeg::hwapi::d3d11_instance::create_device_context()
{
AVBufferRef* dctx_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA);
if (!dctx_ref)
throw std::runtime_error("Failed to allocate AVHWDeviceContext.");
AVHWDeviceContext* dctx = reinterpret_cast<AVHWDeviceContext*>(dctx_ref->data);
AVD3D11VADeviceContext* d3d11va = reinterpret_cast<AVD3D11VADeviceContext*>(dctx->hwctx);
// TODO: Determine if these need an additional reference.
d3d11va->device = _device;
d3d11va->device->AddRef();
d3d11va->device_context = _context;
d3d11va->device_context->AddRef();
d3d11va->lock = [](void*) { obs_enter_graphics(); };
d3d11va->unlock = [](void*) { obs_leave_graphics(); };
int ret = av_hwdevice_ctx_init(dctx_ref);
if (ret < 0)
throw std::runtime_error("Failed to initialize AVHWDeviceContext.");
return dctx_ref;
}
std::shared_ptr<AVFrame> obsffmpeg::hwapi::d3d11_instance::allocate_frame(AVBufferRef* frames)
{
auto gctx = obsffmpeg::obs_graphics();
auto frame = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame* frame) {
av_frame_unref(frame);
av_frame_free(&frame);
});
if (av_hwframe_get_buffer(frames, frame.get(), 0) < 0) {
throw std::runtime_error("Failed to create AVFrame.");
}
return frame;
}
void obsffmpeg::hwapi::d3d11_instance::copy_from_obs(AVBufferRef*, uint32_t handle, uint64_t lock_key,
uint64_t* next_lock_key, std::shared_ptr<AVFrame> frame)
{
auto gctx = obsffmpeg::obs_graphics();
ATL::CComPtr<IDXGIKeyedMutex> mutex;
ATL::CComPtr<ID3D11Texture2D> input;
if (FAILED(_device->OpenSharedResource(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(handle)),
__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&input)))) {
throw std::runtime_error("Failed to open shared texture resource.");
}
if (FAILED(input->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void**>(&mutex)))) {
throw std::runtime_error("Failed to retrieve mutex for texture resource.");
}
if (FAILED(mutex->AcquireSync(lock_key, 1000))) {
throw std::runtime_error("Failed to acquire lock on input texture.");
}
// Set some parameters on the input texture, and get its description.
UINT evict = input->GetEvictionPriority();
input->SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
// Clone the content of the input texture.
_context->CopyResource(reinterpret_cast<ID3D11Texture2D*>(frame->data[0]), input);
// Restore original parameters on input.
input->SetEvictionPriority(evict);
if (FAILED(mutex->ReleaseSync(lock_key))) {
throw std::runtime_error("Failed to release lock on input texture.");
}
// TODO: Determine if this is necessary.
mutex->ReleaseSync(*next_lock_key);
}
std::shared_ptr<AVFrame> obsffmpeg::hwapi::d3d11_instance::avframe_from_obs(AVBufferRef* frames, uint32_t handle,
uint64_t lock_key, uint64_t* next_lock_key)
{
auto gctx = obsffmpeg::obs_graphics();
auto frame = this->allocate_frame(frames);
this->copy_from_obs(frames, handle, lock_key, next_lock_key, frame);
return frame;
}
+80
View File
@@ -0,0 +1,80 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (c) 2019 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 <atlutil.h>
#include <d3d11.h>
#include <d3d11_1.h>
#include <dxgi.h>
#include "base.hpp"
namespace obsffmpeg {
namespace hwapi {
class d3d11 : public ::obsffmpeg::hwapi::base {
typedef HRESULT(__stdcall* CreateDXGIFactory_t)(REFIID, void**);
typedef HRESULT(__stdcall* CreateDXGIFactory1_t)(REFIID, void**);
typedef HRESULT(__stdcall* D3D11CreateDevice_t)(_In_opt_ IDXGIAdapter*, D3D_DRIVER_TYPE,
HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT,
UINT, _Out_opt_ ID3D11Device**,
_Out_opt_ D3D_FEATURE_LEVEL*,
_Out_opt_ ID3D11DeviceContext**);
HMODULE _dxgi_module;
CreateDXGIFactory_t _CreateDXGIFactory;
CreateDXGIFactory1_t _CreateDXGIFactory1;
HMODULE _d3d11_module;
D3D11CreateDevice_t _D3D11CreateDevice;
ATL::CComPtr<IDXGIFactory1> _dxgifactory;
public:
d3d11();
virtual ~d3d11();
virtual std::list<obsffmpeg::hwapi::device> enumerate_adapters() override;
virtual std::shared_ptr<obsffmpeg::hwapi::instance>
create(obsffmpeg::hwapi::device target) override;
virtual std::shared_ptr<obsffmpeg::hwapi::instance> create_from_obs() override;
};
class d3d11_instance : public ::obsffmpeg::hwapi::instance {
ATL::CComPtr<ID3D11Device> _device;
ATL::CComPtr<ID3D11DeviceContext> _context;
public:
d3d11_instance(ATL::CComPtr<ID3D11Device> device, ATL::CComPtr<ID3D11DeviceContext> context);
virtual ~d3d11_instance();
virtual AVBufferRef* create_device_context() override;
virtual std::shared_ptr<AVFrame> allocate_frame(AVBufferRef* frames) override;
virtual void copy_from_obs(AVBufferRef* frames, uint32_t handle, uint64_t lock_key,
uint64_t* next_lock_key, std::shared_ptr<AVFrame> frame) override;
virtual std::shared_ptr<AVFrame> avframe_from_obs(AVBufferRef* frames, uint32_t handle,
uint64_t lock_key,
uint64_t* next_lock_key) override;
};
} // namespace hwapi
} // namespace obsffmpeg
+3 -2
View File
@@ -35,7 +35,7 @@ extern "C" {
#pragma warning(pop)
}
void obsffmpeg::ui::debug_handler::get_defaults(obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::debug_handler::get_defaults(obs_data_t*, const AVCodec*, AVCodecContext*, bool) {}
template<typename T>
std::string to_string(T value){};
@@ -64,7 +64,8 @@ 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*, const AVCodec* codec, AVCodecContext* context)
void obsffmpeg::ui::debug_handler::get_properties(obs_properties_t*, const AVCodec* codec, AVCodecContext* context,
bool)
{
if (context)
return;
+3 -3
View File
@@ -26,11 +26,11 @@ namespace obsffmpeg {
namespace ui {
class debug_handler : public handler {
public:
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
bool hw_encode) override;
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context) override;
AVCodecContext* context, bool hw_encode) override;
virtual void update(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
+18 -14
View File
@@ -20,23 +20,27 @@
// SOFTWARE.
#include "handler.hpp"
#include "encoder.hpp"
void obsffmpeg::ui::handler::override_visible_name(const AVCodec*, std::string&) {}
void obsffmpeg::ui::handler::override_info(obs_encoder_info* main, obs_encoder_info* fallback) {}
void obsffmpeg::ui::handler::override_colorformat(AVPixelFormat& target_format, obs_data_t* settings,
const AVCodec* codec, AVCodecContext* context)
void obsffmpeg::ui::handler::adjust_encoder_info(obsffmpeg::encoder_factory*, obsffmpeg::encoder_info*,
obsffmpeg::encoder_info*)
{}
void obsffmpeg::ui::handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) {}
void obsffmpeg::ui::handler::get_defaults(obs_data_t*, const AVCodec*, AVCodecContext*, bool) {}
void obsffmpeg::ui::handler::import_from_ffmpeg(const std::string ffmpeg, obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
{}
std::string obsffmpeg::ui::handler::export_for_ffmpeg(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
bool obsffmpeg::ui::handler::has_keyframe_support(obsffmpeg::encoder* instance)
{
return std::string();
return (instance->get_avcodec()->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0;
}
void obsffmpeg::ui::handler::get_properties(obs_properties_t*, const AVCodec*, AVCodecContext*, bool) {}
void obsffmpeg::ui::handler::update(obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::handler::override_update(obsffmpeg::encoder*, obs_data_t*) {}
void obsffmpeg::ui::handler::log_options(obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::handler::override_colorformat(AVPixelFormat&, obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::handler::process_avpacket(AVPacket&, const AVCodec*, AVCodecContext*) {}
+26 -18
View File
@@ -22,6 +22,7 @@
#pragma once
#include <string>
#include "hwapi/base.hpp"
extern "C" {
#include <obs.h>
@@ -36,31 +37,38 @@ extern "C" {
}
namespace obsffmpeg {
struct encoder_info;
class encoder_factory;
class encoder;
namespace ui {
class handler {
public:
virtual void override_visible_name(const AVCodec* codec, std::string& name);
public /*factory*/:
virtual void adjust_encoder_info(obsffmpeg::encoder_factory* factory,
obsffmpeg::encoder_info* main,
obsffmpeg::encoder_info* fallback);
virtual void override_info(obs_encoder_info* main, obs_encoder_info* fallback);
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
bool hw_encode);
public /*settings*/:
virtual bool has_keyframe_support(obsffmpeg::encoder* instance);
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context, bool hw_encode);
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
virtual void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
public /*instance*/:
virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings,
const AVCodec* codec, AVCodecContext* context);
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) = 0;
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context) = 0;
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) = 0;
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
virtual void import_from_ffmpeg(const std::string ffmpeg, obs_data_t* settings,
const AVCodec* codec, AVCodecContext* context);
virtual std::string export_for_ffmpeg(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context);
virtual void process_avpacket(AVPacket& packet, const AVCodec* codec, AVCodecContext* context);
};
} // namespace ui
} // namespace obsffmpeg
+39 -26
View File
@@ -21,6 +21,8 @@
#include "nvenc_h264_handler.hpp"
#include "codecs/h264.hpp"
#include "encoder.hpp"
#include "ffmpeg/tools.hpp"
#include "nvenc_shared.hpp"
#include "plugin.hpp"
#include "strings.hpp"
@@ -34,28 +36,6 @@ extern "C" {
#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'.
*/
using namespace obsffmpeg::codecs::h264;
std::map<profile, std::string> profiles{
@@ -79,13 +59,15 @@ INITIALIZER(nvenc_h264_handler_init)
});
};
void obsffmpeg::ui::nvenc_h264_handler::override_visible_name(const AVCodec*, std::string& name)
void obsffmpeg::ui::nvenc_h264_handler::adjust_encoder_info(obsffmpeg::encoder_factory*, obsffmpeg::encoder_info* main,
obsffmpeg::encoder_info* fallback)
{
name = "H.264/AVC Encoder (NVidia NVENC)";
main->readable_name = "H.264/AVC NVidia NVENC (Hardware)";
fallback->readable_name = "H.264/AVC NVidia NVENC (Software)";
}
void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
AVCodecContext* context, bool)
{
nvenc::get_defaults(settings, codec, context);
@@ -93,8 +75,13 @@ void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const
obs_data_set_default_int(settings, P_H264_LEVEL, static_cast<int64_t>(codecs::h264::level::UNKNOWN));
}
bool obsffmpeg::ui::nvenc_h264_handler::has_keyframe_support(obsffmpeg::encoder*)
{
return true;
}
void obsffmpeg::ui::nvenc_h264_handler::get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context)
AVCodecContext* context, bool)
{
if (!context) {
this->get_encoder_properties(props, codec);
@@ -125,6 +112,32 @@ void obsffmpeg::ui::nvenc_h264_handler::update(obs_data_t* settings, const AVCod
}
}
void obsffmpeg::ui::nvenc_h264_handler::override_update(obsffmpeg::encoder* instance, obs_data_t* settings)
{
nvenc::override_update(instance, settings);
}
void obsffmpeg::ui::nvenc_h264_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
{
nvenc::log_options(settings, codec, context);
PLOG_INFO("[%s] H.265/HEVC:", codec->name);
ffmpeg::tools::print_av_option_string(context, "profile", " Profile", [](int64_t v) {
profile val = static_cast<profile>(v);
auto index = profiles.find(val);
if (index != profiles.end())
return index->second;
return std::string("<Unknown>");
});
ffmpeg::tools::print_av_option_string(context, "level", " Level", [](int64_t v) {
level val = static_cast<level>(v);
auto index = levels.find(val);
if (index != levels.end())
return index->second;
return std::string("<Unknown>");
});
}
void obsffmpeg::ui::nvenc_h264_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec)
{
nvenc::get_properties_pre(props, codec);
+18 -7
View File
@@ -33,17 +33,28 @@ extern "C" {
namespace obsffmpeg {
namespace ui {
class nvenc_h264_handler : public handler {
public:
virtual void override_visible_name(const AVCodec* codec, std::string& name) override;
public /*factory*/:
virtual void adjust_encoder_info(obsffmpeg::encoder_factory* factory,
obsffmpeg::encoder_info* main,
obsffmpeg::encoder_info* fallback);
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
bool hw_encode);
public /*settings*/:
virtual bool has_keyframe_support(obsffmpeg::encoder* instance);
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context) override;
AVCodecContext* context, bool hw_encode);
virtual void update(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
virtual void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
public /*instance*/:
//virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
private:
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
+46 -26
View File
@@ -21,6 +21,8 @@
#include "nvenc_hevc_handler.hpp"
#include "codecs/hevc.hpp"
#include "encoder.hpp"
#include "ffmpeg/tools.hpp"
#include "nvenc_shared.hpp"
#include "plugin.hpp"
#include "strings.hpp"
@@ -34,28 +36,6 @@ extern "C" {
#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'.
*/
using namespace obsffmpeg::codecs::hevc;
std::map<profile, std::string> profiles{
@@ -82,13 +62,15 @@ INITIALIZER(nvenc_hevc_handler_init)
});
};
void obsffmpeg::ui::nvenc_hevc_handler::override_visible_name(const AVCodec*, std::string& name)
void obsffmpeg::ui::nvenc_hevc_handler::adjust_encoder_info(obsffmpeg::encoder_factory*, obsffmpeg::encoder_info* main,
obsffmpeg::encoder_info* fallback)
{
name = "H.265/HEVC Encoder (NVidia NVENC)";
main->readable_name = "H.265/HEVC Nvidia NVENC (Hardware)";
fallback->readable_name = "H.265/HEVC Nvidia NVENC (Software)";
}
void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
AVCodecContext* context, bool)
{
nvenc::get_defaults(settings, codec, context);
@@ -97,8 +79,13 @@ void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const
obs_data_set_default_int(settings, P_HEVC_LEVEL, static_cast<int64_t>(codecs::hevc::level::UNKNOWN));
}
bool obsffmpeg::ui::nvenc_hevc_handler::has_keyframe_support(obsffmpeg::encoder*)
{
return true;
}
void obsffmpeg::ui::nvenc_hevc_handler::get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context)
AVCodecContext* context, bool)
{
if (!context) {
this->get_encoder_properties(props, codec);
@@ -133,6 +120,39 @@ void obsffmpeg::ui::nvenc_hevc_handler::update(obs_data_t* settings, const AVCod
}
}
void obsffmpeg::ui::nvenc_hevc_handler::override_update(obsffmpeg::encoder* instance, obs_data_t* settings)
{
nvenc::override_update(instance, settings);
}
void obsffmpeg::ui::nvenc_hevc_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context)
{
nvenc::log_options(settings, codec, context);
PLOG_INFO("[%s] H.265/HEVC:", codec->name);
ffmpeg::tools::print_av_option_string(context, "profile", " Profile", [](int64_t v) {
profile val = static_cast<profile>(v);
auto index = profiles.find(val);
if (index != profiles.end())
return index->second;
return std::string("<Unknown>");
});
ffmpeg::tools::print_av_option_string(context, "level", " Level", [](int64_t v) {
level val = static_cast<level>(v);
auto index = levels.find(val);
if (index != levels.end())
return index->second;
return std::string("<Unknown>");
});
ffmpeg::tools::print_av_option_string(context, "tier", " Tier", [](int64_t v) {
tier val = static_cast<tier>(v);
auto index = tiers.find(val);
if (index != tiers.end())
return index->second;
return std::string("<Unknown>");
});
}
void obsffmpeg::ui::nvenc_hevc_handler::get_encoder_properties(obs_properties_t* props, const AVCodec* codec)
{
nvenc::get_properties_pre(props, codec);
+18 -7
View File
@@ -33,17 +33,28 @@ extern "C" {
namespace obsffmpeg {
namespace ui {
class nvenc_hevc_handler : public handler {
public:
virtual void override_visible_name(const AVCodec* codec, std::string& name) override;
public /*factory*/:
virtual void adjust_encoder_info(obsffmpeg::encoder_factory* factory,
obsffmpeg::encoder_info* main,
obsffmpeg::encoder_info* fallback);
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
bool hw_encode);
public /*settings*/:
virtual bool has_keyframe_support(obsffmpeg::encoder* instance);
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context) override;
AVCodecContext* context, bool hw_encode);
virtual void update(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
virtual void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
virtual void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
public /*instance*/:
//virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
private:
void get_encoder_properties(obs_properties_t* props, const AVCodec* codec);
+166 -54
View File
@@ -20,7 +20,10 @@
// SOFTWARE.
#include "nvenc_shared.hpp"
#include <algorithm>
#include "codecs/hevc.hpp"
#include "encoder.hpp"
#include "ffmpeg/tools.hpp"
#include "plugin.hpp"
#include "strings.hpp"
#include "utility.hpp"
@@ -57,7 +60,7 @@ extern "C" {
#define ST_RATECONTROL_QP_I ST_RATECONTROL_QP ".I"
#define ST_RATECONTROL_QP_I_INITIAL ST_RATECONTROL_QP_I ".Initial"
#define ST_RATECONTROL_QP_P ST_RATECONTROL_QP ".P"
#define ST_RATECONTROL_QP_ST_INITIAL ST_RATECONTROL_QP_P ".Initial"
#define ST_RATECONTROL_QP_P_INITIAL ST_RATECONTROL_QP_P ".Initial"
#define ST_RATECONTROL_QP_B ST_RATECONTROL_QP ".B"
#define ST_RATECONTROL_QP_B_INITIAL ST_RATECONTROL_QP_B ".Initial"
@@ -131,6 +134,36 @@ std::map<b_ref_mode, std::string> obsffmpeg::nvenc::b_ref_mode_to_opt{
{b_ref_mode::MIDDLE, "middle"},
};
void obsffmpeg::nvenc::override_update(obsffmpeg::encoder* instance, obs_data_t*)
{
AVCodecContext* context = const_cast<AVCodecContext*>(instance->get_avcodeccontext());
int64_t rclookahead = 0;
int64_t surfaces = 0;
int64_t async_depth = 0;
av_opt_get_int(context, "rc-lookahead", AV_OPT_SEARCH_CHILDREN, &rclookahead);
av_opt_get_int(context, "surfaces", AV_OPT_SEARCH_CHILDREN, &surfaces);
av_opt_get_int(context, "async_depth", AV_OPT_SEARCH_CHILDREN, &async_depth);
// Calculate and set the number of surfaces to allocate (if not user overridden).
if (surfaces == 0) {
surfaces = std::max(4ll, (context->max_b_frames + 1ll) * 4ll);
if (rclookahead > 0) {
surfaces = std::max(1ll, std::max(surfaces, rclookahead + (context->max_b_frames + 5ll)));
} else if (context->max_b_frames > 0) {
surfaces = std::max(4ll, (context->max_b_frames + 1ll) * 4ll);
} else {
surfaces = 4;
}
av_opt_set_int(context, "surfaces", surfaces, AV_OPT_SEARCH_CHILDREN);
}
// Set delay
context->delay = static_cast<int>(std::min(std::max(async_depth, 3ll), surfaces - 1));
}
void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
{
obs_data_set_default_int(settings, ST_PRESET, static_cast<int64_t>(preset::DEFAULT));
@@ -138,8 +171,8 @@ void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCode
obs_data_set_default_int(settings, ST_RATECONTROL_MODE, static_cast<int64_t>(ratecontrolmode::CBR_HQ));
obs_data_set_default_int(settings, ST_RATECONTROL_TWOPASS, -1);
obs_data_set_default_int(settings, ST_RATECONTROL_LOOKAHEAD, 0);
obs_data_set_default_bool(settings, ST_RATECONTROL_ADAPTIVEI, true);
obs_data_set_default_bool(settings, ST_RATECONTROL_ADAPTIVEB, true);
obs_data_set_default_int(settings, ST_RATECONTROL_ADAPTIVEI, -1);
obs_data_set_default_int(settings, ST_RATECONTROL_ADAPTIVEB, -1);
obs_data_set_default_int(settings, ST_RATECONTROL_BITRATE_TARGET, 6000);
obs_data_set_default_int(settings, ST_RATECONTROL_BITRATE_MAXIMUM, 6000);
@@ -152,19 +185,19 @@ void obsffmpeg::nvenc::get_defaults(obs_data_t* settings, const AVCodec*, AVCode
obs_data_set_default_int(settings, ST_RATECONTROL_QP_I, 21);
obs_data_set_default_int(settings, ST_RATECONTROL_QP_I_INITIAL, -1);
obs_data_set_default_int(settings, ST_RATECONTROL_QP_P, 21);
obs_data_set_default_int(settings, ST_RATECONTROL_QP_ST_INITIAL, -1);
obs_data_set_default_int(settings, ST_RATECONTROL_QP_P_INITIAL, -1);
obs_data_set_default_int(settings, ST_RATECONTROL_QP_B, 21);
obs_data_set_default_int(settings, ST_RATECONTROL_QP_B_INITIAL, -1);
obs_data_set_default_bool(settings, ST_AQ_SPATIAL, true);
obs_data_set_default_int(settings, ST_AQ_SPATIAL, -1);
obs_data_set_default_int(settings, ST_AQ_STRENGTH, 8);
obs_data_set_default_bool(settings, ST_AQ_TEMPORAL, true);
obs_data_set_default_int(settings, ST_AQ_TEMPORAL, -1);
obs_data_set_default_int(settings, ST_OTHER_BFRAMES, 2);
obs_data_set_default_int(settings, ST_OTHER_BFRAME_REFERENCEMODE, static_cast<int64_t>(b_ref_mode::DISABLED));
obs_data_set_default_bool(settings, ST_OTHER_ZEROLATENCY, false);
obs_data_set_default_bool(settings, ST_OTHER_WEIGHTED_PREDICTION, false);
obs_data_set_default_bool(settings, ST_OTHER_NONREFERENCE_PFRAMES, false);
obs_data_set_default_int(settings, ST_OTHER_ZEROLATENCY, -1);
obs_data_set_default_int(settings, ST_OTHER_WEIGHTED_PREDICTION, -1);
obs_data_set_default_int(settings, ST_OTHER_NONREFERENCE_PFRAMES, -1);
}
static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_data_t* settings)
@@ -211,7 +244,7 @@ static bool modified_ratecontrol(obs_properties_t* props, obs_property_t*, obs_d
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_QP_P), have_qp);
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_QP_B), have_qp);
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_QP_I_INITIAL), have_qp_init);
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_QP_ST_INITIAL), have_qp_init);
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_QP_P_INITIAL), have_qp_init);
obs_property_set_visible(obs_properties_get(props, ST_RATECONTROL_QP_B_INITIAL), have_qp_init);
return true;
@@ -227,7 +260,7 @@ static bool modified_quality(obs_properties_t* props, obs_property_t*, obs_data_
static bool modified_aq(obs_properties_t* props, obs_property_t*, obs_data_t* settings)
{
bool spatial_aq = obs_data_get_bool(settings, ST_AQ_SPATIAL);
bool spatial_aq = obs_data_get_int(settings, ST_AQ_SPATIAL) == 1;
obs_property_set_visible(obs_properties_get(props, ST_AQ_STRENGTH), spatial_aq);
return true;
}
@@ -266,12 +299,9 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode
}
{
auto p = obs_properties_add_list(grp, ST_RATECONTROL_TWOPASS, TRANSLATE(ST_RATECONTROL_TWOPASS),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_RATECONTROL_TWOPASS,
TRANSLATE(ST_RATECONTROL_TWOPASS));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_TWOPASS)));
obs_property_list_add_int(p, TRANSLATE(S_STATE_DEFAULT), -1);
obs_property_list_add_int(p, TRANSLATE(S_STATE_DISABLED), 0);
obs_property_list_add_int(p, TRANSLATE(S_STATE_ENABLED), 1);
}
{
@@ -281,13 +311,13 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode
obs_property_int_set_suffix(p, " frames");
}
{
auto p =
obs_properties_add_bool(grp, ST_RATECONTROL_ADAPTIVEI, TRANSLATE(ST_RATECONTROL_ADAPTIVEI));
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEI,
TRANSLATE(ST_RATECONTROL_ADAPTIVEI));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_ADAPTIVEI)));
}
if (strcmp(codec->name, "h264_nvenc") == 0) {
auto p =
obs_properties_add_bool(grp, ST_RATECONTROL_ADAPTIVEB, TRANSLATE(ST_RATECONTROL_ADAPTIVEB));
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_RATECONTROL_ADAPTIVEB,
TRANSLATE(ST_RATECONTROL_ADAPTIVEB));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_ADAPTIVEB)));
}
}
@@ -379,9 +409,9 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode
obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_QP_P)));
}
{
auto p = obs_properties_add_int_slider(grp, ST_RATECONTROL_QP_ST_INITIAL,
TRANSLATE(ST_RATECONTROL_QP_ST_INITIAL), -1, 51, 1);
obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_QP_ST_INITIAL)));
auto p = obs_properties_add_int_slider(grp, ST_RATECONTROL_QP_P_INITIAL,
TRANSLATE(ST_RATECONTROL_QP_P_INITIAL), -1, 51, 1);
obs_property_set_long_description(p, TRANSLATE(DESC(ST_RATECONTROL_QP_P_INITIAL)));
}
{
auto p = obs_properties_add_int_slider(grp, ST_RATECONTROL_QP_B, TRANSLATE(ST_RATECONTROL_QP_B),
@@ -403,7 +433,7 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode
}
{
auto p = obs_properties_add_bool(grp, ST_AQ_SPATIAL, TRANSLATE(ST_AQ_SPATIAL));
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_AQ_SPATIAL, TRANSLATE(ST_AQ_SPATIAL));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_AQ_SPATIAL)));
obs_property_set_modified_callback(p, modified_aq);
}
@@ -413,7 +443,7 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode
obs_property_set_long_description(p, TRANSLATE(DESC(ST_AQ_STRENGTH)));
}
{
auto p = obs_properties_add_bool(grp, ST_AQ_TEMPORAL, TRANSLATE(ST_AQ_TEMPORAL));
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_AQ_TEMPORAL, TRANSLATE(ST_AQ_TEMPORAL));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_AQ_TEMPORAL)));
}
}
@@ -444,18 +474,19 @@ void obsffmpeg::nvenc::get_properties_post(obs_properties_t* props, const AVCode
}
{
auto p = obs_properties_add_bool(grp, ST_OTHER_ZEROLATENCY, TRANSLATE(ST_OTHER_ZEROLATENCY));
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_OTHER_ZEROLATENCY,
TRANSLATE(ST_OTHER_ZEROLATENCY));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_OTHER_ZEROLATENCY)));
}
{
auto p = obs_properties_add_bool(grp, ST_OTHER_WEIGHTED_PREDICTION,
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_OTHER_WEIGHTED_PREDICTION,
TRANSLATE(ST_OTHER_WEIGHTED_PREDICTION));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_OTHER_WEIGHTED_PREDICTION)));
}
{
auto p = obs_properties_add_bool(grp, ST_OTHER_NONREFERENCE_PFRAMES,
auto p = obsffmpeg::obs_properties_add_tristate(grp, ST_OTHER_NONREFERENCE_PFRAMES,
TRANSLATE(ST_OTHER_NONREFERENCE_PFRAMES));
obs_property_set_long_description(p, TRANSLATE(DESC(ST_OTHER_NONREFERENCE_PFRAMES)));
}
@@ -483,7 +514,7 @@ void obsffmpeg::nvenc::get_runtime_properties(obs_properties_t* props, const AVC
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QP_I), false);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QP_I_INITIAL), false);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QP_P), false);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QP_ST_INITIAL), false);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QP_P_INITIAL), false);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QP_B), false);
obs_property_set_enabled(obs_properties_get(props, ST_RATECONTROL_QP_B_INITIAL), false);
obs_property_set_enabled(obs_properties_get(props, ST_AQ), false);
@@ -523,6 +554,7 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode
av_opt_set(context->priv_data, "rc", rcopt->second.c_str(), 0);
}
av_opt_set_int(context->priv_data, "cbr", 0, 0);
switch (rc) {
case ratecontrolmode::CQP:
have_qp = true;
@@ -548,14 +580,18 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode
}
int la = static_cast<int>(obs_data_get_int(settings, ST_RATECONTROL_LOOKAHEAD));
av_opt_set_int(context->priv_data, "lookahead", la, 0);
av_opt_set_int(context->priv_data, "rc-lookahead", la, 0);
if (la > 0) {
bool adapt_i = obs_data_get_bool(settings, ST_RATECONTROL_ADAPTIVEI);
av_opt_set_int(context->priv_data, "no-scenecut", !adapt_i ? 1 : 0, 0);
int64_t adapt_i = obs_data_get_int(settings, ST_RATECONTROL_ADAPTIVEI);
if (!is_tristate_default(adapt_i)) {
av_opt_set_int(context->priv_data, "no-scenecut", adapt_i, AV_OPT_SEARCH_CHILDREN);
}
if (strcmp(codec->name, "h264_nvenc")) {
bool adapt_b = obs_data_get_bool(settings, ST_RATECONTROL_ADAPTIVEB);
av_opt_set_int(context->priv_data, "b_adapt", adapt_b ? 1 : 0, 0);
int64_t adapt_b = obs_data_get_int(settings, ST_RATECONTROL_ADAPTIVEB);
if (!is_tristate_default(adapt_b)) {
av_opt_set_int(context->priv_data, "b_adapt", adapt_b, AV_OPT_SEARCH_CHILDREN);
}
}
}
@@ -597,44 +633,49 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode
av_opt_set_int(context->priv_data, "init_qpI",
obs_data_get_int(settings, ST_RATECONTROL_QP_I_INITIAL), 0);
av_opt_set_int(context->priv_data, "init_qpP",
obs_data_get_int(settings, ST_RATECONTROL_QP_ST_INITIAL), 0);
obs_data_get_int(settings, ST_RATECONTROL_QP_P_INITIAL), 0);
av_opt_set_int(context->priv_data, "init_qpB",
obs_data_get_int(settings, ST_RATECONTROL_QP_B_INITIAL), 0);
}
}
{ // AQ
bool saq = obs_data_get_bool(settings, ST_AQ_SPATIAL);
bool taq = obs_data_get_bool(settings, ST_AQ_TEMPORAL);
int64_t saq = obs_data_get_int(settings, ST_AQ_SPATIAL);
int64_t taq = obs_data_get_int(settings, ST_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);
if (strcmp(codec->name, "h264_nvenc") == 0) {
if (!is_tristate_default(saq))
av_opt_set_int(context->priv_data, "spatial-aq", saq, 0);
if (!is_tristate_default(taq))
av_opt_set_int(context->priv_data, "temporal-aq", taq, 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);
if (!is_tristate_default(saq))
av_opt_set_int(context->priv_data, "spatial_aq", saq, 0);
if (!is_tristate_default(taq))
av_opt_set_int(context->priv_data, "temporal_aq", taq, 0);
}
if (saq) {
if (is_tristate_enabled(saq))
av_opt_set_int(context->priv_data, "aq-strength",
static_cast<int>(obs_data_get_int(settings, ST_AQ_STRENGTH)), 0);
}
}
{ // Other
bool zl = obs_data_get_bool(settings, ST_OTHER_ZEROLATENCY);
bool wp = obs_data_get_bool(settings, ST_OTHER_WEIGHTED_PREDICTION);
bool nrp = obs_data_get_bool(settings, ST_OTHER_NONREFERENCE_PFRAMES);
int64_t zl = obs_data_get_int(settings, ST_OTHER_ZEROLATENCY);
int64_t wp = obs_data_get_int(settings, ST_OTHER_WEIGHTED_PREDICTION);
int64_t nrp = obs_data_get_int(settings, ST_OTHER_NONREFERENCE_PFRAMES);
context->max_b_frames = static_cast<int>(obs_data_get_int(settings, ST_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 (!is_tristate_default(zl))
av_opt_set_int(context->priv_data, "zerolatency", zl, 0);
if (!is_tristate_default(nrp))
av_opt_set_int(context->priv_data, "nonref_p", nrp, 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);
if ((context->max_b_frames != 0) && is_tristate_enabled(wp)) {
PLOG_WARNING("[%s] Weighted Prediction disabled because of B-Frames being used.", codec->name);
av_opt_set_int(context->priv_data, "weighted_pred", 0, 0);
} else if (!is_tristate_default(wp)) {
av_opt_set_int(context->priv_data, "weighted_pred", wp, 0);
}
{
@@ -646,3 +687,74 @@ void obsffmpeg::nvenc::update(obs_data_t* settings, const AVCodec* codec, AVCode
}
}
}
void obsffmpeg::nvenc::log_options(obs_data_t*, const AVCodec* codec, AVCodecContext* context)
{
PLOG_INFO("[%s] Nvidia NVENC:", codec->name);
ffmpeg::tools::print_av_option_string(context, "preset", " Preset", [](int64_t v) {
preset val = static_cast<preset>(v);
std::string name = "<Unknown>";
auto index = preset_to_opt.find(val);
if (index != preset_to_opt.end())
name = index->second;
return name;
});
ffmpeg::tools::print_av_option_string(context, "rc", " Rate Control", [](int64_t v) {
ratecontrolmode val = static_cast<ratecontrolmode>(v);
std::string name = "<Unknown>";
auto index = ratecontrolmode_to_opt.find(val);
if (index != ratecontrolmode_to_opt.end())
name = index->second;
return name;
});
ffmpeg::tools::print_av_option_bool(context, "2pass", " Two Pass");
ffmpeg::tools::print_av_option_int(context, "rc-lookahead", " Look-Ahead", "Frames");
ffmpeg::tools::print_av_option_bool(context, "no-scenecut", " Adaptive I-Frames");
if (strcmp(codec->name, "h264_nvenc") == 0)
ffmpeg::tools::print_av_option_bool(context, "b_adapt", " Adaptive B-Frames");
PLOG_INFO("[%s] Bitrate:", codec->name);
ffmpeg::tools::print_av_option_int(context, "bitrate", " Target", "bits/sec");
ffmpeg::tools::print_av_option_int(context, "rc_max_rate", " Maximum", "bits/sec");
ffmpeg::tools::print_av_option_int(context, "rc_buffer_size", " Buffer", "bits");
PLOG_INFO("[%s] Quality:", codec->name);
ffmpeg::tools::print_av_option_int(context, "qmin", " Minimum", "");
ffmpeg::tools::print_av_option_int(context, "cq", " Target", "");
ffmpeg::tools::print_av_option_int(context, "qmax", " Maximum", "");
PLOG_INFO("[%s] Quantization Parameters:", codec->name);
ffmpeg::tools::print_av_option_int(context, "init_qpI", " I-Frame", "");
ffmpeg::tools::print_av_option_int(context, "init_qpP", " P-Frame", "");
ffmpeg::tools::print_av_option_int(context, "init_qpB", " B-Frame", "");
ffmpeg::tools::print_av_option_int(context, "max_b_frames", " B-Frames", "Frames");
ffmpeg::tools::print_av_option_string(context, "b_ref_mode", " Reference Mode", [](int64_t v) {
b_ref_mode val = static_cast<b_ref_mode>(v);
std::string name = "<Unknown>";
auto index = b_ref_mode_to_opt.find(val);
if (index != b_ref_mode_to_opt.end())
name = index->second;
return name;
});
PLOG_INFO("[%s] Adaptive Quantization:", codec->name);
if (strcmp(codec->name, "h264_nvenc") == 0) {
ffmpeg::tools::print_av_option_bool(context, "spatial-aq", " Spatial AQ");
ffmpeg::tools::print_av_option_int(context, "aq-strength", " Strength", "");
ffmpeg::tools::print_av_option_bool(context, "temporal-aq", " Temporal AQ");
} else {
ffmpeg::tools::print_av_option_bool(context, "spatial_aq", " Spatial AQ");
ffmpeg::tools::print_av_option_int(context, "aq-strength", " Strength", "");
ffmpeg::tools::print_av_option_bool(context, "temporal_aq", " Temporal AQ");
}
PLOG_INFO("[%s] Other:", codec->name);
ffmpeg::tools::print_av_option_bool(context, "zerolatency", " Zero Latency");
ffmpeg::tools::print_av_option_bool(context, "weighted_pred", " Weighted Prediction");
ffmpeg::tools::print_av_option_bool(context, "nonref_p", " Non-reference P-Frames");
ffmpeg::tools::print_av_option_bool(context, "strict_gop", " Strict GOP");
ffmpeg::tools::print_av_option_bool(context, "aud", " Access Unit Delimiters");
ffmpeg::tools::print_av_option_bool(context, "bluray-compat", " Bluray Compatibility");
if (strcmp(codec->name, "h264_nvenc") == 0)
ffmpeg::tools::print_av_option_bool(context, "a53cc", " A53 Closed Captions");
ffmpeg::tools::print_av_option_int(context, "dpb_size", " DPB Size", "");
}
+12
View File
@@ -32,6 +32,8 @@ extern "C" {
}
namespace obsffmpeg {
class encoder;
namespace nvenc {
enum class preset : int64_t {
DEFAULT,
@@ -46,6 +48,8 @@ namespace obsffmpeg {
LOW_LATENCY_HIGH_QUALITY,
LOSSLESS,
LOSSLESS_HIGH_PERFORMANCE,
// Append things before this.
INVALID = -1,
};
enum class ratecontrolmode : int64_t {
@@ -55,12 +59,16 @@ namespace obsffmpeg {
CBR,
CBR_HQ,
CBR_LD_HQ,
// Append things before this.
INVALID = -1,
};
enum class b_ref_mode : int64_t {
DISABLED,
EACH,
MIDDLE,
// Append things before this.
INVALID = -1,
};
extern std::map<preset, std::string> presets;
@@ -75,6 +83,8 @@ namespace obsffmpeg {
extern std::map<b_ref_mode, std::string> b_ref_mode_to_opt;
void override_update(obsffmpeg::encoder* instance, obs_data_t* settings);
void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
void get_properties_pre(obs_properties_t* props, const AVCodec* codec);
@@ -84,5 +94,7 @@ namespace obsffmpeg {
void get_runtime_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context);
void update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
void log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
} // namespace nvenc
} // namespace obsffmpeg
+25 -3
View File
@@ -36,7 +36,7 @@ INITIALIZER(prores_aw_handler_init)
};
void obsffmpeg::ui::prores_aw_handler::override_colorformat(AVPixelFormat& target_format, obs_data_t* settings,
const AVCodec* codec, AVCodecContext* context)
const AVCodec* codec, AVCodecContext*)
{
std::string profile = "";
@@ -60,13 +60,13 @@ void obsffmpeg::ui::prores_aw_handler::override_colorformat(AVPixelFormat& targe
}
}
void obsffmpeg::ui::prores_aw_handler::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*)
void obsffmpeg::ui::prores_aw_handler::get_defaults(obs_data_t* settings, const AVCodec*, AVCodecContext*, bool)
{
obs_data_set_default_int(settings, P_PRORES_PROFILE, 0);
}
void obsffmpeg::ui::prores_aw_handler::get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context)
AVCodecContext* context, bool)
{
if (!context) {
auto p = obs_properties_add_list(props, P_PRORES_PROFILE, TRANSLATE(P_PRORES_PROFILE),
@@ -104,3 +104,25 @@ void obsffmpeg::ui::prores_aw_handler::update(obs_data_t* settings, const AVCode
{
context->profile = static_cast<int>(obs_data_get_int(settings, P_PRORES_PROFILE));
}
void obsffmpeg::ui::prores_aw_handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext*)
{
for (auto ptr = codec->profiles; ptr->profile != FF_PROFILE_UNKNOWN; ptr++) {
if (ptr->profile == static_cast<int>(obs_data_get_int(settings, P_PRORES_PROFILE)))
PLOG_INFO("[%s] Profile: %s", codec->name, ptr->name);
}
}
void obsffmpeg::ui::prores_aw_handler::process_avpacket(AVPacket& packet, const AVCodec*, AVCodecContext*)
{
//FFmpeg Bug:
// When ProRes content is stored in Matroska, FFmpeg strips the size
// from the atom. Later when the ProRes content is demuxed from Matroska,
// FFmpeg creates an atom with the incorrect size, as the ATOM size
// should be content + atom, but FFmpeg set it to only be content. This
// difference leads to decoders to be off by 8 bytes.
//Fix (until FFmpeg stops being broken):
// Pad the packet with 8 bytes of 0x00.
av_grow_packet(&packet, 8);
}
+9 -3
View File
@@ -37,14 +37,20 @@ namespace obsffmpeg {
virtual void override_colorformat(AVPixelFormat& target_format, obs_data_t* settings,
const AVCodec* codec, AVCodecContext* context) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context,
bool hw_encode) override;
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context) override;
AVCodecContext* context, bool hw_encode) override;
virtual void update(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void log_options(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
virtual void process_avpacket(AVPacket& packet, const AVCodec* codec,
AVCodecContext* context) override;
};
} // namespace ui
} // namespace obsffmpeg
+13
View File
@@ -18,3 +18,16 @@
// 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 "utility.hpp"
#include "strings.hpp"
#include "plugin.hpp"
obs_property_t* obsffmpeg::obs_properties_add_tristate(obs_properties_t* props, const char* name, const char* desc)
{
obs_property_t* p = obs_properties_add_list(props, name, desc, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, TRANSLATE(S_STATE_DEFAULT), -1);
obs_property_list_add_int(p, TRANSLATE(S_STATE_DISABLED), 0);
obs_property_list_add_int(p, TRANSLATE(S_STATE_ENABLED), 1);
return p;
}
+25
View File
@@ -87,4 +87,29 @@ namespace obsffmpeg {
{
return obs_get_version() < MAKE_SEMANTIC_VERSION(24, 0, 0);
}
struct obs_graphics {
obs_graphics()
{
obs_enter_graphics();
}
~obs_graphics()
{
obs_leave_graphics();
}
};
obs_property_t* obs_properties_add_tristate(obs_properties_t* props, const char* name, const char* desc);
inline bool is_tristate_enabled(int64_t tristate) {
return tristate == 1;
}
inline bool is_tristate_disabled(int64_t tristate) {
return tristate == 0;
}
inline bool is_tristate_default(int64_t tristate) {
return tristate == -1;
}
} // namespace obsffmpeg