11 Commits

Author SHA1 Message Date
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
20 changed files with 365 additions and 304 deletions
+2 -1
View File
@@ -25,7 +25,7 @@ Include("cmake/util.cmake")
# Automatic Versioning
set(VERSION_MAJOR 0)
set(VERSION_MINOR 2)
set(VERSION_MINOR 3)
set(VERSION_PATCH 0)
set(VERSION_TWEAK 0)
set(PROJECT_COMMIT "N/A")
@@ -325,6 +325,7 @@ add_library(${PROJECT_NAME} MODULE
${PROJECT_GENERATED}
${PROJECT_PRIVATE}
${PROJECT_DATA}
${PROJECT_TEMPLATES}
)
# Include Directories
+151 -54
View File
@@ -147,6 +147,17 @@ static void _get_defaults(obs_data_t* settings, void* type_data) noexcept try {
PLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
};
static void _get_defaults_texture(obs_data_t* settings, void* type_data) noexcept try {
#ifdef DEBUG_CALL_ORDER
PLOG_INFO("%s %llX %llX", __FUNCTION_NAME__, settings, type_data);
#endif
reinterpret_cast<obsffmpeg::encoder_factory*>(type_data)->get_defaults(settings, true);
} catch (const std::exception& ex) {
PLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
} catch (...) {
PLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
};
static obs_properties_t* _get_properties(void* ptr, void* type_data) noexcept try {
#ifdef DEBUG_CALL_ORDER
PLOG_INFO("%s %llX %llX", __FUNCTION_NAME__, ptr, type_data);
@@ -167,6 +178,26 @@ static obs_properties_t* _get_properties(void* ptr, void* type_data) noexcept tr
return reinterpret_cast<obs_properties_t*>(0);
}
static obs_properties_t* _get_properties_texture(void* ptr, void* type_data) noexcept try {
#ifdef DEBUG_CALL_ORDER
PLOG_INFO("%s %llX %llX", __FUNCTION_NAME__, ptr, type_data);
#endif
obs_properties_t* props = obs_properties_create();
if (type_data != nullptr) {
reinterpret_cast<obsffmpeg::encoder_factory*>(type_data)->get_properties(props, true);
}
if (ptr != nullptr) {
reinterpret_cast<obsffmpeg::encoder*>(ptr)->get_properties(props, true);
}
return props;
} catch (const std::exception& ex) {
PLOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
return reinterpret_cast<obs_properties_t*>(0);
} catch (...) {
PLOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
return reinterpret_cast<obs_properties_t*>(0);
}
static bool _update(void* ptr, obs_data_t* settings) noexcept try {
#ifdef DEBUG_CALL_ORDER
PLOG_INFO("%s %llX %llX", __FUNCTION_NAME__, ptr, settings);
@@ -386,6 +417,8 @@ void obsffmpeg::encoder_factory::register_encoder()
if (ffmpeg::tools::can_hardware_encode(avcodec_ptr)) {
info.oei.create = _create_texture;
info.oei.encode_texture = _encode_texture;
info.oei.get_defaults2 = _get_defaults_texture;
info.oei.get_properties2 = _get_properties_texture;
info_fallback.oei.type = info.oei.type;
info_fallback.oei.create = _create;
@@ -413,10 +446,10 @@ void obsffmpeg::encoder_factory::register_encoder()
avcodec_ptr->name, avcodec_ptr->long_name, avcodec_ptr->capabilities);
}
void obsffmpeg::encoder_factory::get_defaults(obs_data_t* settings)
void obsffmpeg::encoder_factory::get_defaults(obs_data_t* settings, bool hw_encode)
{
if (_handler)
_handler->get_defaults(settings, avcodec_ptr, nullptr);
_handler->get_defaults(settings, avcodec_ptr, nullptr, hw_encode);
if ((avcodec_ptr->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0) {
obs_data_set_default_int(settings, S_KEYFRAMES_INTERVALTYPE, 0);
@@ -427,8 +460,11 @@ void obsffmpeg::encoder_factory::get_defaults(obs_data_t* settings)
{ // Integrated Options
// FFmpeg
obs_data_set_default_string(settings, ST_FFMPEG_CUSTOMSETTINGS, "");
obs_data_set_default_int(settings, ST_FFMPEG_COLORFORMAT, static_cast<int64_t>(AV_PIX_FMT_NONE));
if (!hw_encode) {
obs_data_set_default_int(settings, ST_FFMPEG_COLORFORMAT,
static_cast<int64_t>(AV_PIX_FMT_NONE));
obs_data_set_default_int(settings, ST_FFMPEG_THREADS, 0);
}
obs_data_set_default_int(settings, ST_FFMPEG_STANDARDCOMPLIANCE, FF_COMPLIANCE_STRICT);
}
}
@@ -446,10 +482,10 @@ static bool modified_keyframes(obs_properties_t* props, obs_property_t*, obs_dat
return false;
}
void obsffmpeg::encoder_factory::get_properties(obs_properties_t* props)
void obsffmpeg::encoder_factory::get_properties(obs_properties_t* props, bool hw_encode)
{
if (_handler)
_handler->get_properties(props, avcodec_ptr, nullptr);
_handler->get_properties(props, avcodec_ptr, nullptr, hw_encode);
if ((avcodec_ptr->capabilities & AV_CODEC_CAP_INTRA_ONLY) == 0) {
// Key-Frame Options
@@ -498,9 +534,11 @@ void obsffmpeg::encoder_factory::get_properties(obs_properties_t* props)
obs_text_type::OBS_TEXT_DEFAULT);
obs_property_set_long_description(p, TRANSLATE(DESC(ST_FFMPEG_CUSTOMSETTINGS)));
}
if (!hw_encode) {
if (avcodec_ptr->pix_fmts) {
auto p = obs_properties_add_list(grp, ST_FFMPEG_COLORFORMAT, TRANSLATE(ST_FFMPEG_COLORFORMAT),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
auto p = obs_properties_add_list(grp, ST_FFMPEG_COLORFORMAT,
TRANSLATE(ST_FFMPEG_COLORFORMAT), OBS_COMBO_TYPE_LIST,
OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, TRANSLATE(DESC(ST_FFMPEG_COLORFORMAT)));
obs_property_list_add_int(p, TRANSLATE(S_STATE_AUTOMATIC),
static_cast<int64_t>(AV_PIX_FMT_NONE));
@@ -510,10 +548,12 @@ void obsffmpeg::encoder_factory::get_properties(obs_properties_t* props)
}
}
if (avcodec_ptr->capabilities & (AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)) {
auto p = obs_properties_add_int_slider(grp, ST_FFMPEG_THREADS, TRANSLATE(ST_FFMPEG_THREADS), 0,
std::thread::hardware_concurrency() * 2, 1);
auto p =
obs_properties_add_int_slider(grp, ST_FFMPEG_THREADS, TRANSLATE(ST_FFMPEG_THREADS),
0, std::thread::hardware_concurrency() * 2, 1);
obs_property_set_long_description(p, TRANSLATE(DESC(ST_FFMPEG_THREADS)));
}
}
{
auto p = obs_properties_add_list(grp, ST_FFMPEG_STANDARDCOMPLIANCE,
TRANSLATE(ST_FFMPEG_STANDARDCOMPLIANCE), OBS_COMBO_TYPE_LIST,
@@ -560,8 +600,7 @@ void obsffmpeg::encoder::initialize_sw(obs_data_t* settings)
static_cast<AVPixelFormat>(obs_data_get_int(settings, ST_FFMPEG_COLORFORMAT));
if (_pixfmt_target == AV_PIX_FMT_NONE) {
// Find the best conversion format.
std::vector<AVPixelFormat> fmts = ffmpeg::tools::get_software_formats(_codec->pix_fmts);
_pixfmt_target = ffmpeg::tools::get_best_compatible_format(fmts.data(), _pixfmt_source);
_pixfmt_target = ffmpeg::tools::get_least_lossy_format(_codec->pix_fmts, _pixfmt_source);
if (_handler) // Allow Handler to override the automatic color format for sanity reasons.
_handler->override_colorformat(_pixfmt_target, settings, _codec, _context);
@@ -612,15 +651,10 @@ void obsffmpeg::encoder::initialize_sw(obs_data_t* settings)
<< (_swscale.is_source_full_range() ? "full" : "partial") << " range.";
throw std::runtime_error(sstr.str());
}
// Create Frame queue
_frame_queue.set_pixel_format(_context->pix_fmt);
_frame_queue.set_resolution(_context->width, _context->height);
_frame_queue.precache(2);
}
}
void obsffmpeg::encoder::initialize_hw(obs_data_t* settings)
void obsffmpeg::encoder::initialize_hw(obs_data_t*)
{
// Initialize Video Encoding
auto voi = video_output_get_info(obs_encoder_video(_self));
@@ -655,6 +689,61 @@ void obsffmpeg::encoder::initialize_hw(obs_data_t* settings)
throw std::runtime_error("Failed to initialize AVHWFramesContext.");
}
void obsffmpeg::encoder::push_free_frame(std::shared_ptr<AVFrame> frame)
{
auto now = std::chrono::high_resolution_clock::now();
if (_free_frames.size() > 0) {
if ((now - _free_frames_last_used) < std::chrono::seconds(1)) {
_free_frames.push(frame);
}
} else {
_free_frames.push(frame);
_free_frames_last_used = std::chrono::high_resolution_clock::now();
}
}
std::shared_ptr<AVFrame> obsffmpeg::encoder::pop_free_frame()
{
std::shared_ptr<AVFrame> frame;
if (_free_frames.size() > 0) {
// Re-use existing frames first.
frame = _free_frames.top();
_free_frames.pop();
} else {
if (_hwinst) {
frame = _hwinst->allocate_frame(_context->hw_frames_ctx);
} else {
frame = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame* frame) {
av_frame_unref(frame);
av_frame_free(&frame);
});
frame->width = _context->width;
frame->height = _context->height;
frame->format = _context->pix_fmt;
int res = av_frame_get_buffer(frame.get(), 32);
if (res < 0) {
throw std::runtime_error(ffmpeg::tools::get_error_description(res));
}
}
}
return frame;
}
void obsffmpeg::encoder::push_used_frame(std::shared_ptr<AVFrame> frame)
{
_used_frames.push(frame);
}
std::shared_ptr<AVFrame> obsffmpeg::encoder::pop_used_frame()
{
auto frame = _used_frames.front();
_used_frames.pop();
return frame;
}
obsffmpeg::encoder::encoder(obs_data_t* settings, obs_encoder_t* encoder, bool is_texture_encode)
: _self(encoder), _lag_in_frames(0), _count_send_frames(0), _have_first_frame(false)
{
@@ -700,14 +789,27 @@ obsffmpeg::encoder::encoder(obs_data_t* settings, obs_encoder_t* encoder, bool i
// Log Encoder info
PLOG_INFO("[%s] Initializing...", _codec->name);
if (_hwinst) {
PLOG_INFO("[%s] Video Input: %ldx%ld %s %s %s", _codec->name, _context->width, _context->height,
ffmpeg::tools::get_pixel_format_name(_context->sw_pix_fmt),
ffmpeg::tools::get_color_space_name(_context->colorspace),
_swscale.is_source_full_range() ? "Full" : "Partial");
PLOG_INFO("[%s] Video Output: %ldx%ld %s %s %s", _codec->name, _context->width, _context->height,
ffmpeg::tools::get_pixel_format_name(_context->sw_pix_fmt),
ffmpeg::tools::get_color_space_name(_context->colorspace),
_swscale.is_target_full_range() ? "Full" : "Partial");
} else {
PLOG_INFO("[%s] Video Input: %ldx%ld %s %s %s", _codec->name, _swscale.get_source_width(),
_swscale.get_source_height(), ffmpeg::tools::get_pixel_format_name(_swscale.get_source_format()),
_swscale.get_source_height(),
ffmpeg::tools::get_pixel_format_name(_swscale.get_source_format()),
ffmpeg::tools::get_color_space_name(_swscale.get_source_colorspace()),
_swscale.is_source_full_range() ? "Full" : "Partial");
PLOG_INFO("[%s] Video Output: %ldx%ld %s %s %s", _codec->name, _swscale.get_target_width(),
_swscale.get_target_height(), ffmpeg::tools::get_pixel_format_name(_swscale.get_target_format()),
_swscale.get_target_height(),
ffmpeg::tools::get_pixel_format_name(_swscale.get_target_format()),
ffmpeg::tools::get_color_space_name(_swscale.get_target_colorspace()),
_swscale.is_target_full_range() ? "Full" : "Partial");
}
PLOG_INFO("[%s] Framerate: %ld/%ld (%f FPS)", _codec->name, _context->time_base.den, _context->time_base.num,
static_cast<double_t>(_context->time_base.den) / static_cast<double_t>(_context->time_base.num));
PLOG_INFO("[%s] Custom Settings: %s", _codec->name, obs_data_get_string(settings, ST_FFMPEG_CUSTOMSETTINGS));
@@ -744,15 +846,13 @@ obsffmpeg::encoder::~encoder()
av_packet_unref(&_current_packet);
_frame_queue.clear();
_frame_queue_used.clear();
_swscale.finalize();
}
void obsffmpeg::encoder::get_properties(obs_properties_t* props)
void obsffmpeg::encoder::get_properties(obs_properties_t* props, bool hw_encode)
{
if (_handler)
_handler->get_properties(props, _codec, _context);
_handler->get_properties(props, _codec, _context, hw_encode);
obs_property_set_enabled(obs_properties_get(props, S_KEYFRAMES), false);
obs_property_set_enabled(obs_properties_get(props, S_KEYFRAMES_INTERVALTYPE), false);
@@ -771,8 +871,8 @@ bool obsffmpeg::encoder::update(obs_data_t* settings)
_context->strict_std_compliance = static_cast<int>(obs_data_get_int(settings, ST_FFMPEG_STANDARDCOMPLIANCE));
_context->debug = 0;
/// Threading
if (_codec->capabilities
& (AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)) {
if (_codec->capabilities & (AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS)
&& !_hwinst) {
if (_codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
_context->thread_type |= FF_THREAD_FRAME;
}
@@ -787,6 +887,10 @@ bool obsffmpeg::encoder::update(obs_data_t* settings)
_context->thread_count = std::thread::hardware_concurrency();
_lag_in_frames = _context->thread_count;
}
} else {
_context->thread_count = 1;
_context->thread_type = 0;
_lag_in_frames = 1;
}
if (_handler)
@@ -817,6 +921,9 @@ bool obsffmpeg::encoder::update(obs_data_t* settings)
nullptr, "=", ";");
}
if (_handler)
_handler->override_lag_in_frames(_lag_in_frames, settings, _codec, _context);
// Handler Logging
if (_handler)
_handler->log_options(settings, _codec, _context);
@@ -895,8 +1002,9 @@ static inline void copy_data(encoder_frame* frame, AVFrame* vframe)
bool obsffmpeg::encoder::video_encode(encoder_frame* frame, encoder_packet* packet, bool* received_packet)
{
std::shared_ptr<AVFrame> vframe = pop_free_frame(); // Retrieve an empty frame.
// Convert frame.
std::shared_ptr<AVFrame> vframe = _frame_queue.pop(); // Retrieve an empty frame.
{
#ifdef _DEBUG
ScopeProfiler profile("convert");
@@ -929,10 +1037,6 @@ bool obsffmpeg::encoder::video_encode(encoder_frame* frame, encoder_packet* pack
if (!encode_avframe(vframe, packet, received_packet))
return false;
if (vframe != nullptr) {
_frame_queue.push(vframe);
}
return true;
}
@@ -945,12 +1049,8 @@ bool obsffmpeg::encoder::video_encode_texture(uint32_t handle, int64_t pts, uint
return false;
}
std::shared_ptr<AVFrame> frame{av_frame_alloc(), [](void* ptr) {
av_frame_unref(reinterpret_cast<AVFrame*>(ptr));
av_frame_free(reinterpret_cast<AVFrame**>(&ptr));
}};
std::shared_ptr<AVFrame> vframe = _hwinst->avframe_from_obs(_context->hw_frames_ctx, handle, lock_key, next_lock_key);
std::shared_ptr<AVFrame> vframe = pop_free_frame();
_hwinst->copy_from_obs(_context->hw_frames_ctx, handle, lock_key, next_lock_key, vframe);
vframe->color_range = _context->color_range;
vframe->colorspace = _context->colorspace;
@@ -971,7 +1071,10 @@ int obsffmpeg::encoder::receive_packet(bool* received_packet, struct encoder_pac
av_packet_unref(&_current_packet);
int res = avcodec_receive_packet(_context, &_current_packet);
if (res == 0) {
if (res != 0) {
return res;
}
if (!_have_first_frame) {
if (_codec->id == AV_CODEC_ID_H264) {
uint8_t* tmp_packet;
@@ -979,8 +1082,8 @@ int obsffmpeg::encoder::receive_packet(bool* received_packet, struct encoder_pac
uint8_t* tmp_sei;
size_t sz_packet, sz_header, sz_sei;
obs_extract_avc_headers(_current_packet.data, _current_packet.size, &tmp_packet,
&sz_packet, &tmp_header, &sz_header, &tmp_sei, &sz_sei);
obs_extract_avc_headers(_current_packet.data, _current_packet.size, &tmp_packet, &sz_packet,
&tmp_header, &sz_header, &tmp_sei, &sz_sei);
if (sz_header) {
_extra_data.resize(sz_header);
@@ -1022,11 +1125,7 @@ int obsffmpeg::encoder::receive_packet(bool* received_packet, struct encoder_pac
packet->drop_priority = packet->keyframe ? 0 : 1;
*received_packet = true;
{
std::shared_ptr<AVFrame> uframe = _frame_queue_used.pop_only();
_frame_queue.push(uframe);
}
}
push_free_frame(pop_used_frame());
return res;
}
@@ -1034,19 +1133,14 @@ int obsffmpeg::encoder::receive_packet(bool* received_packet, struct encoder_pac
int obsffmpeg::encoder::send_frame(std::shared_ptr<AVFrame> const frame)
{
int res = avcodec_send_frame(_context, frame.get());
switch (res) {
case 0:
if (!_hwapi)
_frame_queue_used.push(frame);
_count_send_frames++;
case AVERROR(EAGAIN):
case AVERROR(EOF):
break;
if (res == 0) {
push_used_frame(frame);
}
return res;
}
bool obsffmpeg::encoder::encode_avframe(std::shared_ptr<AVFrame>& frame, encoder_packet* packet, bool* received_packet)
bool obsffmpeg::encoder::encode_avframe(std::shared_ptr<AVFrame> frame, encoder_packet* packet, bool* received_packet)
{
#ifdef _DEBUG
ScopeProfiler profile("loop");
@@ -1054,7 +1148,7 @@ bool obsffmpeg::encoder::encode_avframe(std::shared_ptr<AVFrame>& frame, encoder
bool sent_frame = false;
bool recv_packet = false;
bool should_lag = (_lag_in_frames - _count_send_frames) <= 0;
bool should_lag = (_count_send_frames >= _lag_in_frames);
auto loop_begin = std::chrono::high_resolution_clock::now();
auto loop_end = loop_begin + std::chrono::milliseconds(50);
@@ -1127,5 +1221,8 @@ bool obsffmpeg::encoder::encode_avframe(std::shared_ptr<AVFrame>& frame, encoder
}
}
if (!sent_frame)
push_free_frame(frame);
return true;
}
+20 -10
View File
@@ -23,6 +23,8 @@
#include <condition_variable>
#include <mutex>
#include <queue>
#include <stack>
#include <thread>
#include <vector>
#include "ffmpeg/avframe-queue.hpp"
@@ -50,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 {
@@ -66,9 +68,9 @@ namespace obsffmpeg {
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();
@@ -83,36 +85,44 @@ namespace obsffmpeg {
const AVCodec* _codec;
AVCodecContext* _context;
AVHWFramesContext* _hwcontext;
std::shared_ptr<obsffmpeg::ui::handler> _handler;
std::shared_ptr<obsffmpeg::hwapi::base> _hwapi;
std::shared_ptr<obsffmpeg::hwapi::instance> _hwinst;
ffmpeg::avframe_queue _frame_queue;
ffmpeg::avframe_queue _frame_queue_used;
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);
@@ -139,7 +149,7 @@ namespace obsffmpeg {
int send_frame(std::shared_ptr<AVFrame> frame);
bool encode_avframe(std::shared_ptr<AVFrame>& frame, struct encoder_packet* packet,
bool encode_avframe(std::shared_ptr<AVFrame> frame, struct encoder_packet* packet,
bool* received_packet);
};
} // namespace obsffmpeg
-100
View File
@@ -279,106 +279,6 @@ 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)
{
double_t score = std::numeric_limits<double_t>::min();
AVPixelFormat best = source;
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)) {
score = found->second;
best = *fmt;
}
}
if (score <= 0) {
int data_loss = 0;
return avcodec_find_best_pix_fmt_of_list(list, source, 0, &data_loss);
}
return best;
}
void ffmpeg::tools::setup_obs_color(video_colorspace colorspace, video_range_type range, AVCodecContext* context)
{
std::map<video_colorspace, std::tuple<AVColorSpace, AVColorPrimaries, AVColorTransferCharacteristic>>
-2
View File
@@ -56,8 +56,6 @@ 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);
} // namespace tools
} // namespace ffmpeg
+8 -1
View File
@@ -23,6 +23,7 @@
#include <cinttypes>
#include <list>
#include <memory>
#include <string>
#include <utility>
@@ -54,7 +55,13 @@ namespace obsffmpeg {
public:
virtual AVBufferRef* create_device_context() = 0;
virtual std::shared_ptr<AVFrame> avframe_from_obs(AVBufferRef* frames, uint32_t handle, uint64_t lock_key,
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
+25 -18
View File
@@ -157,20 +157,31 @@ AVBufferRef* obsffmpeg::hwapi::d3d11_instance::create_device_context()
return dctx_ref;
}
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)
std::shared_ptr<AVFrame> obsffmpeg::hwapi::d3d11_instance::allocate_frame(AVBufferRef* frames)
{
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)
{
AVFrame* frame = av_frame_alloc();
ATL::CComPtr<IDXGIKeyedMutex> mutex;
ATL::CComPtr<ID3D11Texture2D> input;
D3D11_TEXTURE2D_DESC input_desc;
D3D11_TEXTURE2D_DESC output_desc;
//ATL::CComPtr<ID3D11Texture2D> output;
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.");
}
@@ -182,13 +193,6 @@ std::shared_ptr<AVFrame> obsffmpeg::hwapi::d3d11_instance::avframe_from_obs(AVBu
// Set some parameters on the input texture, and get its description.
UINT evict = input->GetEvictionPriority();
input->SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
input->GetDesc(&input_desc);
if (av_hwframe_get_buffer(frames, frame, 0) < 0) {
throw std::runtime_error("Failed to create AVFrame.");
}
reinterpret_cast<ID3D11Texture2D*>(frame->data[0])->GetDesc(&output_desc);
// Clone the content of the input texture.
_context->CopyResource(reinterpret_cast<ID3D11Texture2D*>(frame->data[0]), input);
@@ -202,9 +206,12 @@ std::shared_ptr<AVFrame> obsffmpeg::hwapi::d3d11_instance::avframe_from_obs(AVBu
// TODO: Determine if this is necessary.
mutex->ReleaseSync(*next_lock_key);
return std::shared_ptr<AVFrame>(frame, [](AVFrame* frame) {
av_frame_unref(frame);
av_frame_free(&frame);
});
}
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 frame = this->allocate_frame(frames);
this->copy_from_obs(frames, handle, lock_key, next_lock_key, frame);
return frame;
}
+8 -3
View File
@@ -21,13 +21,13 @@
#include <atlutil.h>
#include <d3d11.h>
#include <d3d11_1.h>
#include <dxgi.h>
#include <windows.h>
#include "base.hpp"
namespace obsffmpeg {
namespace hwapi {
class d3d11 : public base {
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,
@@ -55,7 +55,7 @@ namespace obsffmpeg {
create(obsffmpeg::hwapi::device target) override;
};
class d3d11_instance : public instance {
class d3d11_instance : public ::obsffmpeg::hwapi::instance {
ATL::CComPtr<ID3D11Device> _device;
ATL::CComPtr<ID3D11DeviceContext> _context;
@@ -65,6 +65,11 @@ namespace obsffmpeg {
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;
+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;
+13 -16
View File
@@ -23,34 +23,31 @@
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_info(obs_encoder_info*, obs_encoder_info*) {}
void obsffmpeg::ui::handler::override_colorformat(AVPixelFormat& target_format, obs_data_t* settings,
const AVCodec* codec, AVCodecContext* context)
{}
void obsffmpeg::ui::handler::override_colorformat(AVPixelFormat&, obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::handler::get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) {}
void obsffmpeg::ui::handler::override_lag_in_frames(size_t&, obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::handler::get_properties(obs_properties_t* props, const AVCodec* codec, AVCodecContext* context) {}
void obsffmpeg::ui::handler::get_defaults(obs_data_t*, const AVCodec*, AVCodecContext*, bool) {}
obsffmpeg::hwapi::device obsffmpeg::ui::handler::find_hw_device(std::shared_ptr<obsffmpeg::hwapi::base> api,
const AVCodec* codec, AVCodecContext* context)
void obsffmpeg::ui::handler::get_properties(obs_properties_t*, const AVCodec*, AVCodecContext*, bool) {}
obsffmpeg::hwapi::device obsffmpeg::ui::handler::find_hw_device(std::shared_ptr<obsffmpeg::hwapi::base>, const AVCodec*,
AVCodecContext*)
{
return obsffmpeg::hwapi::device();
}
void obsffmpeg::ui::handler::update(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) {}
void obsffmpeg::ui::handler::update(obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::handler::log_options(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context) {}
void obsffmpeg::ui::handler::log_options(obs_data_t*, const AVCodec*, AVCodecContext*) {}
void obsffmpeg::ui::handler::import_from_ffmpeg(const std::string ffmpeg, obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
{}
void obsffmpeg::ui::handler::import_from_ffmpeg(const std::string, obs_data_t*, const AVCodec*, AVCodecContext*) {}
std::string obsffmpeg::ui::handler::export_for_ffmpeg(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
std::string obsffmpeg::ui::handler::export_for_ffmpeg(obs_data_t*, const AVCodec*, AVCodecContext*)
{
return std::string();
}
void obsffmpeg::ui::handler::process_avpacket(AVPacket& packet, const AVCodec* codec, AVCodecContext* context) {}
void obsffmpeg::ui::handler::process_avpacket(AVPacket&, const AVCodec*, AVCodecContext*) {}
+5 -2
View File
@@ -47,10 +47,13 @@ namespace obsffmpeg {
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);
virtual void override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context);
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context, bool hw_encode);
virtual void get_properties(obs_properties_t* props, const AVCodec* codec,
AVCodecContext* context);
AVCodecContext* context, bool hw_encode);
virtual obsffmpeg::hwapi::device find_hw_device(std::shared_ptr<obsffmpeg::hwapi::base> api,
const AVCodec* codec, AVCodecContext* context);
+8 -2
View File
@@ -85,8 +85,14 @@ void obsffmpeg::ui::nvenc_h264_handler::override_visible_name(const AVCodec*, st
name = "H.264/AVC Encoder (NVidia NVENC)";
}
void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
void obsffmpeg::ui::nvenc_h264_handler::override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
{
nvenc::override_lag_in_frames(lag, settings, codec, context);
}
void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context, bool)
{
nvenc::get_defaults(settings, codec, context);
@@ -95,7 +101,7 @@ void obsffmpeg::ui::nvenc_h264_handler::get_defaults(obs_data_t* settings, const
}
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);
+5 -2
View File
@@ -36,11 +36,14 @@ namespace obsffmpeg {
public:
virtual void override_visible_name(const AVCodec* codec, std::string& name) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
virtual void override_lag_in_frames(size_t& lag, 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;
+8 -2
View File
@@ -87,8 +87,14 @@ void obsffmpeg::ui::nvenc_hevc_handler::override_visible_name(const AVCodec*, st
name = "H.265/HEVC Encoder (NVidia NVENC)";
}
void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
void obsffmpeg::ui::nvenc_hevc_handler::override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context)
{
nvenc::override_lag_in_frames(lag, settings, codec, context);
}
void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context, bool)
{
nvenc::get_defaults(settings, codec, context);
@@ -98,7 +104,7 @@ void obsffmpeg::ui::nvenc_hevc_handler::get_defaults(obs_data_t* settings, const
}
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);
+5 -2
View File
@@ -36,11 +36,14 @@ namespace obsffmpeg {
public:
virtual void override_visible_name(const AVCodec* codec, std::string& name) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
virtual void override_lag_in_frames(size_t& lag, 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;
+15 -1
View File
@@ -20,6 +20,7 @@
// SOFTWARE.
#include "nvenc_shared.hpp"
#include <algorithm>
#include "codecs/hevc.hpp"
#include "plugin.hpp"
#include "strings.hpp"
@@ -131,6 +132,19 @@ std::map<b_ref_mode, std::string> obsffmpeg::nvenc::b_ref_mode_to_opt{
{b_ref_mode::MIDDLE, "middle"},
};
void obsffmpeg::nvenc::override_lag_in_frames(size_t& lag, obs_data_t*, const AVCodec*, AVCodecContext* context)
{
// With NVENC, the number of frames lagged before we get our first
// packet is determined by the number of b-frames. Threads, lookahead
// frames and various other settings are ignored.
// The minimum number of lagged frames is 1.
int64_t rcla = 0;
av_opt_get_int(context, "rc-lookahead", AV_OPT_SEARCH_CHILDREN, &rcla);
lag = static_cast<size_t>(std::max(1ll + static_cast<int64_t>(context->max_b_frames), rcla));
}
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));
@@ -678,7 +692,7 @@ void obsffmpeg::nvenc::log_options(obs_data_t* settings, const AVCodec* codec, A
bool cfg_rc_quality = obs_data_get_bool(settings, ST_RATECONTROL_QUALITY);
int64_t cfg_rc_quality_min = obs_data_get_int(settings, ST_RATECONTROL_QUALITY_MINIMUM);
int64_t cfg_rc_quality_max = obs_data_get_int(settings, ST_RATECONTROL_QUALITY_MAXIMUM);
double_t cfg_rc_quality_tgt = obs_data_get_int(settings, ST_RATECONTROL_QUALITY_TARGET);
double_t cfg_rc_quality_tgt = obs_data_get_double(settings, ST_RATECONTROL_QUALITY_TARGET) / 100.0 * 51.0;
int64_t cfg_rc_qp_i = obs_data_get_int(settings, ST_RATECONTROL_QP_I);
int64_t cfg_rc_qp_p = obs_data_get_int(settings, ST_RATECONTROL_QP_P);
int64_t cfg_rc_qp_b = obs_data_get_int(settings, ST_RATECONTROL_QP_B);
+3
View File
@@ -75,6 +75,9 @@ namespace obsffmpeg {
extern std::map<b_ref_mode, std::string> b_ref_mode_to_opt;
void override_lag_in_frames(size_t& lag, obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context);
void get_defaults(obs_data_t* settings, const AVCodec* codec, AVCodecContext* context);
void get_properties_pre(obs_properties_t* props, const AVCodec* codec);
+5 -5
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),
@@ -105,7 +105,7 @@ 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* context)
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)))
@@ -113,7 +113,7 @@ void obsffmpeg::ui::prores_aw_handler::log_options(obs_data_t* settings, const A
}
}
void obsffmpeg::ui::prores_aw_handler::process_avpacket(AVPacket& packet, const AVCodec* codec, AVCodecContext* context)
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
+2 -2
View File
@@ -38,10 +38,10 @@ namespace obsffmpeg {
const AVCodec* codec, AVCodecContext* context) override;
virtual void get_defaults(obs_data_t* settings, const AVCodec* codec,
AVCodecContext* context) override;
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;