Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 78 additions & 20 deletions src/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1029,9 +1029,11 @@ std::optional<session_t> make_session(const encoder_t &encoder, const config_t &
ctx->bit_rate = bitrate;
ctx->rc_min_rate = bitrate;

if(!hardware && ctx->slices > 1) {
if(!hardware && (ctx->slices > 1 || config.videoFormat != 0)) {
// Use a larger rc_buffer_size for software encoding when slices are enabled,
// because libx264 can severely degrade quality if the buffer is too small.
// libx265 encounters this issue more frequently, so always scale the
// buffer by 1.5x for software HEVC encoding.
ctx->rc_buffer_size = bitrate / ((config.framerate * 10) / 15);
}
else {
Expand Down Expand Up @@ -1694,36 +1696,92 @@ bool validate_encoder(encoder_t &encoder) {
}

int init() {
BOOST_LOG(info) << "// Testing for available encoders, this may generate errors. You can safely ignore those errors. //"sv;
bool encoder_found = false;
if(!config::video.encoder.empty()) {
// If there is a specific encoder specified, use it if it passes validation
KITTY_WHILE_LOOP(auto pos = std::begin(encoders), pos != std::end(encoders), {
auto encoder = *pos;

if(encoder.name == config::video.encoder) {
// Remove the encoder from the list entirely if it fails validation
if(!validate_encoder(encoder)) {
pos = encoders.erase(pos);
break;
}

KITTY_WHILE_LOOP(auto pos = std::begin(encoders), pos != std::end(encoders), {
if(
(!config::video.encoder.empty() && pos->name != config::video.encoder) ||
!validate_encoder(*pos) ||
(config::video.hevc_mode == 3 && !pos->hevc[encoder_t::DYNAMIC_RANGE])) {
pos = encoders.erase(pos);
// If we can't satisfy both the encoder and HDR requirement, prefer the encoder over HDR support
if(config::video.hevc_mode == 3 && !encoder.hevc[encoder_t::DYNAMIC_RANGE]) {
BOOST_LOG(warning) << "Encoder ["sv << config::video.encoder << "] does not support HDR on this system"sv;
config::video.hevc_mode = 0;
}

continue;
encoders.clear();
encoders.emplace_back(encoder);
encoder_found = true;
break;
}

pos++;
});

if(!encoder_found) {
BOOST_LOG(error) << "Couldn't find any working encoder matching ["sv << config::video.encoder << ']';
config::video.encoder.clear();
}
}

break;
})
BOOST_LOG(info) << "// Testing for available encoders, this may generate errors. You can safely ignore those errors. //"sv;

BOOST_LOG(info);
BOOST_LOG(info) << "// Ignore any errors mentioned above, they are not relevant. //"sv;
BOOST_LOG(info);
// If we haven't found an encoder yet but we want one with HDR support, search for that now.
if(!encoder_found && config::video.hevc_mode == 3) {
KITTY_WHILE_LOOP(auto pos = std::begin(encoders), pos != std::end(encoders), {
auto encoder = *pos;

if(encoders.empty()) {
if(config::video.encoder.empty()) {
BOOST_LOG(fatal) << "Couldn't find any encoder"sv;
}
else {
BOOST_LOG(fatal) << "Couldn't find any encoder matching ["sv << config::video.encoder << ']';
// Remove the encoder from the list entirely if it fails validation
if(!validate_encoder(encoder)) {
pos = encoders.erase(pos);
continue;
}

// Skip it if it doesn't support HDR
if(!encoder.hevc[encoder_t::DYNAMIC_RANGE]) {
pos++;
continue;
}

encoders.clear();
encoders.emplace_back(encoder);
encoder_found = true;
break;
});

if(!encoder_found) {
BOOST_LOG(error) << "Couldn't find any working HDR-capable encoder"sv;
}
}

// If no encoder was specified or the specified encoder was unusable, keep trying
// the remaining encoders until we find one that passes validation.
if(!encoder_found) {
KITTY_WHILE_LOOP(auto pos = std::begin(encoders), pos != std::end(encoders), {
if(!validate_encoder(*pos)) {
pos = encoders.erase(pos);
continue;
}

break;
});
}

if(encoders.empty()) {
BOOST_LOG(fatal) << "Couldn't find any working encoder"sv;
return -1;
}

BOOST_LOG(info);
BOOST_LOG(info) << "// Ignore any errors mentioned above, they are not relevant. //"sv;
BOOST_LOG(info);

auto &encoder = encoders.front();

BOOST_LOG(debug) << "------ h264 ------"sv;
Expand Down