Initial code (pre-GitHub)

Contains:
- ffmpeg object wrappers
- base encoder class
- Apply ProRes encoder (prores_aw)
- OBS plugin structure
This commit is contained in:
Michael Fabian 'Xaymar' Dirks
2018-11-13 19:04:13 +01:00
parent e1d41695a2
commit ec75fe23fe
24 changed files with 2515 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
# Basic Formatting
TabWidth: 8
UseTab: ForIndentation
ColumnLimit: 120
# Language
Language: Cpp
Standard: Cpp11
# Indentation
AccessModifierOffset: 0
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
IndentCaseLabels: false
#IndentPPDirectives: true
IndentWidth: 8
IndentWrappedFunctionNames: true
NamespaceIndentation: All
# Includes
#IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<'
Priority: 1
- Regex: '^"'
Priority: 2
SortIncludes: true
# Alignment
AlignAfterOpenBracket: true
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: DontAlign
AlignOperands: true
AlignTrailingComments: true
DerivePointerAlignment: false
PointerAlignment: Left
# Wrapping and Breaking
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
# AfterExternBlock: false
AfterFunction: true
AfterNamespace: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
#BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false
Cpp11BracedListStyle: true
# Spaces
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCpp11BracedList: false
#SpaceBeforeCtorInitializerColon: true
#SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
# Other
CommentPragmas: '^(!FIXME!|!TODO!|ToDo:)'
CompactNamespaces: false
DisableFormat: false
FixNamespaceComments: true
#ForEachMacros: ''
KeepEmptyLinesAtTheStartOfBlocks: false
ReflowComments: false
SortUsingDeclarations: true
+389
View File
@@ -0,0 +1,389 @@
# A Plugin that integrates the AMD AMF encoder into OBS Studio
# Copyright (C) 2016 - 2017 Michael Fabian Dirks
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# CMake Setup
cmake_minimum_required(VERSION 3.1.0)
include("cmake/util.cmake")
# Define Project
project(
enc-ffmpeg
VERSION 1.0.0.0
)
set(PROJECT_FULL_NAME "FFMPEG Encoder for OBS Studio")
set(PROJECT_DESCRIPTION "Plugin for OBS Studio to add FFMPEG options for Recording and Streaming")
set(PROJECT_AUTHORS "Michael Fabian 'Xaymar' Dirks <info@xaymar.com>")
set(PROJECT_COPYRIGHT_YEARS "2018")
################################################################################
# CMake / Compiler
################################################################################
# Detect Build Type
if("${CMAKE_SOURCE_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
set(PropertyPrefix "")
else()
set(PropertyPrefix "${PROJECT_NAME}_")
endif()
# Detect Architecture
math(EXPR BITS "8*${CMAKE_SIZEOF_VOID_P}")
if("${BITS}" STREQUAL "32")
set(ARCH "x86")
else()
set(ARCH "x64")
endif()
# Configure Version Header
configure_file(
"${PROJECT_SOURCE_DIR}/cmake/version.hpp.in"
"${PROJECT_BINARY_DIR}/source/version.hpp"
)
configure_file(
"${PROJECT_SOURCE_DIR}/cmake/module.cpp.in"
"${PROJECT_BINARY_DIR}/source/module.cpp"
)
# Windows Specific Resource Definition
if(WIN32)
set(PROJECT_PRODUCT_NAME "${PROJECT_FULL_NAME}")
set(PROJECT_COMPANY_NAME "${PROJECT_AUTHORS}")
set(PROJECT_COPYRIGHT "${PROJECT_AUTHORS} © ${PROJECT_COPYRIGHT_YEARS}")
set(PROJECT_LEGAL_TRADEMARKS_1 "")
set(PROJECT_LEGAL_TRADEMARKS_2 "")
configure_file(
"${PROJECT_SOURCE_DIR}/cmake/version.rc.in"
"${PROJECT_BINARY_DIR}/cmake/version.rc"
@ONLY
)
endif()
# All Warnings, Extra Warnings, Pedantic
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
# Update if necessary
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic")
endif()
math(EXPR BITS "8*${CMAKE_SIZEOF_VOID_P}")
################################################################################
# Options
################################################################################
set(${PropertyPrefix}OBS_NATIVE FALSE CACHE BOOL "Use native obs-studio build" FORCE)
set(${PropertyPrefix}OBS_REFERENCE FALSE CACHE BOOL "Use referenced obs-studio build" FORCE)
set(${PropertyPrefix}OBS_PACKAGE FALSE CACHE BOOL "Use packaged obs-studio build" FORCE)
set(${PropertyPrefix}OBS_DOWNLOAD FALSE CACHE BOOL "Use downloaded obs-studio build" FORCE)
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 "22.0.2" CACHE STRING "OBS Studio Version to download")
endif()
if(NOT ${PropertyPrefix}OBS_NATIVE)
set(CMAKE_PACKAGE_PREFIX "${CMAKE_BINARY_DIR}" CACHE PATH "Path for generated archives.")
set(CMAKE_PACKAGE_NAME "${PROJECT_NAME}" CACHE STRING "Name for the generated archives.")
set(CMAKE_PACKAGE_SUFFIX_OVERRIDE "" CACHE STRING "Override for the suffix.")
endif()
################################################################################
# Dependencies
################################################################################
# Detect OBS Studio Type
if(TARGET libobs)
message(STATUS "${PROJECT_NAME}: Using native obs-studio.")
CacheSet(${PropertyPrefix}OBS_NATIVE TRUE)
else()
CacheSet(${PropertyPrefix}OBS_NATIVE FALSE)
if(EXISTS "${OBS_STUDIO_DIR}/cmake/LibObs/LibObsConfig.cmake")
message(STATUS "${PROJECT_NAME}: Using packaged obs-studio.")
CacheSet(${PropertyPrefix}OBS_PACKAGE TRUE)
elseif(EXISTS "${OBS_STUDIO_DIR}/libobs/obs-module.h")
message(STATUS "${PROJECT_NAME}: Using referenced obs-studio.")
CacheSet(${PropertyPrefix}OBS_REFERENCE TRUE)
else()
message(STATUS "${PROJECT_NAME}: No OBS Studio detected, using downloadable prebuilt binaries.")
CacheSet(${PropertyPrefix}OBS_DOWNLOAD TRUE)
set(${PropertyPrefix}OBS_DOWNLOAD_URL "https://github.com/Xaymar/obs-studio/releases/download/${OBS_DOWNLOAD_VERSION}/obs-studio-${ARCH}-vs2017.7z")
endif()
endif()
# CMake Modules
if(${PropertyPrefix}OBS_DOWNLOAD)
include("cmake/DownloadProject.cmake")
endif()
if(NOT ${PropertyPrefix}OBS_NATIVE)
include("cmake/cppcheck.cmake")
endif()
# Load OBS Studio
if(${PropertyPrefix}OBS_NATIVE)
Option(BUILD_FFMPEG_ENCODER "Build AMD Encoder module" ON)
if (NOT BUILD_FFMPEG_ENCODER)
message(STATUS "Not building AMD Encoder")
return()
endif()
elseif(${PropertyPrefix}OBS_PACKAGE)
include("${OBS_STUDIO_DIR}/cmake/LibObs/LibObsConfig.cmake")
elseif(${PropertyPrefix}OBS_REFERENCE)
set(obsPath "${OBS_STUDIO_DIR}")
include("${OBS_STUDIO_DIR}/cmake/external/Findlibobs.cmake")
elseif(${PropertyPrefix}OBS_DOWNLOAD)
download_project(
PROJ libobs
URL ${OBS_DOWNLOAD_URL}
UPDATE_DISCONNECTED 1
)
include("${libobs_SOURCE_DIR}/cmake/LibObs/LibObsConfig.cmake")
else()
message(CRITICAL "Impossible case reached, very system stability.")
return()
endif()
# FFmpeg
find_package(FFmpeg REQUIRED COMPONENTS avutil avcodec swscale)
################################################################################
# Code
################################################################################
set(PROJECT_PRIVATE
"${PROJECT_SOURCE_DIR}/source/encoder.cpp"
"${PROJECT_SOURCE_DIR}/source/encoder.hpp"
"${PROJECT_SOURCE_DIR}/source/plugin.cpp"
"${PROJECT_SOURCE_DIR}/source/plugin.hpp"
"${PROJECT_SOURCE_DIR}/source/utility.cpp"
"${PROJECT_SOURCE_DIR}/source/utility.hpp"
"${PROJECT_SOURCE_DIR}/source/encoders/prores_aw.hpp"
"${PROJECT_SOURCE_DIR}/source/encoders/prores_aw.cpp"
"${PROJECT_SOURCE_DIR}/source/encoders/prores_ks.hpp"
"${PROJECT_SOURCE_DIR}/source/encoders/prores_ks.cpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/avframe-queue.cpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/avframe-queue.hpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/swscale.hpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/swscale.cpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/tools.hpp"
"${PROJECT_SOURCE_DIR}/source/ffmpeg/tools.cpp"
)
SET(PROJECT_GENERATED
"${PROJECT_BINARY_DIR}/source/module.cpp"
"${PROJECT_BINARY_DIR}/source/version.hpp"
)
set(PROJECT_DATA
"${PROJECT_SOURCE_DIR}/data/locale/en-US.ini"
"${PROJECT_SOURCE_DIR}/LICENSE"
)
set(PROJECT_LIBRARIES
)
# Source Grouping
source_group(TREE "${PROJECT_SOURCE_DIR}" PREFIX "Data Files" FILES ${PROJECT_DATA})
source_group(TREE "${PROJECT_SOURCE_DIR}/source" PREFIX "Private Files" FILES ${PROJECT_PRIVATE})
source_group(TREE "${PROJECT_BINARY_DIR}/source" PREFIX "Generated Files" FILES ${PROJECT_GENERATED})
################################################################################
# Target
################################################################################
add_library(${PROJECT_NAME} MODULE
${PROJECT_GENERATED}
${PROJECT_PRIVATE}
${PROJECT_DATA}
)
# Include Directories
target_include_directories(${PROJECT_NAME}
PUBLIC
PRIVATE
"${PROJECT_BINARY_DIR}/source"
"${PROJECT_SOURCE_DIR}/source"
${FFMPEG_INCLUDE_DIRS}
)
# OBS Studio
if(${PropertyPrefix}OBS_NATIVE)
target_link_libraries(${PROJECT_NAME}
libobs
)
elseif(${PropertyPrefix}OBS_REFERENCE)
target_include_directories(${PROJECT_NAME}
PRIVATE
"${OBS_STUDIO_DIR}/libobs"
)
target_link_libraries(${PROJECT_NAME}
"${LIBOBS_LIB}"
)
elseif(${PropertyPrefix}OBS_PACKAGE)
target_include_directories(${PROJECT_NAME}
PRIVATE
"${OBS_STUDIO_DIR}/include"
)
target_link_libraries(${PROJECT_NAME}
libobs
)
elseif(${PropertyPrefix}OBS_DOWNLOAD)
target_link_libraries(${PROJECT_NAME}
libobs
)
endif()
# Link Libraries
target_link_libraries(${PROJECT_NAME}
"${PROJECT_LIBRARIES}"
${FFMPEG_LIBRARIES}
)
# Definitions
if (WIN32)
target_compile_definitions(${PROJECT_NAME}
PRIVATE
_CRT_SECURE_NO_WARNINGS
# windows.h
WIN32_LEAN_AND_MEAN
NOGPICAPMASKS
NOVIRTUALKEYCODES
#NOWINMESSAGES
NOWINSTYLES
NOSYSMETRICS
NOMENUS
NOICONS
NOKEYSTATES
NOSYSCOMMANDS
NORASTEROPS
NOSHOWWINDOW
NOATOM
NOCLIPBOARD
NOCOLOR
NOCTLMGR
NODRAWTEXT
#NOGDI
NOKERNEL
#NOUSER
#NONLS
NOMB
NOMEMMGR
NOMETAFILE
NOMINMAX
#NOMSG
NOOPENFILE
NOSCROLL
NOSERVICE
NOSOUND
#NOTEXTMETRIC
NOWH
NOWINOFFSETS
NOCOMM
NOKANJI
NOHELP
NOPROFILER
NODEFERWINDOWPOS
NOMCX
NOIME
NOMDI
NOINOUT
)
endif()
# File Version
if(WIN32)
set_target_properties(
${PROJECT_NAME}
PROPERTIES
VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.${PROJECT_VERSION_TWEAK}
SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.${PROJECT_VERSION_TWEAK}
)
else()
set_target_properties(
${PROJECT_NAME}
PROPERTIES
VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.${PROJECT_VERSION_TWEAK}
SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.${PROJECT_VERSION_TWEAK}
)
endif()
# CPPCheck
if(NOT ${PropertyPrefix}OBS_NATIVE)
set(excludes )
list(APPEND excludes "${PROJECT_SOURCE_DIR}/AMF")
if(${PropertyPrefix}OBS_REFERENCE)
list(APPEND excludes "${OBS_STUDIO_DIR}/libobs")
elseif(${PropertyPrefix}OBS_PACKAGE)
list(APPEND excludes "${OBS_STUDIO_DIR}/libobs")
elseif(${PropertyPrefix}OBS_DOWNLOAD)
list(APPEND excludes "${libobs_SOURCE_DIR}")
endif()
cppcheck(
EXCLUDE ${excludes}
)
cppcheck_add_project(${PROJECT_NAME})
endif()
################################################################################
# Installation
################################################################################
if(${PropertyPrefix}OBS_NATIVE)
install_obs_plugin_with_data(${PROJECT_NAME} data)
else()
install(
TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION "./obs-plugins/${BITS}bit/" COMPONENT Runtime
LIBRARY DESTINATION "./obs-plugins/${BITS}bit/" COMPONENT Runtime
)
if(MSVC)
install(
FILES $<TARGET_PDB_FILE:${PROJECT_NAME}>
DESTINATION "./obs-plugins/${BITS}bit/"
OPTIONAL
)
endif()
install(
DIRECTORY "${PROJECT_SOURCE_DIR}/resources/"
DESTINATION "./data/obs-plugins/${PROJECT_NAME}/"
)
if("${CMAKE_PACKAGE_SUFFIX_OVERRIDE}" STREQUAL "")
set(PackageFullName "${CMAKE_PACKAGE_PREFIX}/${CMAKE_PACKAGE_NAME}-${PROJECT_VERSION}")
else()
set(PackageFullName "${CMAKE_PACKAGE_PREFIX}/${CMAKE_PACKAGE_NAME}-${CMAKE_PACKAGE_SUFFIX_OVERRIDE}")
endif()
add_custom_target(
PACKAGE_7Z
${CMAKE_COMMAND} -E tar cfv "${PackageFullName}.7z" --format=7zip --
"${CMAKE_INSTALL_PREFIX}/obs-plugins"
"${CMAKE_INSTALL_PREFIX}/data"
WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}"
)
add_custom_target(
PACKAGE_ZIP
${CMAKE_COMMAND} -E tar cfv "${PackageFullName}.zip" --format=zip --
"${CMAKE_INSTALL_PREFIX}/obs-plugins"
"${CMAKE_INSTALL_PREFIX}/data"
WORKING_DIRECTORY "${CMAKE_INSTALL_PREFIX}"
)
endif()
+17
View File
@@ -0,0 +1,17 @@
# Distributed under the OSI-approved MIT License. See accompanying
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
cmake_minimum_required(VERSION 2.8.2)
project(${DL_ARGS_PROJ}-download NONE)
include(ExternalProject)
ExternalProject_Add(${DL_ARGS_PROJ}-download
${DL_ARGS_UNPARSED_ARGUMENTS}
SOURCE_DIR "${DL_ARGS_SOURCE_DIR}"
BINARY_DIR "${DL_ARGS_BINARY_DIR}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
+182
View File
@@ -0,0 +1,182 @@
# Distributed under the OSI-approved MIT License. See accompanying
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
#
# MODULE: DownloadProject
#
# PROVIDES:
# download_project( PROJ projectName
# [PREFIX prefixDir]
# [DOWNLOAD_DIR downloadDir]
# [SOURCE_DIR srcDir]
# [BINARY_DIR binDir]
# [QUIET]
# ...
# )
#
# Provides the ability to download and unpack a tarball, zip file, git repository,
# etc. at configure time (i.e. when the cmake command is run). How the downloaded
# and unpacked contents are used is up to the caller, but the motivating case is
# to download source code which can then be included directly in the build with
# add_subdirectory() after the call to download_project(). Source and build
# directories are set up with this in mind.
#
# The PROJ argument is required. The projectName value will be used to construct
# the following variables upon exit (obviously replace projectName with its actual
# value):
#
# projectName_SOURCE_DIR
# projectName_BINARY_DIR
#
# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically
# need to be provided. They can be specified if you want the downloaded source
# and build directories to be located in a specific place. The contents of
# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the
# locations used whether you provide SOURCE_DIR/BINARY_DIR or not.
#
# The DOWNLOAD_DIR argument does not normally need to be set. It controls the
# location of the temporary CMake build used to perform the download.
#
# The PREFIX argument can be provided to change the base location of the default
# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments
# are provided, then PREFIX will have no effect. The default value for PREFIX is
# CMAKE_BINARY_DIR.
#
# The QUIET option can be given if you do not want to show the output associated
# with downloading the specified project.
#
# In addition to the above, any other options are passed through unmodified to
# ExternalProject_Add() to perform the actual download, patch and update steps.
# The following ExternalProject_Add() options are explicitly prohibited (they
# are reserved for use by the download_project() command):
#
# CONFIGURE_COMMAND
# BUILD_COMMAND
# INSTALL_COMMAND
# TEST_COMMAND
#
# Only those ExternalProject_Add() arguments which relate to downloading, patching
# and updating of the project sources are intended to be used. Also note that at
# least one set of download-related arguments are required.
#
# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to
# prevent a check at the remote end for changes every time CMake is run
# after the first successful download. See the documentation of the ExternalProject
# module for more information. It is likely you will want to use this option if it
# is available to you. Note, however, that the ExternalProject implementation contains
# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when
# using the URL download method or when specifying a SOURCE_DIR with no download
# method. Fixes for these have been created, the last of which is scheduled for
# inclusion in CMake 3.8.0. Details can be found here:
#
# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c
# https://gitlab.kitware.com/cmake/cmake/issues/16428
#
# If you experience build errors related to the update step, consider avoiding
# the use of UPDATE_DISCONNECTED.
#
# EXAMPLE USAGE:
#
# include(DownloadProject)
# download_project(PROJ googletest
# GIT_REPOSITORY https://github.com/google/googletest.git
# GIT_TAG master
# UPDATE_DISCONNECTED 1
# QUIET
# )
#
# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
#
#========================================================================================
set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}")
include(CMakeParseArguments)
function(download_project)
set(options QUIET)
set(oneValueArgs
PROJ
PREFIX
DOWNLOAD_DIR
SOURCE_DIR
BINARY_DIR
# Prevent the following from being passed through
CONFIGURE_COMMAND
BUILD_COMMAND
INSTALL_COMMAND
TEST_COMMAND
)
set(multiValueArgs "")
cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Hide output if requested
if (DL_ARGS_QUIET)
set(OUTPUT_QUIET "OUTPUT_QUIET")
else()
unset(OUTPUT_QUIET)
message(STATUS "Downloading/updating ${DL_ARGS_PROJ}")
endif()
# Set up where we will put our temporary CMakeLists.txt file and also
# the base point below which the default source and binary dirs will be.
# The prefix must always be an absolute path.
if (NOT DL_ARGS_PREFIX)
set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}")
else()
get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE
BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if (NOT DL_ARGS_DOWNLOAD_DIR)
set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download")
endif()
# Ensure the caller can know where to find the source and build directories
if (NOT DL_ARGS_SOURCE_DIR)
set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src")
endif()
if (NOT DL_ARGS_BINARY_DIR)
set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build")
endif()
set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE)
set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE)
# The way that CLion manages multiple configurations, it causes a copy of
# the CMakeCache.txt to be copied across due to it not expecting there to
# be a project within a project. This causes the hard-coded paths in the
# cache to be copied and builds to fail. To mitigate this, we simply
# remove the cache if it exists before we configure the new project. It
# is safe to do so because it will be re-generated. Since this is only
# executed at the configure step, it should not cause additional builds or
# downloads.
file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt")
# Create and build a separate CMake project to carry out the download.
# If we've already previously done these steps, they will not cause
# anything to be updated, so extra rebuilds of the project won't occur.
# Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
# has this set to something not findable on the PATH.
configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in"
"${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt")
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
-D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}"
.
RESULT_VARIABLE result
${OUTPUT_QUIET}
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
)
if(result)
message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
${OUTPUT_QUIET}
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
)
if(result)
message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}")
endif()
endfunction()
+234
View File
@@ -0,0 +1,234 @@
set(CPPCHECK_PROJECTS "")
set(CPPCHECK_ARGUMENTS "")
set(CPPCHECK_PLATFORM "")
set(CPPCHECK_LIBRARIES "")
include(CMakeParseArguments)
function(cppcheck)
set(CPPCHECK_PATH "" CACHE PATH "Path to cppcheck binary")
set(CPPCHECK_BIN "cppcheck.exe" CACHE STRING "CPPCheck Binary File")
set(CPPCHECK_ENABLE_INCONCLUSIVE OFF CACHE BOOL "Enable inconclusive checks?")
set(CPPCHECK_ENABLE_MISSING_INCLUDE ON CACHE BOOL "Check for missing includes?")
set(CPPCHECK_ENABLE_UNUSED_FUNCTION OFF CACHE BOOL "Check for unused functions?")
set(CPPCHECK_ENABLE_INFORMATION ON CACHE BOOL "Enable information messages?")
set(CPPCHECK_ENABLE_PORTABILITY ON CACHE BOOL "Enable portability messages?")
set(CPPCHECK_ENABLE_PERFORMANCE ON CACHE BOOL "Enable performance messages?")
set(CPPCHECK_ENABLE_WARNING ON CACHE BOOL "Enable warning messages?")
set(CPPCHECK_STD_POSIX OFF CACHE BOOL "POSIX Standard Compatibility Checks")
set(CPPCHECK_STD_C89 OFF CACHE BOOL "C89 Standard Compatibility Checks")
set(CPPCHECK_STD_C99 OFF CACHE BOOL "C99 Standard Compatibility Checks")
set(CPPCHECK_STD_C11 ON CACHE BOOL "C11 Standard Compatibility Checks")
set(CPPCHECK_STD_CPP03 OFF CACHE BOOL "C++03 Standard Compatibility Checks")
set(CPPCHECK_STD_CPP11 OFF CACHE BOOL "C++11 Standard Compatibility Checks")
set(CPPCHECK_STD_CPP14 ON CACHE BOOL "C++14 Standard Compatibility Checks")
set(CPPCHECK_FORCE_C OFF CACHE BOOL "Force checking with C language")
set(CPPCHECK_FORCE_CPP OFF CACHE BOOL "Force checking with C++ language (overrides CPPCHECK_FORCE_C)")
set(CPPCHECK_VERBOSE ON CACHE BOOL "Show more detailed error reports")
set(CPPCHECK_QUIET ON CACHE BOOL "Hide progress reports")
set(CPPCHECK_LIBRARIES "" CACHE STRING "List of Libraries to load separated by semicolon")
set(CPPCHECK_EXCLUDE_DIRECTORIES "" CACHE STRING "List of directories to exclude separated by semicolon")
set(CPPCHECK_PARALLEL_TASKS "4" CACHE STRING "Number of threads to use for cppcheck")
if(WIN32)
set(CPPCHECK_WIN32_UNICODE ON CACHE BOOL "Use Unicode character encoding for Win32")
endif()
mark_as_advanced(CPPCHECK_BIN CPPCHECK_QUIET CPPCHECK_VERBOSE CPPCHECK_LIBRARIES CPPCHECK_ENABLE_INCONCLUSIVE CPPCHECK_PARALLEL_TASKS)
# Parse arguments
set(cppcheck_options )
set(cppcheck_oneval )
set(cppcheck_mulval EXCLUDE)
cmake_parse_arguments(
CPPCHECKP
"${cppcheck_options}"
"${cppcheck_oneval}"
"${cppcheck_mulval}"
${ARGN}
)
# Detect Architecture (Bitness)
math(EXPR BITS "8*${CMAKE_SIZEOF_VOID_P}")
# Detect Platform
if(WIN32)
if(BITS EQUAL "32")
if(CPPCHECK_WIN32_UNICODE)
set(CPPCHECK_PLATFORM "win32W")
else()
set(CPPCHECK_PLATFORM "win32A")
endif()
else()
set(CPPCHECK_PLATFORM "win64")
endif()
elseif(("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") OR ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") OR APPLE)
if(BITS EQUAL "32")
set(CPPCHECK_PLATFORM "unix32")
else()
set(CPPCHECK_PLATFORM "unix64")
endif()
else()
set(CPPCHECK_PLATFORM "unspecified")
endif()
if(WIN32)
list(APPEND CPPCHECK_LIBRARIES "windows")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
list(APPEND CPPCHECK_LIBRARIES "bsd")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
list(APPEND CPPCHECK_LIBRARIES "gnu")
endif()
# Arguments
set(CPPCHECK_ARGUMENTS "")
# Compiler
if(MSVC)
#list(APPEND CPPCHECK_ARGUMENTS --template="{file}|{line}|{severity}|{id}|{message}")
endif()
# Flags
if(CPPCHECK_ENABLE_INCONCLUSIVE)
list(APPEND CPPCHECK_ARGUMENTS --inconclusive)
endif()
if(CPPCHECK_VERBOSE)
list(APPEND CPPCHECK_ARGUMENTS -v)
endif()
if(CPPCHECK_QUIET)
list(APPEND CPPCHECK_ARGUMENTS -q)
endif()
if(CPPCHECK_PLATFORM)
list(APPEND CPPCHECK_ARGUMENTS --platform=${CPPCHECK_PLATFORM})
endif()
if(CPPCHECK_PARALLEL_TASKS)
list(APPEND CPPCHECK_ARGUMENTS -j ${CPPCHECK_PARALLEL_TASKS})
endif()
# Libraries
foreach(_library ${CPPCHECK_LIBRARIES})
list(APPEND CPPCHECK_ARGUMENTS --library=${_library})
endforeach()
# Exclusion
foreach(_path ${CPPCHECK_EXCLUDE_DIRECTORIES})
file(TO_NATIVE_PATH "${_path}" _npath)
if(MSVC)
list(APPEND CPPCHECK_ARGUMENTS --suppress=*:${_npath}\\*)
else()
list(APPEND CPPCHECK_ARGUMENTS -i${_npath})
endif()
endforeach()
if(CPPCHECKP_EXCLUDE)
foreach(_path ${CPPCHECKP_EXCLUDE})
file(TO_NATIVE_PATH "${_path}" _npath)
if(MSVC)
list(APPEND CPPCHECK_ARGUMENTS --suppress=*:${_npath}\\*)
else()
list(APPEND CPPCHECK_ARGUMENTS -i${_npath})
endif()
endforeach()
endif()
# Checks
if(CPPCHECK_ENABLE_MISSING_INCLUDE)
list(APPEND CPPCHECK_ARGUMENTS --enable=missingInclude)
endif()
if(CPPCHECK_ENABLE_UNUSED_FUNCTION)
list(APPEND CPPCHECK_ARGUMENTS --enable=unusedFunction)
endif()
if(CPPCHECK_ENABLE_INFORMATION)
list(APPEND CPPCHECK_ARGUMENTS --enable=information)
endif()
if(CPPCHECK_ENABLE_PORTABILITY)
list(APPEND CPPCHECK_ARGUMENTS --enable=portability)
endif()
if(CPPCHECK_ENABLE_PERFORMANCE)
list(APPEND CPPCHECK_ARGUMENTS --enable=performance)
endif()
if(CPPCHECK_ENABLE_WARNING)
list(APPEND CPPCHECK_ARGUMENTS --enable=warning)
endif()
# Std
if(CPPCHECK_STD_POSIX)
list(APPEND CPPCHECK_ARGUMENTS --std=posix)
endif()
if(CPPCHECK_STD_C89)
list(APPEND CPPCHECK_ARGUMENTS --std=c89)
endif()
if(CPPCHECK_STD_C99)
list(APPEND CPPCHECK_ARGUMENTS --std=c99)
endif()
if(CPPCHECK_STD_C11)
list(APPEND CPPCHECK_ARGUMENTS --std=c11)
endif()
if(CPPCHECK_STD_CPP03)
list(APPEND CPPCHECK_ARGUMENTS --std=c++03)
endif()
if(CPPCHECK_STD_CPP11)
list(APPEND CPPCHECK_ARGUMENTS --std=c++11)
endif()
if(CPPCHECK_STD_CPP14)
list(APPEND CPPCHECK_ARGUMENTS --std=c++14)
endif()
# Force Language
if(CPPCHECK_FORCE_CPP)
list(APPEND CPPCHECK_ARGUMENTS --language=c++)
elseif(CPPCHECK_FORCE_C)
list(APPEND CPPCHECK_ARGUMENTS --language=c)
endif()
add_custom_target(
CPPCHECK
)
# Propagate to parent scope
set(CPPCHECK_PROJECTS "${CPPCHECK_PROJECTS}" PARENT_SCOPE)
set(CPPCHECK_ARGUMENTS "${CPPCHECK_ARGUMENTS}" PARENT_SCOPE)
set(CPPCHECK_PLATFORM "${CPPCHECK_PLATFORM}" PARENT_SCOPE)
set(CPPCHECK_LIBRARIES "${CPPCHECK_LIBRARIES}" PARENT_SCOPE)
endfunction()
function(cppcheck_add_project u_project)
list(APPEND CPPCHECK_PROJECTS ${u_project})
# Include Directories
get_target_property(_INCLUDE_DIRECTORIES ${u_project} INCLUDE_DIRECTORIES)
foreach(_path ${_INCLUDE_DIRECTORIES})
file(TO_NATIVE_PATH "${_path}" _npath)
list(APPEND CPPCHECK_ARGUMENTS -I${_npath})
endforeach()
if(MSVC)
add_custom_target(
CPPCHECK_${u_project}
COMMAND "${CPPCHECK_PATH}/${CPPCHECK_BIN}" ${CPPCHECK_ARGUMENTS} --project=${${u_project}_BINARY_DIR}/${u_project}.sln
COMMAND_EXPAND_LISTS
VERBATIM
)
else()
# Non-MSVC and Unix (Linux, FreeBSD, APPLE) need to have -I, -i, -D and -U specified manually.
# Each file can be added to --file-list= as a comma separated list.
# Defines
get_target_property(_COMPILE_DEFINITIONS ${u_project} COMPILE_DEFINITIONS)
foreach(_def ${_COMPILE_DEFINITIONS})
list(APPEND CPPCHECK_ARGUMENTS -D${_def})
endforeach()
# Source Files
get_target_property(_SOURCES ${u_project} SOURCES)
foreach(_path ${_SOURCES})
file(TO_NATIVE_PATH "${_path}" _npath)
list(APPEND CPPCHECK_ARGUMENTS ${_npath})
endforeach()
add_custom_target(
CPPCHECK_${u_project}
COMMAND "${CPPCHECK_PATH}/${CPPCHECK_BIN}" ${CPPCHECK_ARGUMENTS}
COMMAND_EXPAND_LISTS
VERBATIM
)
endif()
add_dependencies(CPPCHECK CPPCHECK_${u_project})
endfunction()
+17
View File
@@ -0,0 +1,17 @@
#include <obs.h>
#include <obs-module.h>
OBS_DECLARE_MODULE();
OBS_MODULE_AUTHOR("@PROJECT_AUTHORS@");
OBS_MODULE_USE_DEFAULT_LOCALE("@PROJECT_NAME@", "en-US");
MODULE_EXPORT const char* obs_module_name()
{
return "@PROJECT_FULL_NAME@";
}
MODULE_EXPORT const char* obs_module_description()
{
return "@PROJECT_DESCRIPTION@";
}
+19
View File
@@ -0,0 +1,19 @@
function(cacheset Name Value)
get_property(V_ADVANCED CACHE "${Name}" PROPERTY ADVANCED)
get_property(V_TYPE CACHE "${Name}" PROPERTY TYPE)
get_property(V_HELPSTRING CACHE "${Name}" PROPERTY HELPSTRING)
set(${Name} ${Value} CACHE ${V_TYPE} ${V_HELPSTRING} FORCE)
if(${V_ADVANCED})
mark_as_advanced(FORCE ${Name})
endif()
endfunction()
function(cacheclear Name)
get_property(V_ADVANCED CACHE "${Name}" PROPERTY ADVANCED)
get_property(V_TYPE CACHE "${Name}" PROPERTY TYPE)
get_property(V_HELPSTRING CACHE "${Name}" PROPERTY HELPSTRING)
set(${Name} 0 CACHE ${V_TYPE} ${V_HELPSTRING} FORCE)
if(${V_ADVANCED})
mark_as_advanced(FORCE ${Name})
endif()
endfunction()
+98
View File
@@ -0,0 +1,98 @@
#pragma once
#include <cinttypes>
#include <string>
#define MAKE_VERSION(major,minor,patch,build) ( \
((uint64_t(major) << 48) & 0xFFFF) \
((uint64_t(minor) << 32) & 0xFFFF) \
((uint64_t(patch) << 16) & 0xFFFF) \
((uint64_t(build)) & 0xFFFF))
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define PROJECT_VERSION_BUILD @PROJECT_VERSION_TWEAK@
#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_FULL_NAME "@PROJECT_FULL_NAME@"
#define PROJECT_DESCRIPTION "@PROJECT_DESCRIPTION@"
struct version {
union {
uint64_t full;
struct {
uint16_t major;
uint16_t minor;
uint16_t patch;
uint16_t build;
};
};
inline bool operator==(version const& rhl)
{
return (rhl.full == this->full);
}
inline bool operator!=(version const& rhl)
{
return (rhl.full != this->full);
}
inline bool operator<(version const& rhl)
{
return (rhl.full < this->full);
}
inline bool operator<=(version const& rhl)
{
return (rhl.full <= this->full);
}
inline bool operator>(version const& rhl)
{
return (rhl.full > this->full);
}
inline bool operator>=(version const& rhl)
{
return (rhl.full >= this->full);
}
inline int32_t compare(version const& rhl, bool& major, bool& minor, bool& patch, bool& build)
{
if (major) {
int32_t diff = (this->major - rhl.major);
if (diff != 0) {
major = true;
minor = patch = build = false;
return diff;
}
}
if (minor) {
int32_t diff = (this->minor - rhl.minor);
if (diff != 0) {
minor = true;
major = patch = build = false;
return diff;
}
}
if (patch) {
int32_t diff = (this->patch - rhl.patch);
if (diff != 0) {
patch = true;
major = minor = build = false;
return diff;
}
}
if (build) {
int32_t diff = (this->build - rhl.build);
if (diff != 0) {
build = true;
major = minor = patch = false;
return diff;
}
}
major = minor = patch = build = false;
return 0;
}
};
+55
View File
@@ -0,0 +1,55 @@
#pragma code_page(65001)
#include <windows.h>
#include <winver.h>
#define VER_FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_TWEAK@
#define VER_FILEVERSION_STR "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@.@PROJECT_VERSION_TWEAK@\0"
#define VER_PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_TWEAK@
#define VER_PRODUCTVERSION_STR "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@.@PROJECT_VERSION_TWEAK@\0"
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS (VER_DEBUG)
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "@PROJECT_COMPANY_NAME@\0"
VALUE "FileDescription", "@PROJECT_DESCRIPTION@\0"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "@PROJECT_NAME@\0"
VALUE "LegalCopyright", "@PROJECT_COPYRIGHT@\0"
VALUE "LegalTrademarks1", "@PROJECT_LEGAL_TRADEMARKS_1@\0"
VALUE "LegalTrademarks2", "@PROJECT_LEGAL_TRADEMARKS_1@\0"
VALUE "OriginalFilename", "@PROJECT_NAME@\0"
VALUE "ProductName", "@PROJECT_PRODUCT_NAME@\0"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
/* The following line should only be modified for localized versions. */
/* It consists of any number of WORD,WORD pairs, with each pair */
/* describing a language,codepage combination supported by the file. */
/* */
/* For example, a file might have values "0x409,1252" indicating that it */
/* supports English language (0x409) in the Windows ANSI codepage (1252). */
VALUE "Translation", 0x409, 1252
END
END
+15
View File
@@ -0,0 +1,15 @@
Bitrate="Bitrate"
Bitrate.Description="Bitrate in kbit/s"
KeyFrame.Type="Key Frame Type"
KeyFrame.Type.Frames="Frames"
KeyFrame.Type.Seconds="Seconds"
KeyFrame.Interval="Key Frame Interval"
KeyFrame.Interval.Description="Interval in which a Key Frame is placed."
CustomParameters="Custom Parameters"
CustomParameters.Description="Format: key1=val1 key2=val2 key3='val3 val4'"
# ProRes
ProRes.Profile.Proxy="Proxy (PXY)"
ProRes.Profile.Light="Light (LT)"
ProRes.Profile.Standard="Standard"
ProRes.Profile.HighQuality="High Quality (HQ)"
+20
View File
@@ -0,0 +1,20 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "encoder.hpp"
obsffmpeg::encoder::base::~base() {}
+145
View File
@@ -0,0 +1,145 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef OBS_FFMPEG_ENCODER_HPP
#define OBS_FFMPEG_ENCODER_HPP
#pragma once
#include <map>
#include <string>
#include "ffmpeg/swscale.hpp"
#include <obs.h>
extern "C" {
#pragma warning(push)
#pragma warning(disable : 4244)
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#pragma warning(pop)
}
namespace obsffmpeg {
namespace encoder {
class base {
protected:
obs_encoder_t* self = nullptr;
AVCodec* avcodec = nullptr;
AVCodecContext* avcontext = nullptr;
AVDictionary* avdictionary = nullptr;
ffmpeg::swscale swscale;
std::pair<uint32_t, uint32_t> resolution;
std::pair<uint32_t, uint32_t> framerate;
AVPixelFormat source_format;
AVColorSpace source_colorspace;
AVColorRange source_range;
AVPixelFormat target_format;
AVColorSpace target_colorspace;
AVColorRange target_range;
public:
virtual ~base();
virtual void get_properties(obs_properties_t* props) = 0;
virtual bool update(obs_data_t* settings) = 0;
virtual bool get_extra_data(uint8_t** extra_data, size_t* size) = 0;
virtual bool get_sei_data(uint8_t** sei_data, size_t* size) = 0;
virtual void get_video_info(struct video_scale_info* info) = 0;
virtual bool encode(struct encoder_frame* frame, struct encoder_packet* packet,
bool* received_packet) = 0;
};
#define make_encoder_base(_source, _target, _name, _codec) \
static void* _source##_create(obs_data_t* settings, obs_encoder_t* encoder) \
{ \
_target* ptr = nullptr; \
try { \
ptr = new _target(settings, encoder); \
} catch (...) { \
} \
return ptr; \
} \
static void _source##_destroy(void* ptr) \
{ \
delete static_cast<_target*>(ptr); \
} \
static const char* _source##_get_name(void*) \
{ \
return _name; \
} \
static obs_properties_t* _source##_get_properties(void* ptr) \
{ \
obs_properties_t* pr = _target::get_properties(); \
if (ptr) { \
static_cast<_target*>(ptr)->get_properties(pr); \
} \
return pr; \
} \
static void _source##_get_defaults(obs_data_t* settings) \
{ \
_target::get_defaults(settings); \
} \
static bool _source##_get_extra_data(void* ptr, uint8_t** extra_data, size_t* size) \
{ \
return static_cast<_target*>(ptr)->get_extra_data(extra_data, size); \
} \
static bool _source##_get_sei_data(void* ptr, uint8_t** sei_data, size_t* size) \
{ \
return static_cast<_target*>(ptr)->get_sei_data(sei_data, size); \
} \
static void _source##_get_video_info(void* ptr, struct video_scale_info* info) \
{ \
static_cast<_target*>(ptr)->get_video_info(info); \
} \
static bool _source##_encode(void* ptr, struct encoder_frame* frame, struct encoder_packet* packet, \
bool* received_packet) \
{ \
return static_cast<_target*>(ptr)->encode(frame, packet, received_packet); \
} \
static obs_encoder_info _source##_info; \
static void _source##_initialize() \
{ \
_source##_info.id = "obs-ffmpeg-encoder-" #_source; \
_source##_info.type = OBS_ENCODER_VIDEO; \
_source##_info.caps = 0; \
_source##_info.codec = _codec; \
_source##_info.create = _source##_create; \
_source##_info.destroy = _source##_destroy; \
_source##_info.get_name = _source##_get_name; \
_source##_info.get_properties = _source##_get_properties; \
_source##_info.get_defaults = _source##_get_defaults; \
_source##_info.get_extra_data = _source##_get_extra_data; \
_source##_info.get_sei_data = _source##_get_sei_data; \
_source##_info.get_video_info = _source##_get_video_info; \
_source##_info.encode = _source##_encode; \
obs_register_encoder(&(_source##_info)); \
}
//*/
} // namespace encoder
} // namespace obsffmpeg
#endif OBS_FFMPEG_ENCODER_HPP
+343
View File
@@ -0,0 +1,343 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "prores_aw.hpp"
#include <obs-module.h>
#include <thread>
#include "ffmpeg/tools.hpp"
#include "utility.hpp"
extern "C" {
#pragma warning(push)
#pragma warning(disable : 4244)
#include "libavutil/dict.h"
#include "libavutil/frame.h"
#include "libavutil/opt.h"
#pragma warning(pop)
}
#include <util/profiler.hpp>
#define T_PROFILE "ProRes.Profile"
#define T_PROFILE_(x) "ProRes.Profile." vstr(x)
#define T_CUSTOM "Custom"
#define LOG_PREFIX "[prores_aw] "
make_encoder_base(prores_aw, obsffmpeg::encoder::prores_aw, "ProRes (Anatoliy Wasserman) (FFMPEG)", "prores");
void obsffmpeg::encoder::prores_aw::initialize()
{
auto avd = avcodec_find_encoder_by_name("prores_aw");
if (!avd) {
PLOG_INFO("ProRes (Anatoliy Wasserman) not supported.");
return;
}
prores_aw_initialize();
PLOG_INFO("ProRes (Anatoliy Wasserman) supported.");
}
void obsffmpeg::encoder::prores_aw::finalize()
{
//prores_aw_finalize();
}
void obsffmpeg::encoder::prores_aw::get_defaults(obs_data_t* settings)
{
obs_data_set_default_int(settings, T_PROFILE, static_cast<long long>(profile::HighQuality));
}
obs_properties_t* obsffmpeg::encoder::prores_aw::get_properties()
{
obs_properties_t* prs = obs_properties_create();
obs_property_t* p = nullptr;
p = obs_properties_add_list(prs, T_PROFILE, TRANSLATE(T_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, TRANSLATE(DESC(T_PROFILE)));
obs_property_list_add_int(p, TRANSLATE(T_PROFILE_(Proxy)), static_cast<long long>(profile::Proxy));
obs_property_list_add_int(p, TRANSLATE(T_PROFILE_(Light)), static_cast<long long>(profile::Light));
obs_property_list_add_int(p, TRANSLATE(T_PROFILE_(Standard)), static_cast<long long>(profile::Standard));
obs_property_list_add_int(p, TRANSLATE(T_PROFILE_(HighQuality)), static_cast<long long>(profile::HighQuality));
p = obs_properties_add_text(prs, T_CUSTOM, TRANSLATE(T_CUSTOM), OBS_TEXT_DEFAULT);
obs_property_set_long_description(p, TRANSLATE(DESC(T_CUSTOM)));
return prs;
}
obsffmpeg::encoder::prores_aw::prores_aw(obs_data_t* settings, obs_encoder_t* encoder)
{
this->self = encoder;
auto encvideo = obs_encoder_video(this->self);
auto voi = video_output_get_info(encvideo);
// Options, Parameters, etc.
/// Resolution, Frame Rate
this->resolution.first = voi->width;
this->resolution.second = voi->height;
this->framerate.first = voi->fps_num;
this->framerate.second = voi->fps_den;
/// Source/Input
this->source_colorspace = ffmpeg::tools::obs_videocolorspace_to_avcolorspace(voi->colorspace);
this->source_range = ffmpeg::tools::obs_videorangetype_to_avcolorrange(voi->range);
this->source_format = ffmpeg::tools::obs_videoformat_to_avpixelformat(voi->format);
/// Target/Output
this->target_colorspace = this->source_colorspace;
this->target_range = this->source_range;
switch (voi->format) {
case VIDEO_FORMAT_RGBA:
case VIDEO_FORMAT_BGRA:
case VIDEO_FORMAT_BGRX:
this->target_format = AV_PIX_FMT_YUV444P10;
this->video_profile = profile::FourFourFourFour;
break;
case VIDEO_FORMAT_I444:
case VIDEO_FORMAT_YVYU:
case VIDEO_FORMAT_YUY2:
case VIDEO_FORMAT_UYVY:
case VIDEO_FORMAT_I420:
case VIDEO_FORMAT_NV12:
this->video_profile = static_cast<profile>(obs_data_get_int(settings, T_PROFILE));
if (this->video_profile == profile::FourFourFourFour) {
this->target_format = AV_PIX_FMT_YUV444P10;
} else {
this->target_format = AV_PIX_FMT_YUV422P10;
}
break;
}
// Log Settings
PLOG_INFO(LOG_PREFIX
"Initializing encoder...\n\tResolution: %lux%lu\n\tFramerate: %lu/%lu (%.2lf fps)\n\tInput: %s %s "
"%s\n\tOutput: %s %s %s\n\tProfile: %ld",
this->resolution.first, this->resolution.second, this->framerate.first, this->framerate.second,
(double_t(this->framerate.first) / double_t(this->framerate.second)),
ffmpeg::tools::get_pixel_format_name(this->source_format),
ffmpeg::tools::get_color_space_name(this->source_colorspace),
swscale.is_source_full_range() ? "Full" : "Partial",
ffmpeg::tools::get_pixel_format_name(this->target_format),
ffmpeg::tools::get_color_space_name(this->target_colorspace),
swscale.is_target_full_range() ? "Full" : "Partial", static_cast<int>(this->video_profile));
// prores_aw restriction
if (this->resolution.first % 2 == 1) {
PLOG_ERROR(LOG_PREFIX "Width must be a multiple of 2.");
throw std::exception();
}
// Quit if we for some reason can't find prores_aw anymore.
this->avcodec = avcodec_find_encoder_by_name("prores_aw");
if (!this->avcodec) {
PLOG_ERROR(LOG_PREFIX "Failed to find encoder.");
throw std::exception();
}
this->avcontext = avcodec_alloc_context3(this->avcodec);
if (!this->avcontext) {
PLOG_ERROR(LOG_PREFIX "Failed to create context.");
throw std::exception();
}
// Apply Settings
/// Resolution
this->avcontext->width = this->resolution.first;
this->avcontext->height = this->resolution.second;
/// Framerate
this->avcontext->time_base.num = this->framerate.first;
this->avcontext->time_base.den = this->framerate.second;
this->avcontext->ticks_per_frame = 1;
/// GOP/Keyframe (ProRes is Intra only)
this->avcontext->gop_size = 0;
/// Color, Profile
this->avcontext->colorspace = this->target_colorspace;
this->avcontext->color_range = this->target_range;
this->avcontext->pix_fmt = this->target_format;
this->avcontext->profile = static_cast<int>(this->video_profile);
/// Other
this->avcontext->field_order = AV_FIELD_PROGRESSIVE;
this->avcontext->strict_std_compliance = FF_COMPLIANCE_NORMAL;
this->avcontext->debug = 0;
/// Threading
this->avcontext->thread_type = FF_THREAD_FRAME;
#if defined(__cplusplus)
this->avcontext->thread_count = std::thread::hardware_concurrency();
#elif defined(_WIN32)
{
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
this->avcontext->thread_count = sysinfo.dwNumberOfProcessors;
}
#elif defined(_GNU)
this->avcontext->thread_count = 16;
#else
this->avcontext->thread_count = 16;
#endif
/// Dynamic Stuff
this->update(settings);
// Open Encoder
int res = avcodec_open2(this->avcontext, this->avcodec, NULL);
if (res < 0) {
avcodec_free_context(&this->avcontext);
PLOG_ERROR(LOG_PREFIX "Failed to open codec: %s (%ld).", ffmpeg::tools::get_error_description(res),
res);
throw std::exception();
}
// Configure and initialize SWScale
swscale.set_source_size(voi->width, voi->height);
swscale.set_source_format(this->source_format);
swscale.set_source_color(this->source_range == AVCOL_RANGE_JPEG, this->source_colorspace);
swscale.set_target_size(voi->width, voi->height);
swscale.set_target_format(this->target_format);
swscale.set_target_color(this->target_range == AVCOL_RANGE_JPEG, this->target_colorspace);
if (!swscale.initialize(SWS_FAST_BILINEAR)) {
PLOG_ERROR(LOG_PREFIX "Incompatible conversion parameters:\n\tInput: %s %s %s\n\tOutput: %s %s %s",
ffmpeg::tools::get_pixel_format_name(this->source_format),
ffmpeg::tools::get_color_space_name(this->source_colorspace),
swscale.is_source_full_range() ? "Full" : "Partial",
ffmpeg::tools::get_pixel_format_name(this->target_format),
ffmpeg::tools::get_color_space_name(this->target_colorspace),
swscale.is_target_full_range() ? "Full" : "Partial");
throw std::exception();
}
frame_queue.set_pixel_format(this->avcontext->pix_fmt);
frame_queue.set_resolution(this->resolution.first, this->resolution.second);
frame_queue.precache(this->avcontext->thread_count / 2);
this->current_packet = av_packet_alloc();
if (!this->current_packet) {
PLOG_ERROR(LOG_PREFIX "Failed to allocated packet.");
throw std::exception();
}
PLOG_INFO(LOG_PREFIX "Encoder initialized.");
}
obsffmpeg::encoder::prores_aw::~prores_aw()
{
frame_queue.clear();
swscale.finalize();
if (this->avcontext) {
avcodec_close(this->avcontext);
avcodec_free_context(&this->avcontext);
}
}
void obsffmpeg::encoder::prores_aw::get_properties(obs_properties_t* props) {}
bool obsffmpeg::encoder::prores_aw::update(obs_data_t* settings)
{
return false;
}
bool obsffmpeg::encoder::prores_aw::get_extra_data(uint8_t** extra_data, size_t* size)
{
if (!this->avcontext->extradata) {
return false;
}
*extra_data = this->avcontext->extradata;
*size = this->avcontext->extradata_size;
return true;
}
bool obsffmpeg::encoder::prores_aw::get_sei_data(uint8_t** sei_data, size_t* size)
{
return false;
}
void obsffmpeg::encoder::prores_aw::get_video_info(video_scale_info* info)
{
return;
}
bool obsffmpeg::encoder::prores_aw::encode(encoder_frame* frame, encoder_packet* packet, bool* received_packet)
{
int res = 0;
{
ScopeProfiler sp_frame("frame");
AVFrame* vframe = frame_queue.pop();
vframe->pts = frame->pts;
vframe->color_range = this->avcontext->color_range;
vframe->colorspace = this->avcontext->colorspace;
{
ScopeProfiler profile("convert");
res = swscale.convert(reinterpret_cast<uint8_t**>(frame->data),
reinterpret_cast<int*>(frame->linesize), 0, this->resolution.second,
vframe->data, vframe->linesize);
if (res <= 0) {
PLOG_ERROR(LOG_PREFIX "Failed to convert frame: %s (%ld).",
ffmpeg::tools::get_error_description(res), res);
return false;
}
}
{
ScopeProfiler profile("send");
res = avcodec_send_frame(this->avcontext, vframe);
if (res < 0) {
PLOG_ERROR(LOG_PREFIX "Failed to encode frame: %s (%ld).",
ffmpeg::tools::get_error_description(res), res);
return false;
}
}
frame_queue_used.push(vframe);
}
{
ScopeProfiler profile("receive");
res = avcodec_receive_packet(this->avcontext, this->current_packet);
if (res < 0) {
if (res == AVERROR(EAGAIN)) {
*received_packet = false;
return true;
} else if (res == AVERROR(EOF)) {
return true;
} else {
PLOG_ERROR(LOG_PREFIX "Failed to receive packet: %s (%ld).",
ffmpeg::tools::get_error_description(res), res);
return false;
}
} else {
AVFrame* uframe = frame_queue_used.pop_only();
if (uframe) {
if (frame_queue.empty()) {
frame_queue.push(uframe);
} else {
av_frame_free(&uframe);
}
}
packet->type = OBS_ENCODER_VIDEO;
packet->pts = this->current_packet->pts;
packet->dts = this->current_packet->pts;
packet->data = this->current_packet->data;
packet->size = this->current_packet->size;
packet->keyframe = true; // There are only keyframes in ProRes (Intra Only)
packet->drop_priority = 0;
*received_packet = true;
}
}
return true;
}
+80
View File
@@ -0,0 +1,80 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef OBS_FFMPEG_ENCODER_PRORES_AW
#define OBS_FFMPEG_ENCODER_PRORES_AW
#pragma once
#include <encoder.hpp>
#include "ffmpeg/avframe-queue.hpp"
#include <vector>
extern "C" {
#include <libavcodec/avcodec.h>
}
namespace obsffmpeg {
namespace encoder {
class prores_aw : base {
enum class profile {
Auto = FF_PROFILE_UNKNOWN,
Proxy = 0 /*FF_PROFILE_PRORES_PROXY*/,
Light = 1 /*FF_PROFILE_PRORES_LT*/,
Standard = 2 /*FF_PROFILE_PRORES_STANDARD*/,
HighQuality = 3 /*FF_PROFILE_PRORES_HQ*/,
FourFourFourFour = 4 /*FF_PROFILE_PRORES_4444*/ // Automatically set if I444 or RGB input.
};
private:
profile video_profile = profile::Auto;
ffmpeg::avframe_queue frame_queue;
ffmpeg::avframe_queue frame_queue_used;
AVPacket* current_packet = nullptr;
public:
prores_aw(obs_data_t* settings, obs_encoder_t* encoder);
~prores_aw();
virtual void get_properties(obs_properties_t* props) override;
virtual bool update(obs_data_t* settings) override;
virtual bool get_extra_data(uint8_t** extra_data, size_t* size) override;
virtual bool get_sei_data(uint8_t** sei_data, size_t* size) override;
virtual void get_video_info(video_scale_info* info) override;
virtual bool encode(encoder_frame* frame, encoder_packet* packet,
bool* received_packet) override;
public:
static void initialize();
static void finalize();
static void get_defaults(obs_data_t* settings);
static obs_properties_t* get_properties();
};
} // namespace encoder
} // namespace obsffmpeg
#endif OBS_FFMPEG_ENCODER_PRORES_AW
+151
View File
@@ -0,0 +1,151 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "avframe-queue.hpp"
#include "tools.hpp"
AVFrame* ffmpeg::avframe_queue::create_frame()
{
AVFrame* frame = av_frame_alloc();
frame->width = this->resolution.first;
frame->height = this->resolution.second;
frame->format = this->format;
int res = av_frame_get_buffer(frame, 0);
if (res < 0) {
throw std::exception(ffmpeg::tools::get_error_description(res));
}
return frame;
}
void ffmpeg::avframe_queue::destroy_frame(AVFrame* frame)
{
if (frame == nullptr)
return;
av_frame_free(&frame);
}
ffmpeg::avframe_queue::avframe_queue() {}
ffmpeg::avframe_queue::~avframe_queue()
{
clear();
}
void ffmpeg::avframe_queue::set_resolution(uint32_t width, uint32_t height)
{
this->resolution.first = width;
this->resolution.second = height;
}
void ffmpeg::avframe_queue::get_resolution(uint32_t& width, uint32_t& height)
{
width = this->resolution.first;
height = this->resolution.second;
}
uint32_t ffmpeg::avframe_queue::get_width()
{
return this->resolution.first;
}
uint32_t ffmpeg::avframe_queue::get_height()
{
return this->resolution.second;
}
void ffmpeg::avframe_queue::set_pixel_format(AVPixelFormat format)
{
this->format = format;
}
AVPixelFormat ffmpeg::avframe_queue::get_pixel_format()
{
return this->format;
}
void ffmpeg::avframe_queue::precache(size_t count)
{
for (size_t n = 0; n < count; n++) {
push(create_frame());
}
}
void ffmpeg::avframe_queue::clear()
{
std::unique_lock<std::mutex> ulock(this->lock);
for (AVFrame* frame : frames) {
destroy_frame(frame);
}
frames.clear();
}
void ffmpeg::avframe_queue::push(AVFrame* frame)
{
std::unique_lock<std::mutex> ulock(this->lock);
frames.push_back(frame);
}
AVFrame* ffmpeg::avframe_queue::pop()
{
std::unique_lock<std::mutex> ulock(this->lock);
AVFrame* ret = nullptr;
while (ret == nullptr) {
if (frames.size() == 0) {
ret = create_frame();
} else {
ret = frames.front();
if (ret == nullptr) {
ret = create_frame();
} else {
frames.pop_front();
if ((ret->width != this->resolution.first) || (ret->height != this->resolution.second)
|| (ret->format != this->format)) {
destroy_frame(ret);
ret = nullptr;
}
}
}
}
return ret;
}
AVFrame* ffmpeg::avframe_queue::pop_only()
{
std::unique_lock<std::mutex> ulock(this->lock);
if (frames.size() == 0) {
return nullptr;
}
AVFrame* ret = frames.front();
if (ret == nullptr) {
return nullptr;
}
frames.pop_front();
return ret;
}
bool ffmpeg::avframe_queue::empty()
{
return frames.empty();
}
size_t ffmpeg::avframe_queue::size()
{
return frames.size();
}
+70
View File
@@ -0,0 +1,70 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef OBS_FFMPEG_FFMPEG_AVFRAME_QUEUE
#define OBS_FFMPEG_FFMPEG_AVFRAME_QUEUE
#pragma once
#include <mutex>
#include <deque>
extern "C" {
#include <libavutil/frame.h>
}
namespace ffmpeg {
class avframe_queue {
std::deque<AVFrame*> frames;
std::mutex lock;
std::pair<uint32_t, uint32_t> resolution;
AVPixelFormat format = AV_PIX_FMT_NONE;
AVFrame* create_frame();
void destroy_frame(AVFrame* frame);
public:
avframe_queue();
~avframe_queue();
void set_resolution(uint32_t width, uint32_t height);
void get_resolution(uint32_t& width, uint32_t& height);
uint32_t get_width();
uint32_t get_height();
void set_pixel_format(AVPixelFormat format);
AVPixelFormat get_pixel_format();
void precache(size_t count);
void clear();
void push(AVFrame* frame);
AVFrame* pop();
AVFrame* pop_only();
bool empty();
size_t size();
};
} // namespace ffmpeg
#endif OBS_FFMPEG_FFMPEG_AVFRAME_QUEUE
+196
View File
@@ -0,0 +1,196 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "swscale.hpp"
#include <stdexcept>
ffmpeg::swscale::swscale() {}
ffmpeg::swscale::~swscale()
{
finalize();
}
void ffmpeg::swscale::set_source_size(uint32_t width, uint32_t height)
{
source_size.first = width;
source_size.second = height;
}
void ffmpeg::swscale::get_source_size(uint32_t& width, uint32_t& height)
{
width = this->source_size.first;
height = this->source_size.second;
}
std::pair<uint32_t, uint32_t> ffmpeg::swscale::get_source_size()
{
return this->source_size;
}
uint32_t ffmpeg::swscale::get_source_width()
{
return this->source_size.first;
}
uint32_t ffmpeg::swscale::get_source_height()
{
return this->source_size.second;
}
void ffmpeg::swscale::set_source_format(AVPixelFormat format)
{
source_format = format;
}
AVPixelFormat ffmpeg::swscale::get_source_format()
{
return this->source_format;
}
void ffmpeg::swscale::set_source_color(bool full_range, AVColorSpace space)
{
source_full_range = full_range;
source_colorspace = space;
}
void ffmpeg::swscale::set_source_colorspace(AVColorSpace space)
{
this->source_colorspace = space;
}
AVColorSpace ffmpeg::swscale::get_source_colorspace()
{
return this->source_colorspace;
}
void ffmpeg::swscale::set_source_full_range(bool full_range)
{
this->source_full_range = full_range;
}
bool ffmpeg::swscale::is_source_full_range()
{
return this->source_full_range;
}
void ffmpeg::swscale::set_target_size(uint32_t width, uint32_t height)
{
target_size.first = width;
target_size.second = height;
}
void ffmpeg::swscale::get_target_size(uint32_t& width, uint32_t& height) {}
std::pair<uint32_t, uint32_t> ffmpeg::swscale::get_target_size()
{
return this->target_size;
}
uint32_t ffmpeg::swscale::get_target_width()
{
return this->target_size.first;
}
uint32_t ffmpeg::swscale::get_target_height()
{
return this->target_size.second;
}
void ffmpeg::swscale::set_target_format(AVPixelFormat format)
{
target_format = format;
}
AVPixelFormat ffmpeg::swscale::get_target_format()
{
return this->target_format;
}
void ffmpeg::swscale::set_target_color(bool full_range, AVColorSpace space)
{
target_full_range = full_range;
target_colorspace = space;
}
void ffmpeg::swscale::set_target_colorspace(AVColorSpace space)
{
this->target_colorspace = space;
}
AVColorSpace ffmpeg::swscale::get_target_colorspace()
{
return this->target_colorspace;
}
void ffmpeg::swscale::set_target_full_range(bool full_range)
{
this->target_full_range = full_range;
}
bool ffmpeg::swscale::is_target_full_range()
{
return this->target_full_range;
}
bool ffmpeg::swscale::initialize(int flags)
{
if (this->context) {
return false;
}
if (source_size.first == 0 || source_size.second == 0 || source_format == AV_PIX_FMT_NONE
|| source_colorspace == AVCOL_SPC_UNSPECIFIED) {
throw std::invalid_argument("not all source parameters were set");
}
if (target_size.first == 0 || target_size.second == 0 || target_format == AV_PIX_FMT_NONE
|| target_colorspace == AVCOL_SPC_UNSPECIFIED) {
throw std::invalid_argument("not all target parameters were set");
}
this->context = sws_getContext(source_size.first, source_size.second, source_format, target_size.first,
target_size.second, target_format, flags, nullptr, nullptr, nullptr);
if (!this->context) {
return false;
}
sws_setColorspaceDetails(this->context, sws_getCoefficients(source_colorspace), source_full_range ? 1 : 0,
sws_getCoefficients(target_colorspace), target_full_range ? 1 : 0, 1l << 16 | 0l,
1l << 16 | 0l, 1l << 16 | 0l);
return true;
}
bool ffmpeg::swscale::finalize()
{
if (this->context) {
sws_freeContext(this->context);
this->context = nullptr;
return true;
}
return false;
}
int32_t ffmpeg::swscale::convert(const uint8_t* const source_data[], const int source_stride[], int32_t source_row,
int32_t source_rows, uint8_t* const target_data[], const int target_stride[])
{
if (!this->context) {
return 0;
}
int height =
sws_scale(this->context, source_data, source_stride, source_row, source_rows, target_data, target_stride);
return height;
}
+82
View File
@@ -0,0 +1,82 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef OBS_FFMPEG_FFMPEG_SWSCALE
#define OBS_FFMPEG_FFMPEG_SWSCALE
#pragma once
#include <cinttypes>
#include <utility>
extern "C" {
#include <libavutil/pixfmt.h>
#include <libswscale/swscale.h>
}
namespace ffmpeg {
class swscale {
std::pair<uint32_t, uint32_t> source_size;
AVPixelFormat source_format = AV_PIX_FMT_NONE;
bool source_full_range = false;
AVColorSpace source_colorspace = AVCOL_SPC_UNSPECIFIED;
std::pair<uint32_t, uint32_t> target_size;
AVPixelFormat target_format = AV_PIX_FMT_NONE;
bool target_full_range = false;
AVColorSpace target_colorspace = AVCOL_SPC_UNSPECIFIED;
SwsContext* context = nullptr;
public:
swscale();
~swscale();
void set_source_size(uint32_t width, uint32_t height);
void get_source_size(uint32_t& width, uint32_t& height);
std::pair<uint32_t, uint32_t> get_source_size();
uint32_t get_source_width();
uint32_t get_source_height();
void set_source_format(AVPixelFormat format);
AVPixelFormat get_source_format();
void set_source_color(bool full_range, AVColorSpace space);
void set_source_colorspace(AVColorSpace space);
AVColorSpace get_source_colorspace();
void set_source_full_range(bool full_range);
bool is_source_full_range();
void set_target_size(uint32_t width, uint32_t height);
void get_target_size(uint32_t& width, uint32_t& height);
std::pair<uint32_t, uint32_t> get_target_size();
uint32_t get_target_width();
uint32_t get_target_height();
void set_target_format(AVPixelFormat format);
AVPixelFormat get_target_format();
void set_target_color(bool full_range, AVColorSpace space);
void set_target_colorspace(AVColorSpace space);
AVColorSpace get_target_colorspace();
void set_target_full_range(bool full_range);
bool is_target_full_range();
bool initialize(int flags);
bool finalize();
int32_t convert(const uint8_t* const source_data[], const int source_stride[], int32_t source_row,
int32_t source_rows, uint8_t* const target_data[], const int target_stride[]);
};
} // namespace ffmpeg
#endif OBS_FFMPEG_FFMPEG_SWSCALE
+126
View File
@@ -0,0 +1,126 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "tools.hpp"
#include <stdexcept>
extern "C" {
#include <libavutil/error.h>
#include <libavutil/pixdesc.h>
}
const char* ffmpeg::tools::get_pixel_format_name(AVPixelFormat v)
{
return av_get_pix_fmt_name(v);
}
const char* ffmpeg::tools::get_color_space_name(AVColorSpace v)
{
switch (v) {
case AVCOL_SPC_RGB:
return "RGB";
case AVCOL_SPC_BT709:
return "BT.709";
case AVCOL_SPC_FCC:
return "FCC Title 47 CoFR 73.682 (a)(20)";
case AVCOL_SPC_BT470BG:
return "BT.601 625";
case AVCOL_SPC_SMPTE170M:
case AVCOL_SPC_SMPTE240M:
return "BT.601 525";
case AVCOL_SPC_YCGCO:
return "ITU-T SG16";
case AVCOL_SPC_BT2020_NCL:
return "BT.2020 NCL";
case AVCOL_SPC_BT2020_CL:
return "BT.2020 CL";
case AVCOL_SPC_SMPTE2085:
return "SMPTE 2085";
case AVCOL_SPC_CHROMA_DERIVED_NCL:
return "Chroma NCL";
case AVCOL_SPC_CHROMA_DERIVED_CL:
return "Chroma CL";
case AVCOL_SPC_ICTCP:
return "BT.2100";
case AVCOL_SPC_NB:
return "Not Part of ABI";
}
return "Unknown";
}
const char* ffmpeg::tools::get_error_description(int error)
{
switch (error) {
case AVERROR(EPERM):
return "Permission Denied";
case AVERROR(ENOMEM):
return "Out Of Memory";
case AVERROR(EINVAL):
return "Invalid Value for Parameter";
}
return "Not Translated Yet";
}
AVPixelFormat ffmpeg::tools::obs_videoformat_to_avpixelformat(video_format v)
{
switch (v) {
// 32-Bits
case VIDEO_FORMAT_BGRX:
return AV_PIX_FMT_BGRA;
case VIDEO_FORMAT_BGRA:
return AV_PIX_FMT_BGRA;
case VIDEO_FORMAT_RGBA:
return AV_PIX_FMT_RGBA;
case VIDEO_FORMAT_I444:
return AV_PIX_FMT_YUV444P;
case VIDEO_FORMAT_YUY2:
return AV_PIX_FMT_YUYV422;
case VIDEO_FORMAT_YVYU:
return AV_PIX_FMT_YVYU422;
case VIDEO_FORMAT_UYVY:
return AV_PIX_FMT_UYVY422;
case VIDEO_FORMAT_I420:
return AV_PIX_FMT_YUV420P;
case VIDEO_FORMAT_NV12:
return AV_PIX_FMT_NV12;
}
throw std::invalid_argument("unknown format");
}
AVColorSpace ffmpeg::tools::obs_videocolorspace_to_avcolorspace(video_colorspace v)
{
switch (v) {
case VIDEO_CS_DEFAULT:
case VIDEO_CS_709:
return AVCOL_SPC_BT709;
case VIDEO_CS_601:
return AVCOL_SPC_SMPTE170M;
}
throw std::invalid_argument("unknown color space");
}
AVColorRange ffmpeg::tools::obs_videorangetype_to_avcolorrange(video_range_type v)
{
switch (v) {
case VIDEO_RANGE_DEFAULT:
case VIDEO_RANGE_FULL:
return AVCOL_RANGE_JPEG;
case VIDEO_RANGE_PARTIAL:
return AVCOL_RANGE_MPEG;
}
throw std::invalid_argument("unknown range");
}
+44
View File
@@ -0,0 +1,44 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef OBS_FFMPEG_FFMPEG_UTILITY
#define OBS_FFMPEG_FFMPEG_UTILITY
#pragma once
#include <obs.h>
extern "C" {
#include <libavutil/pixfmt.h>
}
namespace ffmpeg {
namespace tools {
const char* get_pixel_format_name(AVPixelFormat v);
const char* get_color_space_name(AVColorSpace v);
const char* get_error_description(int error);
AVPixelFormat obs_videoformat_to_avpixelformat(video_format v);
AVColorSpace obs_videocolorspace_to_avcolorspace(video_colorspace v);
AVColorRange obs_videorangetype_to_avcolorrange(video_range_type v);
}
} // namespace ffmpeg
#endif OBS_FFMPEG_FFMPEG_UTILITY
+55
View File
@@ -0,0 +1,55 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "plugin.hpp"
#include <obs-module.h>
#include <obs.h>
#include "utility.hpp"
#include "encoders/prores_aw.hpp"
extern "C" {
#pragma warning(push)
#pragma warning(disable : 4244)
#include <libavcodec/avcodec.h>
#pragma warning(pop)
}
MODULE_EXPORT bool obs_module_load(void)
{
try {
avcodec_register_all();
obsffmpeg::encoder::prores_aw::initialize();
return true;
} catch (std::exception ex) {
PLOG_ERROR("Exception during initalization: %s.", ex.what());
} catch (...) {
PLOG_ERROR("Unrecognized exception during initalization.");
}
return false;
}
MODULE_EXPORT void obs_module_unload(void)
{
try {
obsffmpeg::encoder::prores_aw::finalize();
} catch (std::exception ex) {
PLOG_ERROR("Exception during finalizing: %s.", ex.what());
} catch (...) {
PLOG_ERROR("Unrecognized exception during finalizing.");
}
}
+30
View File
@@ -0,0 +1,30 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef OBS_FFMPEG_PLUGIN_HPP
#define OBS_FFMPEG_PLUGIN_HPP
#pragma once
#include <functional>
#include <list>
namespace obsffmpeg {
} // namespace obsffmpeg
#endif OBS_FFMPEG_PLUGIN_HPP
View File
+48
View File
@@ -0,0 +1,48 @@
// FFMPEG Video Encoder Integration for OBS Studio
// Copyright (C) 2018 - 2018 Michael Fabian Dirks
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef OBS_FFMPEG_UTILITY_HPP
#define OBS_FFMPEG_UTILITY_HPP
#pragma once
#include "version.hpp"
// Logging
#define PLOG(level, ...) blog(level, "["##PROJECT_NAME##"] " __VA_ARGS__);
#define PLOG_ERROR(...) PLOG(LOG_ERROR, __VA_ARGS__)
#define PLOG_WARNING(...) PLOG(LOG_WARNING, __VA_ARGS__)
#define PLOG_INFO(...) PLOG(LOG_INFO, __VA_ARGS__)
#define PLOG_DEBUG(...) PLOG(LOG_DEBUG, __VA_ARGS__)
// Function Name
#ifndef __FUNCTION_NAME__
#if defined(_WIN32) || defined(_WIN64) //WINDOWS
#define __FUNCTION_NAME__ __FUNCTION__
#else //*NIX
#define __FUNCTION_NAME__ __func__
#endif
#endif
// I18n
#define TRANSLATE(x) obs_module_text(x)
#define DESC(x) x ".Description"
// Other
#define vstr(s) dstr(s)
#define dstr(s) #s
#endif OBS_FFMPEG_UTILITY_HPP