Skip to content

Commit

Permalink
feat(vaapi): add option to enable strict enforcement of frame size
Browse files Browse the repository at this point in the history
  • Loading branch information
cgutman committed Oct 31, 2024
1 parent ec0cdcf commit 8465fa6
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 8 deletions.
27 changes: 27 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2303,6 +2303,33 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>

## VA-API Encoder

### vaapi_strict_rc_buffer

<table>
<tr>
<td>Description</td>
<td colspan="2">
Enabling this option can avoid dropped frames over the network during scene changes, but video quality may
be reduced during motion.
@note{This option only applies for H.264 and HEVC when using VA-API [encoder](#encoder) on AMD GPUs.}
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
disabled
@endcode</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
vaapi_strict_rc_buffer = enabled
@endcode</td>
</tr>
</table>

## Software Encoder

### sw_preset
Expand Down
6 changes: 6 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ namespace config {
-1,
}, // vt

{
false, // strict_rc_buffer
}, // vaapi

{}, // capture
{}, // encoder
{}, // adapter_name
Expand Down Expand Up @@ -1014,6 +1018,8 @@ namespace config {
int_f(vars, "vt_software", video.vt.vt_require_sw, vt::force_software_from_view);
int_f(vars, "vt_realtime", video.vt.vt_realtime, vt::rt_from_view);

bool_f(vars, "vaapi_strict_rc_buffer", video.vaapi.strict_rc_buffer);

string_f(vars, "capture", video.capture);
string_f(vars, "encoder", video.encoder);
string_f(vars, "adapter_name", video.adapter_name);
Expand Down
4 changes: 4 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ namespace config {
int vt_coder;
} vt;

struct {
bool strict_rc_buffer;
} vaapi;

std::string capture;
std::string encoder;
std::string adapter_name;
Expand Down
2 changes: 1 addition & 1 deletion src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ namespace platf {
* @note Implementations may set or modify codec options prior to codec initialization.
*/
virtual void
init_codec_options(AVCodecContext *ctx, AVDictionary *options) {};
init_codec_options(AVCodecContext *ctx, AVDictionary **options) {};

/**
* @brief Prepare to derive a context.
Expand Down
21 changes: 17 additions & 4 deletions src/platform/linux/vaapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,24 @@ namespace va {
}

void
init_codec_options(AVCodecContext *ctx, AVDictionary *options) override {
// Don't set the RC buffer size when using H.264 on Intel GPUs. It causes
// major encoding quality degradation.
init_codec_options(AVCodecContext *ctx, AVDictionary **options) override {

Check warning on line 133 in src/platform/linux/vaapi.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/vaapi.cpp#L133

Added line #L133 was not covered by tests
auto vendor = vaQueryVendorString(va_display);
if (ctx->codec_id != AV_CODEC_ID_H264 || (vendor && !strstr(vendor, "Intel"))) {

// Use VBR with a single frame VBV when the user forces it and for known good cases:
// - Intel GPUs
// - AV1
//
// VBR ensures the bitstream isn't full of filler data for bitrate undershoots and
// single frame VBV ensures that we don't have large bitrate overshoots (at least
// as much as they can be avoided without pre-analysis).
//
// When we have to resort to the default 1 second VBV for encoding quality reasons,
// we stick to CBR in order to avoid encoding huge frames after bitrate undershoots
// leave headroom available in the RC window.
if (config::video.vaapi.strict_rc_buffer ||
(vendor && strstr(vendor, "Intel")) ||
ctx->codec_id == AV_CODEC_ID_AV1) {
av_dict_set(options, "rc_mode", "VBR", 0);

Check warning on line 150 in src/platform/linux/vaapi.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/vaapi.cpp#L150

Added line #L150 was not covered by tests
ctx->rc_buffer_size = ctx->bit_rate * ctx->framerate.den / ctx->framerate.num;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1696,7 +1696,7 @@ namespace video {
}

// Allow the encoding device a final opportunity to set/unset or override any options
encode_device->init_codec_options(ctx.get(), options);
encode_device->init_codec_options(ctx.get(), &options);

if (auto status = avcodec_open2(ctx.get(), codec, &options)) {
char err_str[AV_ERROR_MAX_STRING_SIZE] { 0 };
Expand Down
11 changes: 9 additions & 2 deletions src_assets/common/assets/web/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,13 @@ <h1 class="my-4">{{ $t('config.configuration') }}</h1>
"vt_realtime": "enabled",
},
},
{
id: "vaapi",
name: "VA-API Encoder",
options: {
"vaapi_strict_rc_buffer": "disabled",
},
},
{
id: "sw",
name: "Software Encoder",
Expand All @@ -283,7 +290,7 @@ <h1 class="my-4">{{ $t('config.configuration') }}</h1>
var app = document.getElementById("app");
if (this.platform === "windows") {
this.tabs = this.tabs.filter((el) => {
return el.id !== "vt";
return el.id !== "vt" && el.id !== "vaapi";
});
}
if (this.platform === "linux") {
Expand All @@ -293,7 +300,7 @@ <h1 class="my-4">{{ $t('config.configuration') }}</h1>
}
if (this.platform === "macos") {
this.tabs = this.tabs.filter((el) => {
return el.id !== "amd" && el.id !== "nv" && el.id !== "qsv";
return el.id !== "amd" && el.id !== "nv" && el.id !== "qsv" && el.id !== "vaapi";
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import IntelQuickSyncEncoder from './encoders/IntelQuickSyncEncoder.vue'
import AmdAmfEncoder from './encoders/AmdAmfEncoder.vue'
import VideotoolboxEncoder from './encoders/VideotoolboxEncoder.vue'
import SoftwareEncoder from './encoders/SoftwareEncoder.vue'
import VAAPIEncoder from './encoders/VAAPIEncoder.vue'
const props = defineProps([
'platform',
Expand Down Expand Up @@ -45,6 +46,13 @@ const config = ref(props.config)
:config="config"
/>

<!-- VAAPI Encoder Tab -->
<VAAPIEncoder
v-if="currentTab === 'vaapi'"
:platform="platform"
:config="config"
/>

<!-- Software Encoder Tab -->
<SoftwareEncoder
v-if="currentTab === 'sw'"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup>
import { ref } from 'vue'
const props = defineProps([
'platform',
'config',
])
const config = ref(props.config)
</script>

<template>
<div id="vaapi-encoder" class="config-page">
<!-- Strict RC Buffer -->
<div class="mb-3">
<label for="vaapi_strict_rc_buffer" class="form-label">{{ $t('config.vaapi_strict_rc_buffer') }}</label>
<select id="vaapi_strict_rc_buffer" class="form-select" v-model="config.vaapi_strict_rc_buffer">
<option value="enabled">{{ $t('_common.enabled') }}</option>
<option value="disabled">{{ $t('_common.disabled') }}</option>
</select>
<div class="form-text">{{ $t('config.vaapi_strict_rc_buffer_desc') }}</div>
</div>
</div>
</template>

<style scoped>
</style>
2 changes: 2 additions & 0 deletions src_assets/common/assets/web/public/assets/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@
"touchpad_as_ds4_desc": "If disabled, touchpad presence will not be taken into account during gamepad type selection.",
"upnp": "UPnP",
"upnp_desc": "Automatically configure port forwarding for streaming over the Internet",
"vaapi_strict_rc_buffer": "Strictly enforce frame bitrate limits for H.264/HEVC on AMD GPUs",
"vaapi_strict_rc_buffer_desc": "Enabling this option can avoid dropped frames over the network during scene changes, but video quality may be reduced during motion.",
"virtual_sink": "Virtual Sink",
"virtual_sink_desc": "Manually specify a virtual audio device to use. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection!",
"virtual_sink_placeholder": "Steam Streaming Speakers",
Expand Down

0 comments on commit 8465fa6

Please sign in to comment.