@@ -127,6 +127,27 @@ namespace {
127127 return " full" ;
128128 }
129129
130+ /* *
131+ * @brief Convert a decoder preference to the persisted TOML token.
132+ *
133+ * @param selection Decoder preference to serialize.
134+ * @return Stable lowercase settings value.
135+ */
136+ const char *video_decoder_selection_text (app::VideoDecoderSelection selection) {
137+ switch (selection) {
138+ case app::VideoDecoderSelection::autoDetect:
139+ return " auto" ;
140+ case app::VideoDecoderSelection::h264:
141+ return " h264" ;
142+ case app::VideoDecoderSelection::mpeg2:
143+ return " mpeg2" ;
144+ case app::VideoDecoderSelection::h263p:
145+ return " h263p" ;
146+ }
147+
148+ return " auto" ;
149+ }
150+
130151 bool try_parse_logging_level (std::string_view text, logging::LogLevel *level) {
131152 const std::string normalized = ascii_lowercase (text);
132153 if (normalized == " trace" ) {
@@ -193,6 +214,43 @@ namespace {
193214 return false ;
194215 }
195216
217+ /* *
218+ * @brief Parse a decoder preference from the persisted TOML token.
219+ *
220+ * @param text Settings value to parse.
221+ * @param selection Receives the parsed decoder preference on success.
222+ * @return True when @p text is a supported decoder preference.
223+ */
224+ bool try_parse_video_decoder_selection (std::string_view text, app::VideoDecoderSelection *selection) {
225+ const std::string normalized = ascii_lowercase (text);
226+ if (normalized == " auto" ) {
227+ if (selection != nullptr ) {
228+ *selection = app::VideoDecoderSelection::autoDetect;
229+ }
230+ return true ;
231+ }
232+ if (normalized == " h264" || normalized == " h.264" ) {
233+ if (selection != nullptr ) {
234+ *selection = app::VideoDecoderSelection::h264;
235+ }
236+ return true ;
237+ }
238+ if (normalized == " mpeg2" || normalized == " mpeg-2" || normalized == " h262" || normalized == " h.262" ) {
239+ if (selection != nullptr ) {
240+ *selection = app::VideoDecoderSelection::mpeg2;
241+ }
242+ return true ;
243+ }
244+ if (normalized == " h263p" || normalized == " h.263p" || normalized == " h263+" || normalized == " h.263+" ) {
245+ if (selection != nullptr ) {
246+ *selection = app::VideoDecoderSelection::h263p;
247+ }
248+ return true ;
249+ }
250+
251+ return false ;
252+ }
253+
196254 void append_invalid_value_warning (std::vector<std::string> *warnings, const std::string &filePath, std::string_view keyPath, std::string_view valueText) {
197255 if (warnings == nullptr ) {
198256 return ;
@@ -263,6 +321,34 @@ namespace {
263321 append_invalid_value_warning (warnings, filePath, " ui.log_viewer_placement" , " <non-string>" );
264322 }
265323
324+ /* *
325+ * @brief Load one decoder preference setting when present.
326+ *
327+ * @param settingNode TOML node to parse.
328+ * @param filePath Settings file path used in warnings.
329+ * @param selection Receives the parsed decoder preference on success.
330+ * @param warnings Warning collection updated for invalid values.
331+ */
332+ void load_video_decoder_selection_setting (
333+ toml::node_view<const toml::node> settingNode,
334+ const std::string &filePath,
335+ app::VideoDecoderSelection *selection,
336+ std::vector<std::string> *warnings
337+ ) {
338+ if (!settingNode) {
339+ return ;
340+ }
341+
342+ if (const auto videoDecoderText = settingNode.value <std::string>(); videoDecoderText) {
343+ if (!try_parse_video_decoder_selection (*videoDecoderText, selection)) {
344+ append_invalid_value_warning (warnings, filePath, " streaming.video_decoder" , *videoDecoderText);
345+ }
346+ return ;
347+ }
348+
349+ append_invalid_value_warning (warnings, filePath, " streaming.video_decoder" , " <non-string>" );
350+ }
351+
266352 /* *
267353 * @brief Load one integer settings value when present.
268354 *
@@ -346,6 +432,8 @@ namespace {
346432 content += " # Preferred streaming parameters.\n " ;
347433 content += std::string (" fps = " ) + std::to_string (settings.streamFramerate ) + " \n " ;
348434 content += std::string (" bitrate_kbps = " ) + std::to_string (settings.streamBitrateKbps ) + " \n " ;
435+ content += " # Video decoder preference. Use auto to keep normal host negotiation.\n " ;
436+ content += std::string (" video_decoder = \" " ) + video_decoder_selection_text (settings.videoDecoder ) + " \"\n " ;
349437 content += std::string (" play_audio_on_pc = " ) + (settings.playAudioOnPc ? " true" : " false" ) + " \n " ;
350438 content += std::string (" play_audio_on_xbox = " ) + (settings.playAudioOnXbox ? " true" : " false" ) + " \n " ;
351439 content += " # Show stream telemetry after streaming ends.\n " ;
@@ -392,7 +480,7 @@ namespace {
392480 void inspect_streaming_keys (const toml::table &streamingTable, const std::string &filePath, app::LoadAppSettingsResult *result) {
393481 for (const auto &[rawKey, node] : streamingTable) {
394482 const std::string key (rawKey.str ());
395- if (key == " video_width" || key == " video_height" || key == " video_bpp" || key == " video_refresh" || key == " video_mode_selected" || key == " fps" || key == " bitrate_kbps" || key == " play_audio_on_pc" || key == " play_audio_on_xbox" || key == " show_performance_stats" ) {
483+ if (key == " video_width" || key == " video_height" || key == " video_bpp" || key == " video_refresh" || key == " video_mode_selected" || key == " fps" || key == " bitrate_kbps" || key == " video_decoder " || key == " play_audio_on_pc" || key == " play_audio_on_xbox" || key == " show_performance_stats" ) {
396484 continue ;
397485 }
398486
@@ -490,6 +578,7 @@ namespace app {
490578 load_boolean_setting (settingsTable[" streaming" ][" video_mode_selected" ], filePath, " streaming.video_mode_selected" , &result.settings .preferredVideoModeSet , &result.warnings );
491579 load_integer_setting (settingsTable[" streaming" ][" fps" ], filePath, " streaming.fps" , &result.settings .streamFramerate , &result.warnings );
492580 load_integer_setting (settingsTable[" streaming" ][" bitrate_kbps" ], filePath, " streaming.bitrate_kbps" , &result.settings .streamBitrateKbps , &result.warnings );
581+ load_video_decoder_selection_setting (settingsTable[" streaming" ][" video_decoder" ], filePath, &result.settings .videoDecoder , &result.warnings );
493582 load_boolean_setting (settingsTable[" streaming" ][" play_audio_on_pc" ], filePath, " streaming.play_audio_on_pc" , &result.settings .playAudioOnPc , &result.warnings );
494583 load_boolean_setting (settingsTable[" streaming" ][" play_audio_on_xbox" ], filePath, " streaming.play_audio_on_xbox" , &result.settings .playAudioOnXbox , &result.warnings );
495584 load_boolean_setting (settingsTable[" streaming" ][" show_performance_stats" ], filePath, " streaming.show_performance_stats" , &result.settings .showPerformanceStats , &result.warnings );
0 commit comments