Skip to content
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions Pages/AppPage.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ void AppPage::Connect(int appId) {
config->framePacing = host->FramePacing;
config->enableStats = host->EnableStats;
config->enableGraphs = host->EnableGraphs;
config->idrInterval = host->IdrInterval;
if (config->enableHDR) {
host->VideoCodec = "HEVC (H.265)";
}
Expand Down
25 changes: 17 additions & 8 deletions Pages/HostSettingsPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0">Resolution</TextBlock>
<ComboBox x:Name="ResolutionSelector" SelectionChanged="ResolutionSelector_SelectionChanged" SelectedIndex="{x:Bind CurrentResolutionIndex,Mode=TwoWay}" Grid.Row="0" Grid.Column="1" ItemsSource="{x:Bind AvailableResolutions}">
Expand Down Expand Up @@ -90,26 +92,33 @@
Best for Xbox One. Locks rendering frame rate to refresh rate and evenly spaces frames.
</TextBlock>

<TextBlock Grid.Row="10" Grid.Column="0">Show performance stats:</TextBlock>
<TextBlock Grid.Row="10" Grid.Column="0" >Periodic decoder refresh:</TextBlock>
<CheckBox Name="EnableIdrIntervalCheckbox" Grid.Row="10" Grid.Column="1" Checked="EnableIdrIntervalCheckbox_Checked" Unchecked="EnableIdrIntervalCheckbox_Unchecked"></CheckBox>
<TextBlock Grid.Row="10" Grid.Column="2" >Mitigates HEVC corruption. Refreshes every (Target FPS)*(Interval) frames.</TextBlock>

<TextBlock Grid.Row="11" Grid.Column="0" >Refresh interval (Seconds)</TextBlock>
<Slider Name ="IdrIntervalSlider" Grid.Row="11" Grid.Column="1" Grid.ColumnSpan="2" Value="{x:Bind Host.IdrInterval}" IsEnabled="False" x:DefaultBindMode="TwoWay" Minimum="2" Maximum="60" SmallChange="1" TickFrequency="2" StepFrequency="2" />

<TextBlock Grid.Row="12" Grid.Column="0">Show performance stats:</TextBlock>
<CheckBox
Grid.Row="10" Grid.Column="1"
Grid.Row="12" Grid.Column="1"
x:Name="EnableStatsCheckbox"
IsChecked="{x:Bind Host.EnableStats, Mode=TwoWay}" />

<TextBlock Grid.Row="11" Grid.Column="0" >Show performance graphs:</TextBlock>
<TextBlock Grid.Row="13" Grid.Column="0" >Show performance graphs:</TextBlock>
<CheckBox
Grid.Row="11" Grid.Column="1"
Grid.Row="13" Grid.Column="1"
x:Name="EnableGraphsCheckbox"
IsEnabled="{x:Bind Host.EnableStats, Mode=OneWay}"
IsChecked="{x:Bind Host.EnableGraphs, Mode=TwoWay}" />
<TextBlock
Name="XboxOneGraphsNote" Grid.Row="11" Grid.Column="1" Grid.ColumnSpan="2" Visibility="Collapsed">
Name="XboxOneGraphsNote" Grid.Row="13" Grid.Column="1" Grid.ColumnSpan="2" Visibility="Collapsed">
Graphs are unavailable on Xbox One when system resolution is set to 4K.
</TextBlock>

<TextBlock Grid.Row="12" Grid.Column="0">Other:</TextBlock>
<Button Grid.Row="12" Grid.Column="1" x:Name="GlobalSettingsOption" Click="GlobalSettingsOption_Click">Open Global Settings</Button>
</Grid>
<TextBlock Grid.Row="14" Grid.Column="0">Other:</TextBlock>
<Button Grid.Row="14" Grid.Column="1" x:Name="GlobalSettingsOption" Click="GlobalSettingsOption_Click">Open Global Settings</Button>
</Grid>
</StackPanel>
</ScrollViewer>
</Page>
25 changes: 25 additions & 0 deletions Pages/HostSettingsPage.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@ void HostSettingsPage::OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEv
XboxOneGraphsNote->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
}
}

