| /* |
| * Copyright 2020 Google LLC |
| * |
| */ |
| |
| /* |
| * Copyright (c) 2020, Alliance for Open Media. All rights reserved |
| * |
| * This source code is subject to the terms of the BSD 2 Clause License and |
| * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| * was not distributed with this source code in the LICENSE file, you can |
| * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| * Media Patent License 1.0 was not distributed with this source code in the |
| * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
| */ |
| |
| #include "pch.h" |
| #include "App.h" |
| |
| #include <ppltasks.h> |
| #include <Xinput.h> |
| |
| using namespace uwp_dx12_player; |
| |
| using namespace concurrency; |
| using namespace Windows::ApplicationModel; |
| using namespace Windows::ApplicationModel::Core; |
| using namespace Windows::ApplicationModel::Activation; |
| using namespace Windows::UI::Core; |
| using namespace Windows::UI::Input; |
| using namespace Windows::System; |
| using namespace Windows::Foundation; |
| using namespace Windows::Graphics::Display; |
| |
| using Microsoft::WRL::ComPtr; |
| |
| // The DirectX 12 Application template is documented at https://go.microsoft.com/fwlink/?LinkID=613670&clcid=0x409 |
| |
| // The main function is only used to initialize our IFrameworkView class. |
| [Platform::MTAThread] int main(Platform::Array<Platform::String ^> ^) { |
| PlayerWindow::InitializeLog(logging::LOG_INFO); |
| XB_LOGI << "Start application"; |
| |
| auto direct3DApplicationSource = ref new Direct3DApplicationSource(); |
| CoreApplication::Run(direct3DApplicationSource); |
| return 0; |
| } |
| |
| IFrameworkView |
| ^ Direct3DApplicationSource::CreateView() { |
| return ref new App(); |
| } |
| |
| App::App() : m_windowClosed(false), m_windowVisible(true) {} |
| |
| // The first method called when the IFrameworkView is being created. |
| void App::Initialize(CoreApplicationView ^ applicationView) { |
| // Register event handlers for app lifecycle. This example includes Activated, so that we |
| // can make the CoreWindow active and start rendering on the window. |
| applicationView->Activated += |
| ref new TypedEventHandler<CoreApplicationView ^, IActivatedEventArgs ^>(this, &App::OnActivated); |
| |
| CoreApplication::Suspending += ref new EventHandler<SuspendingEventArgs ^>(this, &App::OnSuspending); |
| |
| CoreApplication::Resuming += ref new EventHandler<Platform::Object ^>(this, &App::OnResuming); |
| } |
| |
| // Called when the CoreWindow object is created (or re-created). |
| void App::SetWindow(CoreWindow ^ window) { |
| window->SizeChanged += |
| ref new TypedEventHandler<CoreWindow ^, WindowSizeChangedEventArgs ^>(this, &App::OnWindowSizeChanged); |
| |
| window->VisibilityChanged += |
| ref new TypedEventHandler<CoreWindow ^, VisibilityChangedEventArgs ^>(this, &App::OnVisibilityChanged); |
| |
| window->Closed += ref new TypedEventHandler<CoreWindow ^, CoreWindowEventArgs ^>(this, &App::OnWindowClosed); |
| |
| DisplayInformation ^ currentDisplayInformation = DisplayInformation::GetForCurrentView(); |
| |
| currentDisplayInformation->DpiChanged += |
| ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &App::OnDpiChanged); |
| |
| currentDisplayInformation->OrientationChanged += |
| ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &App::OnOrientationChanged); |
| |
| DisplayInformation::DisplayContentsInvalidated += |
| ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &App::OnDisplayContentsInvalidated); |
| } |
| |
| // Initializes scene resources, or loads a previously saved app state. |
| void App::Load(Platform::String ^ entryPoint) { |
| if (m_main == nullptr) { |
| m_main = std::unique_ptr<PlayerWindow>(new PlayerWindow(CoreWindow::GetForCurrentThread())); |
| m_decoder_state = m_main->Run(); |
| } |
| } |
| |
| // This method is called after the window becomes active. |
| void App::Run() { |
| DWORD lastPacketNumber = 0; |
| while (!m_windowClosed) { |
| if (m_decoder_state == -1) { |
| // Decoder creation failed. Exit |
| XB_LOGE << "Unable to create decoder instance. May be due to wrong application mode (must be GAME MODE)"; |
| break; |
| } |
| if (m_windowVisible) { |
| CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); |
| XINPUT_STATE state; |
| ZeroMemory(&state, sizeof(XINPUT_STATE)); |
| if (XInputGetState(0, &state) == ERROR_SUCCESS) { |
| if (state.dwPacketNumber != lastPacketNumber) { |
| if (state.Gamepad.wButtons == XINPUT_GAMEPAD_DPAD_RIGHT) { |
| m_main->StopDecode(taskNext); |
| } |
| lastPacketNumber = state.dwPacketNumber; |
| } |
| } |
| if (m_windowVisible) { |
| m_main->ShowFrame(); |
| } |
| if (m_main->isJobsDone()) { |
| XB_LOGI << "Close main window"; |
| m_main->StopDecode(taskStop); |
| m_windowClosed = true; |
| } |
| |
| } else { |
| CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); |
| m_main->StopDecode(taskStopFlush); |
| m_windowClosed = true; |
| } |
| } |
| } |
| |
| // Required for IFrameworkView. |
| // Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView |
| // class is torn down while the app is in the foreground. |
| void App::Uninitialize() {} |
| |
| // Application lifecycle event handlers. |
| |
| void App::OnActivated(CoreApplicationView ^ applicationView, IActivatedEventArgs ^ args) { |
| // Run() won't start until the CoreWindow is activated. |
| CoreWindow::GetForCurrentThread()->Activate(); |
| } |
| |
| void App::OnSuspending(Platform::Object ^ sender, SuspendingEventArgs ^ args) { |
| // Save app state asynchronously after requesting a deferral. Holding a deferral |
| // indicates that the application is busy performing suspending operations. Be |
| // aware that a deferral may not be held indefinitely. After about five seconds, |
| // the app will be forced to exit. |
| SuspendingDeferral ^ deferral = args->SuspendingOperation->GetDeferral(); |
| |
| create_task([this, deferral]() { |
| deferral->Complete(); |
| }); |
| } |
| |
| void App::OnResuming(Platform::Object ^ sender, Platform::Object ^ args) { |
| // Restore any data or state that was unloaded on suspend. By default, data |
| // and state are persisted when resuming from suspend. Note that this event |
| // does not occur if the app was previously terminated. |
| |
| // m_main->OnResuming(); |
| } |
| |
| // Window event handlers. |
| |
| void App::OnWindowSizeChanged(CoreWindow ^ sender, WindowSizeChangedEventArgs ^ args) { |
| // GetDeviceResources()->SetLogicalSize(Size(sender->Bounds.Width, sender->Bounds.Height)); |
| // m_main->OnWindowSizeChanged(); |
| } |
| |
| void App::OnVisibilityChanged(CoreWindow ^ sender, VisibilityChangedEventArgs ^ args) { |
| m_windowVisible = args->Visible; |
| } |
| |
| void App::OnWindowClosed(CoreWindow ^ sender, CoreWindowEventArgs ^ args) { m_windowClosed = true; } |
| |
| // DisplayInformation event handlers. |
| |
| void App::OnDpiChanged(DisplayInformation ^ sender, Object ^ args) { |
| // Note: The value for LogicalDpi retrieved here may not match the effective DPI of the app |
| // if it is being scaled for high resolution devices. Once the DPI is set on DeviceResources, |
| // you should always retrieve it using the GetDpi method. |
| // See DeviceResources.cpp for more details. |
| // GetDeviceResources()->SetDpi(sender->LogicalDpi); |
| // m_main->OnWindowSizeChanged(); |
| } |
| |
| void App::OnOrientationChanged(DisplayInformation ^ sender, Object ^ args) { |
| // GetDeviceResources()->SetCurrentOrientation(sender->CurrentOrientation); |
| // m_main->OnWindowSizeChanged(); |
| } |
| |
| void App::OnDisplayContentsInvalidated(DisplayInformation ^ sender, Object ^ args) { |
| // GetDeviceResources()->ValidateDevice(); |
| } |