void FGameLiveStreaming::StopBroadcastingGame() { if( bIsBroadcasting ) { if( LiveStreamer != nullptr ) { if( LiveStreamer->IsBroadcasting() ) { LiveStreamer->StopWebCam(); LiveStreamer->StopBroadcasting(); } } if( FSlateApplication::IsInitialized() ) // During shutdown, Slate may have already been destroyed by the time our viewport gets cleaned up { FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); SlateRenderer->OnSlateWindowRendered().RemoveAll( this ); } // Cleanup readback buffer textures { FlushRenderingCommands(); ReadbackTextures[0].SafeRelease(); ReadbackTextures[1].SafeRelease(); ReadbackTextureIndex = 0; ReadbackBuffers[0] = nullptr; ReadbackBuffers[1] = nullptr; ReadbackBufferIndex = 0; } } }
void FEditorLiveStreaming::BroadcastEditorVideoFrame() { if( ensure( IsBroadcastingEditor() ) ) { // Check to see if we're streaming live video. If so, we'll want to push new frames to be broadcast. if( LiveStreamer->IsBroadcasting() ) { // Is this live streamer ready to accept new frames? if( LiveStreamer->IsReadyForVideoFrames() ) { FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); const FMappedTextureBuffer& CurrentBuffer = ReadbackBuffers[ReadbackBufferIndex]; if ( CurrentBuffer.IsValid() ) { //TODO PushVideoFrame Needs to Take Width and Height LiveStreamer->PushVideoFrame((FColor*)CurrentBuffer.Data/*, CurrentBuffer.Width, CurrentBuffer.Height*/); ++SubmittedVideoFrameCount; // If this is the first frame we've submitted, then we can fade out our notification UI, since broadcasting is in progress if( SubmittedVideoFrameCount == 1 ) { TSharedPtr< SNotificationItem > Notification( NotificationWeakPtr.Pin() ); if( Notification.IsValid() ) { Notification->ExpireAndFadeout(); } } SlateRenderer->UnmapVirtualScreenBuffer(); } TArray<FString> UnusedKeypressBuffer; SlateRenderer->CopyWindowsToVirtualScreenBuffer( UnusedKeypressBuffer ); SlateRenderer->MapVirtualScreenBuffer(&ReadbackBuffers[ReadbackBufferIndex]); // Ping pong between buffers ReadbackBufferIndex = ( ReadbackBufferIndex + 1 ) % 2; } } else { // If our streaming service has stopped broadcasting for some reason, then we'll cancel our broadcast StopBroadcastingEditor(); } } }
void FRenderDocPluginModule::OnEditorLoaded(SWindow& SlateWindow, void* ViewportRHIPtr) { // --> YAGER by SKrysanov 6/11/2014 : fixed crash on removing this callback in render thread. if (IsInGameThread()) { FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); SlateRenderer->OnSlateWindowRendered().Remove(LoadedDelegateHandle); } // <-- YAGER by SKrysanov 6/11/2014 if (IsInitialized) { return; } IsInitialized = true; if (GConfig) { bool bGreetingHasBeenShown; GConfig->GetBool(TEXT("RenderDoc"), TEXT("GreetingHasBeenShown"), bGreetingHasBeenShown, GGameIni); if (!bGreetingHasBeenShown) { GEditor->EditorAddModalWindow(SNew(SRenderDocPluginAboutWindow)); GConfig->SetBool(TEXT("RenderDoc"), TEXT("GreetingHasBeenShown"), true, GGameIni); } } //TODO: REMOVE THIS WHEN WE GET PULL REQUEST ACCEPTED HWND WindowHandle = GetActiveWindow(); //Trigger a capture just to make sure we are set up correctly. This should prevent us from crashing on exit. ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER( InitializeRenderDoc, HWND, WindowHandle, WindowHandle, FRenderDocPluginGUI*, RenderDocGUI, RenderDocGUI, pRENDERDOC_StartFrameCapture, RenderDocStartFrameCapture, RenderDocStartFrameCapture, pRENDERDOC_EndFrameCapture, RenderDocEndFrameCapture, RenderDocEndFrameCapture, { RenderDocStartFrameCapture(WindowHandle); RenderDocEndFrameCapture(WindowHandle); FString NewestCapture = RenderDocGUI->GetNewestCapture(FPaths::Combine(*FPaths::GameSavedDir(), *FString("RenderDocCaptures"))); IFileManager::Get().Delete(*NewestCapture); });
void FWebMRecord::OnWorldCreated(UWorld* World, const UWorld::InitializationValues IVS) { if (IsRunningCommandlet() || IsRunningDedicatedServer()) { return; } if (!bRegisteredSlateDelegate) { FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); SlateRenderer->OnSlateWindowRendered().AddRaw(this, &FWebMRecord::OnSlateWindowRenderedDuringCapture); bRegisteredSlateDelegate = true; // Setup readback buffer textures { for (int32 TextureIndex = 0; TextureIndex < 2; ++TextureIndex) { FRHIResourceCreateInfo CreateInfo; ReadbackTextures[TextureIndex] = RHICreateTexture2D( VideoWidth, VideoHeight, PF_B8G8R8A8, 1, 1, TexCreate_CPUReadback, CreateInfo ); } ReadbackTextureIndex = 0; ReadbackBuffers[0] = nullptr; ReadbackBuffers[1] = nullptr; ReadbackBufferIndex = 0; } } }
void FEditorLiveStreaming::StartBroadcastingEditor() { if( !IsBroadcastingEditor() && IsLiveStreamingAvailable() ) { // Select a live streaming service { static const FName LiveStreamingFeatureName( "LiveStreaming" ); LiveStreamer = &IModularFeatures::Get().GetModularFeature<ILiveStreamingService>( LiveStreamingFeatureName ); } // Register to find out about status changes LiveStreamer->OnStatusChanged().AddRaw( this, &FEditorLiveStreaming::BroadcastStatusCallback ); // @todo livestream: Allow connection to chat independently from broadcasting? (see removing delegate too) LiveStreamer->OnChatMessage().AddRaw( this, &FEditorLiveStreaming::OnChatMessage ); // Tell our live streaming plugin to start broadcasting { const auto& Settings = *GetDefault< UEditorLiveStreamingSettings >(); FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); const FIntRect VirtualScreen = SlateRenderer->SetupVirtualScreenBuffer( Settings.bPrimaryMonitorOnly, Settings.ScreenScaling, LiveStreamer ); bIsBroadcasting = true; SubmittedVideoFrameCount = 0; // @todo livestream: What about if virtual screen size changes while we are still broadcasting? For example, if the user changes their // desktop resolution while the editor is running. We'd need to stop and restart the broadcast. FBroadcastConfig BroadcastConfig; BroadcastConfig.VideoBufferWidth = VirtualScreen.Width(); BroadcastConfig.VideoBufferHeight = VirtualScreen.Height(); BroadcastConfig.FramesPerSecond = Settings.FrameRate; BroadcastConfig.PixelFormat = FBroadcastConfig::EBroadcastPixelFormat::R8G8B8A8; BroadcastConfig.bCaptureAudioFromComputer = Settings.bCaptureAudioFromComputer; BroadcastConfig.bCaptureAudioFromMicrophone = Settings.bCaptureAudioFromMicrophone; LiveStreamer->StartBroadcasting( BroadcastConfig ); if( Settings.bEnableWebCam ) { FWebCamConfig WebCamConfig; switch( Settings.WebCamResolution ) { case EEditorLiveStreamingWebCamResolution::Normal_320x240: WebCamConfig.DesiredWebCamWidth = 320; WebCamConfig.DesiredWebCamHeight = 240; break; case EEditorLiveStreamingWebCamResolution::Wide_320x180: WebCamConfig.DesiredWebCamWidth = 320; WebCamConfig.DesiredWebCamHeight = 180; break; case EEditorLiveStreamingWebCamResolution::Normal_640x480: WebCamConfig.DesiredWebCamWidth = 640; WebCamConfig.DesiredWebCamHeight = 480; break; case EEditorLiveStreamingWebCamResolution::Wide_640x360: WebCamConfig.DesiredWebCamWidth = 640; WebCamConfig.DesiredWebCamHeight = 360; break; case EEditorLiveStreamingWebCamResolution::Normal_800x600: WebCamConfig.DesiredWebCamWidth = 800; WebCamConfig.DesiredWebCamHeight = 600; break; case EEditorLiveStreamingWebCamResolution::Wide_800x450: WebCamConfig.DesiredWebCamWidth = 800; WebCamConfig.DesiredWebCamHeight = 450; break; case EEditorLiveStreamingWebCamResolution::Normal_1024x768: WebCamConfig.DesiredWebCamWidth = 1024; WebCamConfig.DesiredWebCamHeight = 768; break; case EEditorLiveStreamingWebCamResolution::Wide_1024x576: WebCamConfig.DesiredWebCamWidth = 1024; WebCamConfig.DesiredWebCamHeight = 576; break; case EEditorLiveStreamingWebCamResolution::Normal_1080x810: WebCamConfig.DesiredWebCamWidth = 1080; WebCamConfig.DesiredWebCamHeight = 810; break; case EEditorLiveStreamingWebCamResolution::Wide_1080x720: WebCamConfig.DesiredWebCamWidth = 1080; WebCamConfig.DesiredWebCamHeight = 720; break; case EEditorLiveStreamingWebCamResolution::Normal_1280x960: WebCamConfig.DesiredWebCamWidth = 1280; WebCamConfig.DesiredWebCamHeight = 960; break; case EEditorLiveStreamingWebCamResolution::Wide_1280x720: WebCamConfig.DesiredWebCamWidth = 1280; WebCamConfig.DesiredWebCamHeight = 720; break; case EEditorLiveStreamingWebCamResolution::Normal_1920x1440: WebCamConfig.DesiredWebCamWidth = 1920; WebCamConfig.DesiredWebCamHeight = 1440; break; case EEditorLiveStreamingWebCamResolution::Wide_1920x1080: WebCamConfig.DesiredWebCamWidth = 1920; WebCamConfig.DesiredWebCamHeight = 1080; break; default: check(0); break; } // @todo livestream: Allow web cam to be started/stopped independently from the broadcast itself, so users can setup their web cam LiveStreamer->StartWebCam( WebCamConfig ); } } } }
void FGameLiveStreaming::StartBroadcastingGame( const FGameBroadcastConfig& GameBroadcastConfig ) { if( !IsBroadcastingGame() ) { if( bIsBroadcasting ) { FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); SlateRenderer->OnSlateWindowRendered().RemoveAll( this ); bIsBroadcasting = false; } // We can GetLiveStreamingService() here to fill in our LiveStreamer variable lazily, to make sure the service plugin is loaded // before we try to cache it's interface pointer if( GetLiveStreamingService() != nullptr ) { FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); SlateRenderer->OnSlateWindowRendered().AddRaw( this, &FGameLiveStreaming::OnSlateWindowRenderedDuringBroadcasting ); this->bMirrorWebCamImage = GameBroadcastConfig.bMirrorWebCamImage; this->bDrawSimpleWebCamVideo = GameBroadcastConfig.bDrawSimpleWebCamVideo; // @todo livestream: This will interfere with editor live streaming if both are running at the same time! The editor live // streaming does check to make sure that game isn't already broadcasting, but the game currently doesn't have a good way to // do that, besides asking the LiveStreamer itself. UGameViewportClient* GameViewportClient = GEngine->GameViewport; check( GameViewportClient != nullptr ); // @todo livestream: What about if viewport size changes while we are still broadcasting? We need to restart the broadcast! FBroadcastConfig BroadcastConfig; BroadcastConfig.VideoBufferWidth = GameViewportClient->Viewport->GetSizeXY().X; BroadcastConfig.VideoBufferHeight = GameViewportClient->Viewport->GetSizeXY().Y; BroadcastConfig.VideoBufferWidth = FPlatformMath::FloorToInt( (float)BroadcastConfig.VideoBufferWidth * GameBroadcastConfig.ScreenScaling ); BroadcastConfig.VideoBufferHeight = FPlatformMath::FloorToInt( (float)BroadcastConfig.VideoBufferHeight * GameBroadcastConfig.ScreenScaling ); // Fix up the desired resolution so that it will work with the streaming system. Some broadcasters require the // video buffer to be multiples of specific values, such as 32 // @todo livestream: This could cause the aspect ratio to be changed and the buffer to be stretched non-uniformly, but usually the aspect only changes slightly LiveStreamer->MakeValidVideoBufferResolution( BroadcastConfig.VideoBufferWidth, BroadcastConfig.VideoBufferHeight ); // Setup readback buffer textures { for( int32 TextureIndex = 0; TextureIndex < 2; ++TextureIndex ) { FRHIResourceCreateInfo CreateInfo; ReadbackTextures[ TextureIndex ] = RHICreateTexture2D( BroadcastConfig.VideoBufferWidth, BroadcastConfig.VideoBufferHeight, PF_B8G8R8A8, 1, 1, TexCreate_CPUReadback, CreateInfo ); } ReadbackTextureIndex = 0; ReadbackBuffers[0] = nullptr; ReadbackBuffers[1] = nullptr; ReadbackBufferIndex = 0; } BroadcastConfig.FramesPerSecond = GameBroadcastConfig.FrameRate; BroadcastConfig.PixelFormat = FBroadcastConfig::EBroadcastPixelFormat::B8G8R8A8; // Matches viewport backbuffer format BroadcastConfig.bCaptureAudioFromComputer = GameBroadcastConfig.bCaptureAudioFromComputer; BroadcastConfig.bCaptureAudioFromMicrophone = GameBroadcastConfig.bCaptureAudioFromMicrophone; LiveStreamer->StartBroadcasting( BroadcastConfig ); if( GameBroadcastConfig.bEnableWebCam ) { // @todo livestream: Allow web cam to be started/stopped independently from the broadcast itself, so users can setup their web cam FWebCamConfig WebCamConfig; WebCamConfig.DesiredWebCamWidth = GameBroadcastConfig.DesiredWebCamWidth; WebCamConfig.DesiredWebCamHeight = GameBroadcastConfig.DesiredWebCamHeight; LiveStreamer->StartWebCam( WebCamConfig ); } bIsBroadcasting = true; } } }
void FRenderDocPluginModule::StartupModule() { //Load DLL FString BinaryPath; if (GConfig) { GConfig->GetString(TEXT("RenderDoc"), TEXT("BinaryPath"), BinaryPath, GGameIni); } FString PathToRenderDocDLL = FPaths::Combine(*BinaryPath, *FString("renderdoc.dll")); RenderDocDLL = NULL; RenderDocDLL = GetModuleHandle(*PathToRenderDocDLL); if (BinaryPath.IsEmpty() || !RenderDocDLL) { UE_LOG(RenderDocPlugin, Error, TEXT("Could not find the renderdoc DLL, have you loaded the RenderDocLoaderPlugin?")); return; } //Init function pointers RenderDocGetAPIVersion = (pRENDERDOC_GetAPIVersion)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_GetAPIVersion"); RenderDocSetLogFile = (pRENDERDOC_SetLogFile)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_SetLogFile"); RenderDocSetCaptureOptions = (pRENDERDOC_SetCaptureOptions)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_SetCaptureOptions"); RenderDocGetCapture = (pRENDERDOC_GetCapture)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_GetCapture"); RenderDocSetActiveWindow = (pRENDERDOC_SetActiveWindow)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_SetActiveWindow"); RenderDocTriggerCapture = (pRENDERDOC_TriggerCapture)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_TriggerCapture"); RenderDocStartFrameCapture = (pRENDERDOC_StartFrameCapture)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_StartFrameCapture"); RenderDocEndFrameCapture = (pRENDERDOC_EndFrameCapture)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_EndFrameCapture"); RenderDocGetOverlayBits = (pRENDERDOC_GetOverlayBits)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_GetOverlayBits"); RenderDocMaskOverlayBits = (pRENDERDOC_MaskOverlayBits)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_MaskOverlayBits"); RenderDocSetFocusToggleKeys = (pRENDERDOC_SetFocusToggleKeys)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_SetFocusToggleKeys"); RenderDocSetCaptureKeys = (pRENDERDOC_SetCaptureKeys)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_SetCaptureKeys"); RenderDocInitRemoteAccess = (pRENDERDOC_InitRemoteAccess)GetRenderDocFunctionPointer(RenderDocDLL, "RENDERDOC_InitRemoteAccess"); //Set capture settings FString RenderDocCapturePath = FPaths::Combine(*FPaths::GameSavedDir(), *FString("RenderDocCaptures")); if (!IFileManager::Get().DirectoryExists(*RenderDocCapturePath)) { IFileManager::Get().MakeDirectory(*RenderDocCapturePath, true); } FString CapturePath = FPaths::Combine(*RenderDocCapturePath, *FDateTime::Now().ToString()); CapturePath = FPaths::ConvertRelativePathToFull(CapturePath); FPaths::NormalizeDirectoryName(CapturePath); if (sizeof(TCHAR) == sizeof(char)) { RenderDocSetLogFile((char*)*CapturePath); } else { char CapturePathShort[1024]; ZeroMemory(CapturePathShort, 1024); size_t NumCharsConverted; wcstombs_s(&NumCharsConverted, CapturePathShort, *CapturePath, CapturePath.Len()); RenderDocSetLogFile(CapturePathShort); } RenderDocSetFocusToggleKeys(NULL, 0); RenderDocSetCaptureKeys(NULL, 0); CaptureOptions Options = RenderDocSettings.CreateOptions(); RenderDocSetCaptureOptions(&Options); //Init remote access SocketPort = 0; RenderDocInitRemoteAccess(&SocketPort); //Init UI FRenderDocPluginStyle::Initialize(); FRenderDocPluginCommands::Register(); FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor"); TSharedRef<FUICommandList> CommandBindings = LevelEditorModule.GetGlobalLevelEditorActions(); ExtensionManager = LevelEditorModule.GetToolBarExtensibilityManager(); CommandBindings->MapAction(FRenderDocPluginCommands::Get().CaptureFrame, FExecuteAction::CreateRaw(this, &FRenderDocPluginModule::CaptureCurrentViewport), FCanExecuteAction()); CommandBindings->MapAction(FRenderDocPluginCommands::Get().OpenSettings, FExecuteAction::CreateRaw(this, &FRenderDocPluginModule::OpenSettingsEditorWindow), FCanExecuteAction()); ToolbarExtender = MakeShareable(new FExtender); ToolbarExtension = ToolbarExtender->AddToolBarExtension("CameraSpeed", EExtensionHook::After, CommandBindings, FToolBarExtensionDelegate::CreateRaw(this, &FRenderDocPluginModule::AddToolbarExtension)); LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); //Init renderdoc RenderDocMaskOverlayBits(eOverlay_None, eOverlay_None); RenderDocGUI = new FRenderDocPluginGUI(RenderDocGetCapture); IsInitialized = false; FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); LoadedDelegateHandle = SlateRenderer->OnSlateWindowRendered().AddRaw(this, &FRenderDocPluginModule::OnEditorLoaded); int32 RenderDocVersion = RenderDocGetAPIVersion(); UE_LOG(RenderDocPlugin, Log, TEXT("RenderDoc plugin started! Your renderdoc installation is v%i"), RenderDocVersion); }