if (host->IdrInterval > 0) {
EnableIdrIntervalCheckbox->IsChecked = true;
IdrIntervalSlider->Minimum = 2;
IdrIntervalSlider->IsEnabled = true;
} else {
EnableIdrIntervalCheckbox->IsChecked = false;
Comment thread
razorlikes marked this conversation as resolved.
IdrIntervalSlider->Minimum = 0;
IdrIntervalSlider->Value = 0;
IdrIntervalSlider->IsEnabled = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

void HostSettingsPage::backButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
Expand Down Expand Up @@ -191,6 +202,20 @@ void HostSettingsPage::FramePacing_SelectionChanged(Platform::Object^ sender, Wi
host->FramePacing = selectedFramePacing;
}

void HostSettingsPage::EnableIdrIntervalCheckbox_Checked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) {
IdrIntervalSlider->IsEnabled = true;
if (IdrIntervalSlider->Value < 2) {
IdrIntervalSlider->Value = 10;
}
IdrIntervalSlider->Minimum = 2;
}

void HostSettingsPage::EnableIdrIntervalCheckbox_Unchecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) {
IdrIntervalSlider->IsEnabled = false;
IdrIntervalSlider->Minimum = 0;
IdrIntervalSlider->Value = 0;
}

void HostSettingsPage::GlobalSettingsOption_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(MoonlightSettings::typeid));
Expand Down
2 changes: 2 additions & 0 deletions Pages/HostSettingsPage.xaml.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ namespace moonlight_xbox_dx
void BitrateInput_TextChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::TextChangedEventArgs^ e);
void AutoStartSelector_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
void FramePacing_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
void EnableIdrIntervalCheckbox_Checked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void EnableIdrIntervalCheckbox_Unchecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void GlobalSettingsOption_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void BitrateInput_KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e);
void OnLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
Expand Down
2 changes: 2 additions & 0 deletions State/ApplicationState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Concurrency::task<void> moonlight_xbox_dx::ApplicationState::Init()
if (a.contains("serverAddress")) h->ServerAddress = Utils::StringFromStdString(a["serverAddress"].get<std::string>());
if (a.contains("macaddress")) h->MacAddress = Utils::StringFromStdString(a["macaddress"].get<std::string>());
else h->ComputerName = h->LastHostname;
if (a.contains("idr_interval")) h->IdrInterval = a["idr_interval"];
this->SavedHosts->Append(h);
}
}
Expand Down Expand Up @@ -109,6 +110,7 @@ Concurrency::task<void> moonlight_xbox_dx::ApplicationState::UpdateFile()
hostJson["enable_stats"] = host->EnableStats;
hostJson["enable_graphs"] = host->EnableGraphs;
hostJson["serverAddress"] = Utils::PlatformStringToStdString(host->ServerAddress);
hostJson["idr_interval"] = host->IdrInterval;

std::string macAddr = Utils::PlatformStringToStdString(host->MacAddress);
if (macAddr != "00:00:00:00:00:00" && macAddr != "")
Expand Down
2 changes: 1 addition & 1 deletion State/MoonlightClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ int MoonlightClient::StartStreaming(std::shared_ptr<DX::DeviceResources> res, St
callbacks.rumble = connection_rumble;
callbacks.rumbleTriggers = connection_trigger_rumble;

FFMpegDecoder::instance().CompleteInitialization(res, &config, sConfig->framePacing == "Immediate");
FFMpegDecoder::instance().CompleteInitialization(res, &config, sConfig->framePacing == "Immediate", sConfig->idrInterval);
DECODER_RENDERER_CALLBACKS rCallbacks = FFMpegDecoder::getDecoder();

AUDIO_RENDERER_CALLBACKS aCallbacks = AudioPlayer::getDecoder();
Expand Down
10 changes: 10 additions & 0 deletions State/MoonlightHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace moonlight_xbox_dx {
bool enableSOPS = false;
bool enableStats = false;
bool enableGraphs = true;
int idrInterval = 0;
Windows::Foundation::Collections::IVector<MoonlightApp^>^ apps;
public:
//Thanks to https://phsucharee.wordpress.com/2013/06/19/data-binding-and-ccx-inotifypropertychanged/
Expand Down Expand Up @@ -284,5 +285,14 @@ namespace moonlight_xbox_dx {
OnPropertyChanged("EnableGraphs");
}
}

property int IdrInterval
{
int get() { return this->idrInterval; }
void set(int value) {
this->idrInterval = (value <= 0) ? 0 : (value < 2 ? 2 : value);
OnPropertyChanged("IdrInterval");
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
};
}
1 change: 1 addition & 0 deletions State/StreamConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace moonlight_xbox_dx
property bool enableSOPS;
property bool enableStats;
property bool enableGraphs;
property int idrInterval;
};

moonlight_xbox_dx::StreamConfiguration^ GetStreamConfig();
Expand Down
20 changes: 17 additions & 3 deletions Streaming/FFmpegDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,22 @@ namespace moonlight_xbox_dx {
Utils::Logf(shouldPrefixThisMessage ? "[ffmpeg] %s" : "%s", lineBuffer);
}

void FFMpegDecoder::CompleteInitialization(const std::shared_ptr<DX::DeviceResources>& res, STREAM_CONFIGURATION *config, bool framePacingImmediate) {
void FFMpegDecoder::CompleteInitialization(const std::shared_ptr<DX::DeviceResources>& res, STREAM_CONFIGURATION *config, bool framePacingImmediate, int idrInterval) {
this->m_deviceResources = res;
this->fps = config->fps;
this->idrInterval = idrInterval;
Pacer::instance().init(res, config->fps, res->GetRefreshRate(), framePacingImmediate);
}

int FFMpegDecoder::Init(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
this->videoFormat = videoFormat;
this->width = width;
this->height = height;
this->fps = 60; // correctly set in CompleteInitialization

this->m_LastFrameNumber = 0;
this->ffmpeg_buffer_size = 0;
this->m_StreamEpochQpc = 0;

this->m_FramesSinceIDR = 0;

#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58,10,100)
avcodec_register_all();
Expand Down Expand Up @@ -280,6 +280,20 @@ namespace moonlight_xbox_dx {
return DR_NEED_IDR;
}

// Request new IDR frames periodically to mitigate stream corruption.
if (idrInterval > 0 && fps > 0) {
if (frame->flags & AV_FRAME_FLAG_KEY) {
m_FramesSinceIDR = 0;
} else {
m_FramesSinceIDR++;
}
Comment thread
razorlikes marked this conversation as resolved.

if (m_FramesSinceIDR >= (fps * idrInterval)) {
LiRequestIdrFrame();
m_FramesSinceIDR = 0; // avoid requesting multiple IDR frames in a row
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Capture a frame timestamp to measuring pacing delay
QueryPerformanceCounter(&decodeEnd);
frame_attach_userdata(frame, decodeEnd.QuadPart);
Expand Down
5 changes: 3 additions & 2 deletions Streaming/FFmpegDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ class FFMpegDecoder {
// Singleton accessor
static FFMpegDecoder &instance();

void CompleteInitialization(const std::shared_ptr<DX::DeviceResources> &res, STREAM_CONFIGURATION *config, bool framePacingImmediate);
void CompleteInitialization(const std::shared_ptr<DX::DeviceResources> &res, STREAM_CONFIGURATION *config, bool framePacingImmediate, int idrInterval);
int Init(int videoFormat, int width, int height, int redrawRate, void *context, int drFlags);
void Cleanup();
int SubmitDecodeUnit(PDECODE_UNIT decodeUnit);
static FFMpegDecoder *getInstance();
static DECODER_RENDERER_CALLBACKS getDecoder();
int videoFormat, width, height, fps;
int videoFormat, width, height, fps, idrInterval;
std::recursive_mutex m_mutex;

// locking helper
Expand Down Expand Up @@ -74,5 +74,6 @@ class FFMpegDecoder {
std::shared_ptr<DX::DeviceResources> m_deviceResources;
int m_LastFrameNumber;
int64_t m_StreamEpochQpc;
int m_FramesSinceIDR;
};
} // namespace moonlight_xbox_dx