Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to encode using baseline/constrained baseline. #1932

Merged

Conversation

20kdc
Copy link
Contributor

@20kdc 20kdc commented Dec 17, 2023

To be clear, this commit was only tested (and I only have the hardware to test it) with PhoneVR.
EDIT: I did manage to get PhoneVR running to test this commit on master with PhoneVR.

In addition, I have not tested this code on all platforms. I've made a best-effort attempt to get it to work, but I don't know if it will fail on Windows, or on an NVIDIA graphics card, etc. As long as everything compiles and nothing changes if the option is not activated, it should be okay, though.

This commit allows encoding using baseline/constrained baseline. This may improve hardware compatibility, and allows for the "software decoders of last resort" which (according to Moonlight code comments (https://github.com/moonlight-stream/moonlight-android/blob/master/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java#L90) ) do not like High profile/etc.

I'm unsure if this should be a boolean setting as it is now or be treated like another codec.

Copy link
Member

@zarik5 zarik5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having a flag for enabling Baseline profile, I would make an enum for Baseline, Main and High.

Comment on lines 108 to 111
auto sessionSettings = v.get("session_settings");
auto sessionVideo = sessionSettings.get("video");

m_h264UseBaselineProfile = sessionVideo.get("h264_use_baseline_profile").get<bool>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you write this code like this, SteamVR will not restart when this setting has been changed. Please check how the other settings are passed to SteamVR and do something similar.

help = "Whenever possible, attempts to force the 'baseline profile' or the 'constrained baseline profile' to increase compatibility with varying mobile devices. Only has an effect for h264 and may not have an effect for some configurations."
))]
#[schema(flag = "steamvr-restart")]
pub h264_use_baseline_profile: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put the setting inside EncoderConfig.

@zarik5
Copy link
Member

zarik5 commented Dec 18, 2023

Another option is to always force Baseline. I believe this should reduce latency a little bit, although quality may be worse. More people should test this PR

amfEncoder->SetProperty(AMF_VIDEO_ENCODER_PROFILE, AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE);
} else {
amfEncoder->SetProperty(AMF_VIDEO_ENCODER_PROFILE, AMF_VIDEO_ENCODER_PROFILE_HIGH);
amfEncoder->SetProperty(AMF_VIDEO_ENCODER_PROFILE_LEVEL, 42);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move profile level outside the condition. This is common for both profiles.

@deiteris
Copy link
Collaborator

deiteris commented Dec 22, 2023

Another option is to always force Baseline. I believe this should reduce latency a little bit, although quality may be worse. More people should test this PR

I'd suggest to keep Main and High profiles since it doesn't make much difference on modern decoders. But need to gather numbers on both encoder/decoder to see the actual impact.

@20kdc
Copy link
Contributor Author

20kdc commented Dec 22, 2023

Hopefully deals with all the reviews, but with that said this PR needs a lot of testing. I avoided trying to implement support for NVENC on Windows owing to the likelihood that a misconfiguration here would lead to breakage (there are many other options and this can affect the exposed profile), and the Linux-SW-x264 driver seems to always use Constrained Baseline regardless of what's passed.

I'm not sure why x264 support on Windows uses ffmpeg, and I'm really not sure why that's the case while it's different for Linux. Not the purpose of this PR, though.

@ShootingKing-AM
Copy link
Member

Tested on Windows 10 and NVIDIA seems to work fine, but based on ALVR stats page I see neither loss nor gain in perf/quality. Tested all Profiles.

@20kdc
Copy link
Contributor Author

20kdc commented Dec 23, 2023

That would be because I avoided implementing support for NVENC on Windows because it seemed risky (the mechanism used for profile selection seems like it could lead to failures). Should I do so anyway?

@ShootingKing-AM
Copy link
Member

ShootingKing-AM commented Dec 24, 2023

I used h264 encoding option through ALVR settings

Comment on lines +433 to +440
pub enum H264Profile {
#[schema(strings(display_name = "High"))]
High = 0,
#[schema(strings(display_name = "Main"))]
Main = 1,
#[schema(strings(display_name = "Baseline"))]
Baseline = 2,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's more natural to have Baseline as 0th index, then Main then High. Also, you don't need to specify the display_name, as in this case the dashboard is able to figure it out by itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High was set as zeroth index because I was uncertain of the behaviour of certain defaults. In most safe languages, values which are not strictly defined but are initialized end up zero. Rust is not necessarily the same, but there is also C++ code involved with no default value provided when reading from the JSON. I do not know the behaviour of this code on error, so I decided the zero value should be the default value, so the behaviour is as consistent as reasonably possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too opinionated, that's ok then.

@@ -1165,6 +1184,9 @@ pub fn session_settings_default() -> SettingsDefault {
variant: RateControlModeDefaultVariant::Cbr,
},
filler_data: false,
h264_profile: H264ProfileDefault {
variant: H264ProfileDefaultVariant::High,
Copy link
Member

@zarik5 zarik5 Dec 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the default level should be Main. Why was High chosen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High was chosen for continuity with the existing default settings in some of the encoders.
Reviewing the diff, it is clear that most encoders default to High right now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nowrep Any reason for this? Main should have less latency.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how reliable this is but this says that high main and base have no difference in latency
https://ipvm.com/reports/h264-high-profile-tested
Given these are just cameras idk

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While higher profiles do increase complexity it seems it may not correlate to latency

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to fix software decoder compatibility then just use ffmpeg in the client instead of MediaCodec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is correct, in practice, AHardwareBuffers are involved, and it'd likely involve some refactoring, and there are APIs that expose these AHardwareBuffers. I don't have the necessary knowledge.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the encoding profile is still good to have.
@20kdc have you checked if the decoder can provide its own supported profiles? We could automate this as a future optimization

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I'm aware decoder can't provide supported profiles outside of successful or failed initialization.
Even if it could, decoder bugs make the output potentially untrustworthy.
The encoder might be able to provide supported profiles to some extent, but that's more like an API-level thing, and it requires getting this information about support to the Dashboard, somehow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I'm aware decoder can't provide supported profiles outside of successful or failed initialization

That's too bad

it requires getting this information about support to the Dashboard

No we don't. we can do the same thing we do for FPS, we just choose the closes one if unsupported by the client.

@zarik5
Copy link
Member

zarik5 commented Jan 2, 2024

If there are no objections I would merge this in a day

@zarik5 zarik5 merged commit 12e6ac6 into alvr-org:master Jan 2, 2024
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants