Added ndi receiver and sdi outputs

This commit is contained in:
mchara40
2025-08-25 13:16:29 +03:00
parent 11b8be19f6
commit d046828313
125 changed files with 14757 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <GameFramework/Actor.h>
#include <Components/NDIViewportCaptureComponent.h>
#include <Components/NDIPTZControllerComponent.h>
#include <Sound/SoundSubmix.h>
#include "NDIBroadcastActor.generated.h"
/**
A quick and easy way to capture the from the perspective of a camera that starts broadcasting the viewport
immediate upon 'BeginPlay'
*/
UCLASS(BlueprintType, Blueprintable, Category = "NDI IO", META = (DisplayName = "NDI Broadcast Actor"))
class NDIIO_API ANDIBroadcastActor : public AActor, public IPTZControllableInterface
{
GENERATED_UCLASS_BODY()
private:
/**
The NDI Media Sender representing the configuration of the network source to send audio, video, and metadata
*/
UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Category = "NDI IO",
META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaSender* NDIMediaSource = nullptr;
/**
A component used to capture an additional viewport for broadcasting over NDI
*/
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "NDI IO",
META = (DisplayName = "Viewport Capture Component", AllowPrivateAccess = true))
UNDIViewportCaptureComponent* ViewportCaptureComponent = nullptr;
UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Category = "NDI IO",
META = (DisplayName = "Audio Submix Capture", AllowPrivateAccess = true))
USoundSubmix* SubmixCapture = nullptr;
/**
Component used for PTZ control
*/
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "NDI IO",
META = (DisplayName = "PTZ Controller", AllowPrivateAccess = true))
UPTZController* PTZController = nullptr;
public:
virtual void BeginPlay() override;
// IPTZControllableInterface
virtual FPTZState GetPTZStateFromUE() const override;
virtual void SetPTZStateToUE(const FPTZState& PTZState) override;
};

View File

@@ -0,0 +1,129 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <GameFramework/Actor.h>
#include <Components/AudioComponent.h>
#include <Components/StaticMeshComponent.h>
#include <Components/NDIReceiverComponent.h>
#include <Enumerations/NDIAudioChannels.h>
#include "NDIReceiveActor.generated.h"
UCLASS(HideCategories = (Activation, Rendering, AssetUserData, Material, Attachment, Actor, Input, Cooking, LOD,
StaticMesh, Materials),
Category = "NDI IO", META = (DisplayName = "NDI Receive Actor"))
class NDIIO_API ANDIReceiveActor : public AActor
{
GENERATED_UCLASS_BODY()
private:
/** The desired width of the frame in cm, represented in the virtual scene */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, BlueprintSetter = "SetFrameWidth", Category = "NDI IO",
META = (DisplayName = "Frame Width", AllowPrivateAccess = true))
float FrameWidth = 177.778;
/** The desired height of the frame in cm, represented in the virtual scene */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, BlueprintSetter = "SetFrameHeight", Category = "NDI IO",
META = (DisplayName = "Frame Height", AllowPrivateAccess = true))
float FrameHeight = 100.0f;
/**
Indicates that this object should play the audio.
*Note Audio played by this object will be played as a UI sound, and won't normalize the audio
if the same 'MediaSource' object is being used as the audio source on multiple receivers.
*/
UPROPERTY(EditInstanceOnly, BlueprintSetter = "UpdateAudioPlayback", Category = "NDI IO",
META = (DisplayName = "Enable Audio Playback?", AllowPrivateAccess = true))
bool bEnableAudioPlayback = false;
UPROPERTY(EditInstanceOnly, BlueprintSetter = "UpdateAudioPlaybackChannels", Category = "NDI IO",
META = (DisplayName = "Audio Playback Channels", AllowPrivateAccess = true))
ENDIAudioChannels AudioPlaybackChannels = ENDIAudioChannels::Mono;
/** Enable/disable the use of the color channels (if there are any) */
UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintSetter = "EnableColor", Category = "NDI IO",
META = (DisplayName = "Enable Color?", AllowPrivateAccess = true))
bool bEnableColor = true;
/** Enable/disable the use of the alpha channel (if there is one) */
UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintSetter = "EnableAlpha", Category = "NDI IO",
META = (DisplayName = "Enable Alpha?", AllowPrivateAccess = true))
bool bEnableAlpha = true;
/** The Receiver object used to get Audio, Video, and Metadata from on the network */
UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Category = "NDI IO",
META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaReceiver* NDIMediaSource = nullptr;
/** The component used to display the video received from the Media Sender object */
UPROPERTY(Transient, META = (DisplayName = "Video Mesh Component"))
UStaticMeshComponent* VideoMeshComponent = nullptr;
/** The component used to play the audio from the NDI Media source */
UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Category= "NDI IO", META = (DisplayName = "Audio Component", AllowPrivateAccess = true))
UAudioComponent* AudioComponent = nullptr;
/** The audio sound wave which receives the audio from the NDI Media source */
UPROPERTY(Transient, META = (DisplayName = "Soundwave"))
UNDIMediaSoundWave* AudioSoundWave = nullptr;
private:
/** The material we are trying to apply to the video mesh */
class UMaterialInterface* VideoMaterial = nullptr;
/** The dynamic material to apply to the plane object of this actor */
UPROPERTY()
class UMaterialInstanceDynamic* VideoMaterialInstance = nullptr;
public:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float DeltaTime) override;
/**
Attempts to set the desired frame size in cm, represented in the virtual scene
*/
void SetFrameSize(FVector2D InFrameSize);
/**
Returns the current frame size of the 'VideoMeshComponent' for this object
*/
const FVector2D GetFrameSize() const;
private:
UFUNCTION(BlueprintSetter)
void SetFrameHeight(const float& InFrameHeight);
UFUNCTION(BlueprintSetter)
void SetFrameWidth(const float& InFrameWidth);
UFUNCTION(BlueprintSetter)
void UpdateAudioPlayback(const bool& Enabled);
UFUNCTION(BlueprintSetter)
void UpdateAudioPlaybackChannels(const ENDIAudioChannels& Channels);
UFUNCTION(BlueprintSetter)
void EnableColor(const bool& Enabled);
UFUNCTION(BlueprintSetter)
void EnableAlpha(const bool& Enabled);
#if WITH_EDITORONLY_DATA
virtual void PreEditChange(FProperty* InProperty) override;
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
void ApplyChannelsMode();
bool bStoppedForChannelsMode = false;
};

View File

@@ -0,0 +1,52 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <GenlockedTimecodeProvider.h>
#include <Objects/Media/NDIMediaReceiver.h>
#include "NDITimecodeProvider.generated.h"
/**
Timecode provider from an NDI source
*/
UCLASS(Blueprintable, editinlinenew, meta=(DisplayName="NDI Timecode Provider"))
class NDIIO_API UNDITimecodeProvider : public UGenlockedTimecodeProvider
{
GENERATED_UCLASS_BODY()
private:
/** The Receiver object used to get timecodes from */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "NDI IO",
META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaReceiver* NDIMediaSource = nullptr;
public:
//~ UTimecodeProvider interface
virtual bool FetchTimecode(FQualifiedFrameTime& OutFrameTime) override;
virtual ETimecodeProviderSynchronizationState GetSynchronizationState() const override;
virtual bool Initialize(class UEngine* InEngine) override;
virtual void Shutdown(class UEngine* InEngine) override;
//~ UObject interface
virtual void BeginDestroy() override;
private:
void ReleaseResources();
private:
FDelegateHandle VideoCaptureEventHandle;
FDelegateHandle ConnectedEventHandle;
FDelegateHandle DisconnectedEventHandle;
mutable FCriticalSection StateSyncContext;
ETimecodeProviderSynchronizationState State = ETimecodeProviderSynchronizationState::Closed;
FQualifiedFrameTime MostRecentFrameTime;
};

View File

@@ -0,0 +1,99 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Components/ActorComponent.h>
#include <Objects/Media/NDIMediaSender.h>
#include <Structures/NDIBroadcastConfiguration.h>
#include "NDIBroadcastComponent.generated.h"
/**
Provides a wrapper to allow you to modify an NDI Media Sender object from blueprints and perform broadcasting
functionality
*/
UCLASS(BlueprintType, Blueprintable, Category = "NDI IO",
META = (DisplayName = "NDI Broadcast Component", BlueprintSpawnableComponent))
class NDIIO_API UNDIBroadcastComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
private:
/** The NDI Media Sender representing the configuration of the network source to send audio, video, and metadata */
UPROPERTY(EditDefaultsOnly, Category = "Properties",
META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaSender* NDIMediaSource = nullptr;
public:
/**
Initialize this component with the media source required for sending NDI audio, video, and metadata.
Returns false, if the MediaSource is already been set. This is usually the case when this component is
initialized in Blueprints.
*/
bool Initialize(UNDIMediaSender* InMediaSource = nullptr);
/**
Attempts to start broadcasting audio, video, and metadata via the 'NDIMediaSource' associated with this object
@param ErrorMessage The error message received when the media source is unable to start broadcasting
@result Indicates whether this object successfully started broadcasting
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Start Broadcasting"))
bool StartBroadcasting(FString& ErrorMessage);
/**
Changes the name of the sender object as seen on the network for remote connections
@param InSourceName The new name of the source to be identified as on the network
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Source Name"))
void ChangeSourceName(const FString& InSourceName);
/**
Attempts to change the Broadcast information associated with this media object
@param InConfiguration The new configuration to broadcast
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Broadcast Configuration"))
void ChangeBroadcastConfiguration(const FNDIBroadcastConfiguration& InConfiguration);
/**
Attempts to change the RenderTarget used in sending video frames over NDI
@param BroadcastTexture The texture to use as video, while broadcasting over NDI
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Broadcast Texture"))
void ChangeBroadcastTexture(UTextureRenderTarget2D* BroadcastTexture = nullptr);
/**
Determines the current tally information.
@param IsOnPreview - A state indicating whether this source in on preview of a receiver
@param IsOnProgram - A state indicating whether this source is on program of a receiver
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Tally Information"))
void GetTallyInformation(bool& IsOnPreview, bool& IsOnProgram);
/**
Gets the current number of receivers connected to this source. This can be used to avoid rendering
when nothing is connected to the video source. which can significantly improve the efficiency if
you want to make a lot of sources available on the network
@param Result The total number of connected receivers attached to the broadcast of this object
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Number of Connections"))
void GetNumberOfConnections(int32& Result);
/**
Attempts to immediately stop sending frames over NDI to any connected receivers
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Stop Broadcasting"))
void StopBroadcasting();
};

View File

@@ -0,0 +1,79 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Components/ActorComponent.h>
#include <Structures/NDIConnectionInformation.h>
#include "NDIFinderComponent.generated.h"
/** Delegates **/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIFinderServiceCollectionChangedDelegate, UNDIFinderComponent*,
InComponent);
/** ******************* **/
/**
A component used for essential functionality when dealing with the finder service. Allowing you to
get a collection of sources found on the network.
*/
UCLASS(BlueprintType, Blueprintable, Category = "NDI IO",
META = (DisplayName = "NDI Finder Component", BlueprintSpawnableComponent))
class NDIIO_API UNDIFinderComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
public:
/** A collection of the current sources and their information, found on the network */
UPROPERTY()
TArray<FNDIConnectionInformation> NetworkSourceCollection;
/** A delegate which is broadcast when any change to the network source collection has been detected */
UPROPERTY(BlueprintAssignable, META = (DisplayName = "On Network Sources Changed", AllowPrivateAccess = true))
FNDIFinderServiceCollectionChangedDelegate OnNetworkSourcesChanged;
public:
/**
Attempts to find a network source by the supplied name.
@param ConnectionInformation An existing source information structure which contains the source name
@param InSourceName A string value representing the name of the source to find
@result A value indicating whether a source with the supplied name was found
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Find Network Source by Name"))
const bool FindNetworkSourceByName(FNDIConnectionInformation& ConnectionInformation,
FString InSourceName = FString(""));
/**
Returns the current collection of sources found on the network
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO", META = (DisplayName = "Get Network Sources"))
const TArray<FNDIConnectionInformation> GetNetworkSources();
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
/** An override function for when the network source collection has been changed */
UFUNCTION(BlueprintImplementableEvent, META = (DisplayName = "On Network Sources Changed Event"))
void OnNetworkSourcesChangedEvent();
private:
/**
An Event handler for when the NDI Finder Service notifies listeners that changes have been
detected in the network source collection
*/
UFUNCTION()
virtual void OnNetworkSourceCollectionChangedEvent() final;
private:
FCriticalSection CollectionSyncContext;
};

View File

@@ -0,0 +1,174 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <UObject/Interface.h>
#include <Components/ActorComponent.h>
#include <Objects/Media/NDIMediaSender.h>
#include "NDIPTZControllerComponent.generated.h"
USTRUCT(BlueprintType, Blueprintable, Category = "NDI IO", META = (DisplayName = "NDI PTZ State"))
struct NDIIO_API FPTZState
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PTZ")
float Pan;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PTZ")
float Tilt;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PTZ")
float FieldOfView;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PTZ")
float FocusDistance;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PTZ")
bool bAutoFocus;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PTZ")
FTransform CameraTransform;
FPTZState()
: Pan(0.f)
, Tilt(0.f)
, FieldOfView(90.f)
, FocusDistance(0.5f)
, bAutoFocus(false)
{}
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FNDIEventDelegate_OnPTZPanTiltSpeed, float, PanSpeed, float, TiltSpeed);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIEventDelegate_OnPTZZoomSpeed, float, ZoomSpeed);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FNDIEventDelegate_OnPTZFocus, bool, AutoMode, float, Distance);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIEventDelegate_OnPTZStore, int, Index);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIEventDelegate_OnPTZRecall, int, Index);
UINTERFACE(BlueprintType, Blueprintable, Category = "NDI IO",
META = (DisplayName = "NDI PTZ Controllable", BlueprintSpawnableComponent))
class NDIIO_API UPTZControllableInterface : public UInterface
{
GENERATED_BODY()
};
class IPTZControllableInterface
{
GENERATED_BODY()
public:
virtual FPTZState GetPTZStateFromUE() const = 0;
virtual void SetPTZStateToUE(const FPTZState& PTZState) = 0;
};
UCLASS(BlueprintType, Blueprintable, Category = "NDI IO",
META = (DisplayName = "NDI PTZ Controller", BlueprintSpawnableComponent))
class UPTZController : public UActorComponent
{
GENERATED_BODY()
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Enable PTZ", AllowPrivateAccess = true), Category="PTZ")
bool EnablePTZ = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Pan Limit", AllowPrivateAccess = true), Category="PTZ")
bool PTZWithPanLimit = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Pan Min Limit", UIMin="-180", UIMax="180", AllowPrivateAccess = true), Category="PTZ")
float PTZPanMinLimit = -180.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Pan Max Limit", UIMin="-180", UIMax="180", AllowPrivateAccess = true), Category="PTZ")
float PTZPanMaxLimit = 180.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Invert Pan", AllowPrivateAccess = true), Category="PTZ")
bool bPTZPanInvert = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Tilt Limit", AllowPrivateAccess = true), Category="PTZ")
bool PTZWithTiltLimit = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Tilt Min Limit", UIMin="-180", UIMax="180", AllowPrivateAccess = true), Category="PTZ")
float PTZTiltMinLimit = -90.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Tilt Max Limit", UIMin="-180", UIMax="180", AllowPrivateAccess = true), Category="PTZ")
float PTZTiltMaxLimit = 90.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Invert Tilt", AllowPrivateAccess = true), Category="PTZ")
bool bPTZTiltInvert = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Field of View Limit", AllowPrivateAccess = true), Category="PTZ")
bool PTZWithFoVLimit = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Field of View Min Limit", UIMin="5", UIMax="170", AllowPrivateAccess = true), Category="PTZ")
float PTZFoVMinLimit = 5.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Field of View Max Limit", UIMin="5", UIMax="170", AllowPrivateAccess = true), Category="PTZ")
float PTZFoVMaxLimit = 170.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Preset Recall Easing", UIMin="0", UIMax="60", AllowPrivateAccess = true), Category="PTZ")
float PTZRecallEasing = 2.f;
UPROPERTY(BlueprintReadWrite, meta=(AllowPrivateAccess = true), Category="PTZ")
float PTZPanSpeed = 0.f;
UPROPERTY(BlueprintReadWrite, meta=(AllowPrivateAccess = true), Category="PTZ")
float PTZTiltSpeed = 0.f;
UPROPERTY(BlueprintReadWrite, meta=(AllowPrivateAccess = true), Category="PTZ")
float PTZZoomSpeed = 0.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="PTZ Presets", AllowPrivateAccess = true), Category="PTZ")
TArray<FPTZState> PTZStoredStates;
UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Category = "NDI IO", META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaSender* NDIMediaSource = nullptr;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On PTZ Pan Tilt Speed", AllowPrivateAccess = true))
FNDIEventDelegate_OnPTZPanTiltSpeed OnPTZPanTiltSpeed;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On PTZ Zoom Speed", AllowPrivateAccess = true))
FNDIEventDelegate_OnPTZZoomSpeed OnPTZZoomSpeed;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On PTZ Focus", AllowPrivateAccess = true))
FNDIEventDelegate_OnPTZFocus OnPTZFocus;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On PTZ Store", AllowPrivateAccess = true))
FNDIEventDelegate_OnPTZStore OnPTZStore;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On PTZ Recall", AllowPrivateAccess = true))
FNDIEventDelegate_OnPTZRecall OnPTZRecall;
public:
/** Call with the PTZ metadata received from an NDI media sender */
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Receive Metadata From Sender"))
void ReceiveMetaDataFromSender(UNDIMediaSender* Sender, FString Data);
public:
UPTZController();
virtual ~UPTZController();
/**
Initialize this component with the required media source to receive metadata from.
Returns false, if the MediaSource is already been set. This is usually the case when this component is
initialized in Blueprints.
*/
bool Initialize(UNDIMediaSender* InMediaSource = nullptr);
void SetPTZPanTiltSpeed(float PanSpeed, float TiltSpeed);
void SetPTZZoomSpeed(float ZoomSpeed);
void SetPTZFocus(bool AutoMode, float Distance);
void StorePTZState(int Index);
void RecallPTZState(int Index);
FPTZState GetPTZStateFromUE() const;
void SetPTZStateToUE(const FPTZState& PTZState);
protected:
virtual void InitializeComponent() override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
protected:
TSharedPtr<class NDIXmlParser> NDIMetadataParser;
struct FPTZStateInterp
{
FPTZState PTZTargetState;
float EasingDuration { 0 };
float EasingRemaining { 0 };
};
FPTZStateInterp PTZStateInterp;
};

View File

@@ -0,0 +1,97 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Components/ActorComponent.h>
#include <Structures/NDIConnectionInformation.h>
#include <Objects/Media/NDIMediaReceiver.h>
#include "NDIReceiverComponent.generated.h"
/**
A component used to receive audio, video, and metadata over NDI
*/
UCLASS(BlueprintType, Blueprintable, Category = "NDI IO",
META = (DisplayName = "NDI Receiver Component", BlueprintSpawnableComponent))
class NDIIO_API UNDIReceiverComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
private:
/** The NDI Media Receiver representing the configuration of the network source to receive audio, video, and
* metadata from */
UPROPERTY(EditDefaultsOnly, Category = "Properties",
META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaReceiver* NDIMediaSource = nullptr;
public:
/**
Initialize this component with the media source required for receiving NDI audio, video, and metadata.
Returns false, if the MediaSource is already been set. This is usually the case when this component is
initialized in Blueprints.
*/
bool Initialize(UNDIMediaReceiver* InMediaSource = nullptr);
/**
Begin receiving NDI audio, video, and metadata frames
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Start Receiver"))
bool StartReceiver(const FNDIConnectionInformation& InConnectionInformation);
/**
Attempt to change the connection for which to get audio, video, and metadata frame from
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Connection"))
void ChangeConnection(const FNDIConnectionInformation& InConnectionInformation);
/**
This will add a metadata frame and return immediately, having scheduled the frame asynchronously
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Metadata Frame"))
void SendMetadataFrame(const FString& metadata);
/**
This will setup the up-stream tally notifications. If no streams are connected, it will automatically send
the tally state upon connection
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Tally Information"))
void SendTallyInformation(const bool& IsOnPreview, const bool& IsOnProgram);
/**
Attempts to stop receiving audio, video, and metadata frame from the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Shutdown Receiver"))
void ShutdownReceiver();
public:
/**
Returns the current framerate of the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Current Frame Rate"))
FFrameRate GetCurrentFrameRate() const;
/**
Returns the current timecode of the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Current Timecode"))
FTimecode GetCurrentTimecode() const;
/**
Returns the current connection information of the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Current Connection Information"))
FNDIConnectionInformation GetCurrentConnectionInformation() const;
/**
Returns the current performance data of the receiver while connected to the source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Performance Data"))
FNDIReceiverPerformanceData GetPerformanceData() const;
};

View File

@@ -0,0 +1,91 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <UObject/UnrealType.h>
#include <Objects/Media/NDIMediaSender.h>
#include <Components/ActorComponent.h>
#include "NDITriCasterExtComponent.generated.h"
USTRUCT(BlueprintType, Blueprintable, Category = "NDI IO", META = (DisplayName = "NDI TricasterExt"))
struct NDIIO_API FTriCasterExt
{
GENERATED_USTRUCT_BODY()
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="TricasterExt")
FString Value;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="TricasterExt")
TMap<FName,FString> KeyValues;
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FNDIEventDelegate_OnTriCasterExt, AActor*, Actor, UObject*, Object, FString, PropertyElementName, FString, PropertyValueStr, FTimespan, EasingDuration);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIEventDelegate_OnTriCasterExtCustom, const FTriCasterExt&, TCData);
UCLASS(BlueprintType, Blueprintable, Category = "NDI IO",
META = (DisplayName = "NDI TricasterExt Component", BlueprintSpawnableComponent))
class UTriCasterExtComponent : public UActorComponent
{
GENERATED_BODY()
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayName="Enable TricasterExt", AllowPrivateAccess = true), Category="TricasterExt")
bool EnableTriCasterExt = true;
UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Category = "NDI IO", META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaSender* NDIMediaSource = nullptr;
UPROPERTY(BlueprintAssignable, BlueprintCallable, Category="NDI Events", META = (DisplayName = "On TricasterExt", AllowPrivateAccess = true))
FNDIEventDelegate_OnTriCasterExt OnTriCasterExt;
UPROPERTY(BlueprintAssignable, BlueprintCallable, Category="NDI Events", META = (DisplayName = "On TricasterExt Custom", AllowPrivateAccess = true))
FNDIEventDelegate_OnTriCasterExtCustom OnTriCasterExtCustom;
public:
/** Call with the TriCasterExt metadata received from an NDI media sender */
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Receive Metadata From Sender"))
void ReceiveMetaDataFromSender(UNDIMediaSender* Sender, FString Data);
public:
UTriCasterExtComponent();
virtual ~UTriCasterExtComponent();
/**
Initialize this component with the required media source to receive metadata from.
Returns false, if the MediaSource is already been set. This is usually the case when this component is
initialized in Blueprints.
*/
bool Initialize(UNDIMediaSender* InMediaSource = nullptr);
void TriCasterExt(AActor* Actor, UObject* Object, FProperty* Property, FString PropertyElementName, FString PropertyValueStr, FTimespan EasingDuration);
void TriCasterExtCustom(const FTriCasterExt& TCData);
protected:
virtual void InitializeComponent() override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
protected:
TSharedPtr<class NDIXmlParser> NDIMetadataParser;
struct FTriCasterExtInterp
{
AActor* Actor;
UObject* Object;
FProperty* Property;
FString PropertyElementName;
FString PropertyValueStr;
float EasingDuration;
float EasingRemaining;
};
TArray<FTriCasterExtInterp> TriCasterExtInterp;
};

View File

@@ -0,0 +1,154 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <CineCameraComponent.h>
#include <Engine/TextureRenderTarget2D.h>
#include <Components/SceneCaptureComponent2D.h>
#include <Objects/Media/NDIMediaSender.h>
#include <Misc/FrameRate.h>
#include <Framework/Application/SlateApplication.h>
#include <SceneManagement.h>
#include <Slate/SceneViewport.h>
#include <Widgets/SViewport.h>
#include <Widgets/SWindow.h>
#include "NDIViewportCaptureComponent.generated.h"
/**
A component used to capture an additional viewport for broadcasting over NDI
*/
UCLASS(BlueprintType, Blueprintable, Category = "NDI IO",
META = (DisplayName = "NDI Viewport Capture Component", BlueprintSpawnableComponent))
class NDIIO_API UNDIViewportCaptureComponent : public USceneCaptureComponent2D
{
GENERATED_UCLASS_BODY()
private:
/**
If true, will allow you to override the capture settings by ignoring the default Broadcast Settings
in the NDI Media Sender, Potentially Requiring a texture rescale of the capture frame when broadcasting
over NDI.
*/
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capture Settings", META = (AllowPrivateAccess = true))
bool bOverrideBroadcastSettings = false;
/**
Describes the Height and Width of the viewport frame to capture.
*/
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capture Settings",
META = (DisplayName = "Capture Size", AllowPrivateAccess = true,
EditCondition = "bOverrideBroadcastSettings"))
FIntPoint CaptureSize = FIntPoint(1280, 720);
/**
Represents the desired number of frames (per second) to capture the viewport
*/
UPROPERTY(BlueprintReadwrite, EditAnywhere, Category = "Capture Settings",
META = (DisplayName = "Capture Rate", AllowPrivateAccess = true,
EditCondition = "bOverrideBroadcastSettings"))
FFrameRate CaptureRate = FFrameRate(60, 1);
/**
The NDI Media Sender representing the configuration of the network source to send audio, video, and metadata
*/
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Properties",
META = (DisplayName = "NDI Media Source", AllowPrivateAccess = true))
UNDIMediaSender* NDIMediaSource = nullptr;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capture Settings",
META = (DisplayName = "Alpha Remap Min", AllowPrivateAccess = true))
float AlphaMin = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capture Settings",
META = (DisplayName = "Alpha Remap Max", AllowPrivateAccess = true))
float AlphaMax = 1.f;
public:
/**
Initialize this component with the media source required for sending NDI audio, video, and metadata.
Returns false, if the MediaSource is already been set. This is usually the case when this component is
initialized in Blueprints.
*/
bool Initialize(UNDIMediaSender* InMediaSource = nullptr);
/**
Changes the name of the sender object as seen on the network for remote connections
@param InSourceName The new name of the source to be identified as on the network
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Source Name"))
void ChangeSourceName(const FString& InSourceName);
/**
Attempts to change the Broadcast information associated with this media object
@param InConfiguration The new configuration to broadcast
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Broadcast Configuration"))
void ChangeBroadcastConfiguration(const FNDIBroadcastConfiguration& InConfiguration);
/**
Attempts to change the RenderTarget used in sending video frames over NDI
@param BroadcastTexture The texture to use as video, while broadcasting over NDI
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Broadcast Texture"))
void ChangeBroadcastTexture(UTextureRenderTarget2D* BroadcastTexture = nullptr);
/**
Change the capture settings of the viewport capture and overrides the NDI Media Sender settings
@param InCaptureSize The Capture size of the frame to capture of the viewport
@param InCaptureRate A framerate at which to capture frames of the viewport
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Capture Settings"))
void ChangeCaptureSettings(FIntPoint InCaptureSize, FFrameRate InCaptureRate);
/**
Determines the current tally information. If you specify a timeout then it will wait until it has
changed, otherwise it will simply poll it and return the current tally immediately
@param IsOnPreview - A state indicating whether this source in on preview of a receiver
@param IsOnProgram - A state indicating whether this source is on program of a receiver
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Tally Information"))
void GetTallyInformation(bool& IsOnPreview, bool& IsOnProgram);
/**
Gets the current number of receivers connected to this source. This can be used to avoid rendering
when nothing is connected to the video source. which can significantly improve the efficiency if
you want to make a lot of sources available on the network
@param Result The total number of connected receivers attached to the broadcast of this object
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Number of Connections"))
void GetNumberOfConnections(int32& Result);
protected:
virtual ~UNDIViewportCaptureComponent();
virtual void InitializeComponent() override;
virtual void UninitializeComponent() override;
#if (ENGINE_MAJOR_VERSION > 5) || ((ENGINE_MAJOR_VERSION == 5) && (ENGINE_MINOR_VERSION >= 6)) // 5.6 or later
virtual void UpdateSceneCaptureContents(FSceneInterface* Scene, ISceneRenderBuilder& SceneRenderBuilder) override;
#else
virtual void UpdateSceneCaptureContents(FSceneInterface* Scene) override;
#endif
private:
UFUNCTION()
void OnBroadcastConfigurationChanged(UNDIMediaSender* Sender);
private:
FCriticalSection UpdateRenderContext;
};

View File

@@ -0,0 +1,28 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include "NDIAudioChannels.generated.h"
/**
Receiver Bandwidth modes
*/
UENUM(BlueprintType, META = (DisplayName = "NDI Audio Channels"))
enum class ENDIAudioChannels : uint8
{
/** Mono. */
Mono = 0x00 UMETA(DisplayName = "Mono"),
/** Stereo. */
Stereo = 0x01 UMETA(DisplayName = "Stereo"),
/** Whatever the number of channels in the source is. */
Source = 0x02 UMETA(DisplayName = "Source"),
};

View File

@@ -0,0 +1,31 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include "NDISourceBandwidth.generated.h"
/**
Receiver Bandwidth modes
*/
UENUM(BlueprintType, META = (DisplayName = "NDI Source Bandwidth"))
enum class ENDISourceBandwidth : uint8
{
/** Receive metadata. */
MetadataOnly = 0x00 UMETA(DisplayName = "Metadata Only"),
/** Receive metadata, audio */
AudioOnly = 0x01 UMETA(DisplayName = "Audio Only"),
/** Receive metadata, audio, video at a lower bandwidth and resolution. */
Lowest = 0x02 UMETA(DisplayName = "Lowest"),
// Receive metadata, audio, video at full resolution.
Highest = 0x03 UMETA(DisplayName = "Highest")
};

View File

@@ -0,0 +1,34 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <vector>
#include <algorithm>
#include <functional>
#include <chrono>
#if PLATFORM_WINDOWS
#include <Windows/AllowWindowsPlatformTypes.h>
#endif
#ifndef NDI_SDK_ENABLED
#error NDI(R) 6.x Runtime must be installed for the NDI(R) IO plugin to run properly.
#endif
#ifdef NDI_SDK_ENABLED
#include <Processing.NDI.Lib.h>
#include <Processing.NDI.Lib.cplusplus.h>
#endif
#if PLATFORM_WINDOWS
#include <Windows/HideWindowsPlatformTypes.h>
#endif
#define NDIIO_MODULE_NAME FName(TEXT("NDIIO"))

View File

@@ -0,0 +1,61 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <vector>
#include <algorithm>
#include <functional>
#include <chrono>
#include <Engine/World.h>
#include <Interfaces/IPluginManager.h>
#include <Modules/ModuleManager.h>
#include <IMediaPlayerFactory.h>
#include <NDIIOPluginSettings.h>
class NDIIO_API FNDIIOPluginModule
: public IModuleInterface
, public IMediaPlayerFactory
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
/** IMediaPlayerFactory implementation */
virtual bool CanPlayUrl(const FString& Url, const IMediaOptions* /*Options*/, TArray<FText>* /*OutWarnings*/, TArray<FText>* OutErrors) const override;
virtual TSharedPtr<IMediaPlayer, ESPMode::ThreadSafe> CreatePlayer(IMediaEventSink& EventSink) override;
virtual FText GetDisplayName() const override;
virtual FName GetPlayerName() const override;
virtual FGuid GetPlayerPluginGUID() const override;
virtual const TArray<FString>& GetSupportedPlatforms() const override;
virtual bool SupportsFeature(EMediaFeature Feature) const override;
bool BeginBroadcastingActiveViewport();
void StopBroadcastingActiveViewport();
private:
bool LoadModuleDependencies();
void ShutdownModuleDependencies();
private:
TSharedPtr<class FNDIFinderService> NDIFinderService = nullptr;
TSharedPtr<class FNDIConnectionService> NDIConnectionService = nullptr;
void* NDI_LIB_HANDLE = nullptr;
/** List of platforms that the media player support. */
TArray<FString> SupportedPlatforms;
/** List of supported URI schemes. */
TArray<FString> SupportedUriSchemes;
};

View File

@@ -0,0 +1,52 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Misc/FrameRate.h>
#include <UObject/Object.h>
#include "NDIIOPluginSettings.generated.h"
/**
Settings for the Broadcasting of the Active Viewport configurable in the running editor of the application
*/
UCLASS(Config = Engine, DefaultConfig)
class NDIIO_API UNDIIOPluginSettings : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, Category = "NDI IO", META = (DisplayName = "Description", MultiLine = true))
FString Decription = TEXT(
"These values define the 'Active Viewport' broadcast settings and does not define default values for outputs."
"\r\n"
"\r\nApplication Stream Name - The default name to use when broadcasting the Currently Active Viewport over "
"NDI."
"\r\nBroadcast Rate - Indicates the preferred frame rate to broadcast the Currently Active Viewport over NDI."
"\r\nPreferred FrameSize - Indicates the preferred frame size to broadcast the Currently Active Viewport over "
"NDI."
"\r\nBegin Broadcast On Play - Starts the broadcast of the Currently Active Viewport immediately on Play."
);
/** The default name to use when broadcasting the Currently Active Viewport over NDI. */
UPROPERTY(Config, EditAnywhere, Category = "NDI IO")
FString ApplicationStreamName = FString("Unreal Engine");
/** Indicates the preferred frame rate to broadcast the Currently Active Viewport over NDI. */
UPROPERTY(Config, EditAnywhere, Category = "NDI IO", META = (DisplayName = "Broadcast Rate"))
FFrameRate BroadcastRate = FFrameRate(60, 1);
/** Indicates the preferred frame size to broadcast the Currently Active Viewport over NDI. */
UPROPERTY(Config, EditAnywhere, Category = "NDI IO", META = (DisplayName = "Preferred Broadcast Framesize"))
FIntPoint PreferredFrameSize = FIntPoint(1920, 1080);
UPROPERTY(Config, EditAnywhere, Category = "NDI IO", META = (DisplayName = "Begin Broadcast On Play"))
bool bBeginBroadcastOnPlay = false;
};

View File

@@ -0,0 +1,52 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Kismet/BlueprintFunctionLibrary.h>
#include <Structures/NDIBroadcastConfiguration.h>
#include "NDIBroadcastConfigurationLibrary.generated.h"
UCLASS(NotBlueprintable, BlueprintType, Category = "NDI IO",
META = (DisplayName = "NDI Broadcast Configuration Library"))
class NDIIO_API UNDIBroadcastConfigurationLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
private:
/**
Returns a value indicating whether the two structures are comparably equal
@param A The structure used as the source comparator
@param B The structure used as the target comparator
@return The resulting value of the comparator operator
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO",
META = (DisplayName = "Equals (NDI Broadcast Configuration)",
CompactNodeTitle = "==", Keywords = "= == Equals", AllowPrivateAccess = true))
static bool K2_Compare_NDIBroadcastConfiguration(FNDIBroadcastConfiguration A, FNDIBroadcastConfiguration B)
{
return A == B;
}
/**
Returns a value indicating whether the two structures are NOT comparably equal
@param A The structure used as the source comparator
@param B The structure used as the target comparator
@return The resulting value of the comparator operator
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO",
META = (DisplayName = "Not Equals (NDI Broadcast Configuration)",
CompactNodeTitle = "!=", Keywords = "! != Not Equals", AllowPrivateAccess = true))
static bool K2_Compare_Not_NDIBroadcastConfiguration(FNDIBroadcastConfiguration A, FNDIBroadcastConfiguration B)
{
return A != B;
}
};

View File

@@ -0,0 +1,82 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Kismet/BlueprintFunctionLibrary.h>
#include <Structures/NDIConnectionInformation.h>
#include "NDIConnectionInformationLibrary.generated.h"
UCLASS(NotBlueprintable, BlueprintType, Category = "NDI IO",
META = (DisplayName = "NDI Connection Information Library"))
class NDIIO_API UNDIConnectionInformationLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
private:
/**
Returns a value indicating whether the two structures are comparably equal
@param A The structure used as the source comparator
@param B The structure used as the target comparator
@return The resulting value of the comparator operator
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO",
META = (DisplayName = "Equals (NDI Connection Information)",
CompactNodeTitle = "==", Keywords = "= == Equals", AllowPrivateAccess = true))
static bool K2_Compare_NDIConnectionInformation(FNDIConnectionInformation A, FNDIConnectionInformation B)
{
return A == B;
}
/**
Returns a value indicating whether the two structures are NOT comparably equal
@param A The structure used as the source comparator
@param B The structure used as the target comparator
@return The resulting value of the comparator operator
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO",
META = (DisplayName = "Not Equals (NDI Connection Information)",
CompactNodeTitle = "!=", Keywords = "! != Not Equals", AllowPrivateAccess = true))
static bool K2_Compare_Not_NDIConnectionInformation(FNDIConnectionInformation A, FNDIConnectionInformation B)
{
return A != B;
}
/**
Returns a value indicating whether the property values of the supplied structure is valid
@param ConnectionInformation The structure to validate
@return An indication of the supplied structures validity
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Is Valid?", AllowPrivateAccess = true))
static bool K2_NDIConnectionInformation_IsValid(FNDIConnectionInformation& ConnectionInformation)
{
return ConnectionInformation.IsValid();
}
/**
Resets the structure's properties to their default values
@param ConnectionInformation The structure to reset to the default value
@return The reference to the passed in structure after the 'reset' has been completed
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Reset Connection Information", AllowPrivateAccess = true))
static UPARAM(ref) FNDIConnectionInformation& K2_NDIConnectionInformation_Reset(
UPARAM(ref) FNDIConnectionInformation& ConnectionInformation)
{
// call the underlying function to reset the properties of the object
ConnectionInformation.Reset();
// return the ConnectionInformation object reference
return ConnectionInformation;
}
};

View File

@@ -0,0 +1,121 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Kismet/BlueprintFunctionLibrary.h>
#include <Structures/NDIConnectionInformation.h>
#include <Objects/Media/NDIMediaReceiver.h>
#include <Objects/Media/NDIMediaSender.h>
#include "NDIIOLibrary.generated.h"
/**
An metadata element as returned by K2_ParseNDIMetaData()
Blueprints do not support recursive datastructures, so parsing metadata
with this will result in only the top-level elements being returned.
*/
USTRUCT(BlueprintType)
struct FNDIMetaDataElement
{
GENERATED_USTRUCT_BODY()
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Metadata")
FString ElementName;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Metadata")
TMap<FString,FString> Attributes;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Metadata")
FString Data;
};
UCLASS(META = (DisplayName = "NDI IO Library"))
class NDIIO_API UNDIIOLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
private:
/**
Retrieves a collection of NDI sources appearing on the network
@return A collection of NDI Sources appearing on the network
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO",
META = (DisplayName = "Get NDI Source Collection", AllowPrivateAccess = true))
static const TArray<FNDIConnectionInformation> K2_GetNDISourceCollection();
/**
Attempts to search the NDI Source Collection for the source name, returning a result indicating
success with the ConnectionInformation parameter filled with the found connection
@param ConnectionInformation The connection information for a successful find with the supplied InSourceName
@param InSourceName The name of the source to find within the collection of NDI sources
@return The result of whether the search was successful
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Find Network Source by Name", DefaultToSelf = "WorldContextObject",
HidePin = "WorldContextObject", AllowPrivateAccess = true))
static const bool K2_FindNetworkSourceByName(UObject* WorldContextObject,
FNDIConnectionInformation& ConnectionInformation,
FString InSourceName = FString(""));
private:
/**
Attempts to start broadcasting the active viewport. The output of the active viewport is the current camera
that is actively being viewed (through), and does not have to be an NDI Broadcast Viewport Component.
@return The result of whether broadcasting the active viewport was started
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Begin Broadcasting Active Viewport", DefaultToSelf = "WorldContextObject",
HidePin = "WorldContextObject", AllowPrivateAccess = true))
static bool K2_BeginBroadcastingActiveViewport(UObject* WorldContextObject);
/**
Will stop broadcasting the active viewport, which was started by a previous call to 'Begin Broadcasting Active
Viewport'
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Stop Broadcasting Active Viewport", DefaultToSelf = "WorldContextObject",
HidePin = "WorldContextObject", AllowPrivateAccess = true))
static void K2_StopBroadcastingActiveViewport(UObject* WorldContextObject);
private:
/**
Returns an NDI Media Receiver object
@param Receiver The Receiver object to return
@return The selected Receiver object
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Get NDI Media Receiver", AllowPrivateAccess = true))
static UPARAM(ref) UNDIMediaReceiver* K2_GetNDIMediaReceiver(UNDIMediaReceiver* Receiver = nullptr);
/**
Returns an NDI Media Sender object
@param Sender The Sender object to return
@return The selected Sender object
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Get NDI Media Sender", AllowPrivateAccess = true))
static UPARAM(ref) UNDIMediaSender* K2_GetNDIMediaSender(UNDIMediaSender* Sender = nullptr);
private:
/**
Parses a string as metadata
Blueprints do not support recursive datastructures, so parsing metadata
with this will result in only the top-level elements being returned.
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Parse NDI MetaData", AllowPrivateAccess = true))
static const TArray<FNDIMetaDataElement> K2_ParseNDIMetaData(FString Data);
};

View File

@@ -0,0 +1,70 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Kismet/BlueprintFunctionLibrary.h>
#include <Structures/NDIReceiverPerformanceData.h>
#include "NDIReceiverPerformanceDataLibrary.generated.h"
UCLASS(NotBlueprintable, BlueprintType, Category = "NDI IO",
META = (DisplayName = "NDI Receiver Performance Data Library"))
class NDIIO_API UNDIReceiverPerformanceDataLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
private:
/**
Returns a value indicating whether the two structures are comparably equal
@param A The structure used as the source comparator
@param B The structure used as the target comparator
@return The resulting value of the comparator operator
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO",
META = (DisplayName = "Equals (NDI Receiver Performance Data)",
CompactNodeTitle = "==", Keywords = "= == Equals", AllowPrivateAccess = true))
static bool K2_Compare_NDIReceiverPerformanceData(FNDIReceiverPerformanceData A, FNDIReceiverPerformanceData B)
{
return A == B;
}
/**
Returns a value indicating whether the two structures are NOT comparably equal
@param A The structure used as the source comparator
@param B The structure used as the target comparator
@return The resulting value of the comparator operator
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "NDI IO",
META = (DisplayName = "Not Equals (NDI Receiver Performance Data)",
CompactNodeTitle = "!=", Keywords = "! != Not Equals", AllowPrivateAccess = true))
static bool K2_Compare_Not_NDIReceiverPerformanceData(FNDIReceiverPerformanceData A, FNDIReceiverPerformanceData B)
{
return A != B;
}
/**
Resets the structure's properties to their default values
@param PerformanceData The structure to reset to the default value
@return The reference to the passed in structure after the 'reset' has been completed
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO",
META = (DisplayName = "Reset Receiver Performance Data", AllowPrivateAccess = true))
static UPARAM(ref) FNDIReceiverPerformanceData& K2_NDIReceiverPerformanceData_Reset(
UPARAM(ref) FNDIReceiverPerformanceData& PerformanceData)
{
// call the underlying function to reset the properties of the object
PerformanceData.Reset();
// return the Performance Data object reference
return PerformanceData;
}
};

View File

@@ -0,0 +1,361 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <NDIIOPluginAPI.h>
#include <UObject/Object.h>
#include <Misc/Timecode.h>
#include <Misc/FrameRate.h>
#include <TimeSynchronizableMediaSource.h>
#include <RendererInterface.h>
#include <Objects/Media/NDIMediaSoundWave.h>
#include <Objects/Media/NDIMediaTexture2D.h>
#include <Structures/NDIConnectionInformation.h>
#include <Structures/NDIReceiverPerformanceData.h>
#include "NDIMediaReceiver.generated.h"
namespace NDIMediaOption
{
static const FName IsNDIMediaReceiver("IsNDIMediaReceiver");
static const FName MaxVideoFrameBuffer("MaxVideoFrameBuffer");
static const FName MaxAudioFrameBuffer("MaxAudioFrameBuffer");
static const FName MaxAncillaryFrameBuffer("MaxAncillaryFrameBuffer");
}
/**
Delegates to notify that the NDIMediaReceiver has received a video, audio, or metadata frame
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaReceiverVideoReceived, UNDIMediaReceiver*, Receiver);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaReceiverAudioReceived, UNDIMediaReceiver*, Receiver);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FNDIMediaReceiverMetaDataReceived, UNDIMediaReceiver*, Receiver, FString, Data, bool, bAttachedToVideoFrame);
/**
A Media object representing the NDI Receiver for being able to receive Audio, Video, and Metadata over NDI
*/
UCLASS(BlueprintType, Blueprintable, HideCategories = ("Platforms"), Category = "NDI IO",
HideCategories = ("Information"), AutoCollapseCategories = ("Content"),
META = (DisplayName = "NDI Media Receiver"))
class NDIIO_API UNDIMediaReceiver : public UTimeSynchronizableMediaSource
{
GENERATED_BODY()
public:
/**
Information describing detailed information about the sender this receiver is to connect to
*/
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings",
META = (DisplayName = "Connection", AllowPrivateAccess = true))
FNDIConnectionInformation ConnectionSetting;
private:
/**
The current frame count, seconds, minutes, and hours in time-code notation
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Timecode", AllowPrivateAccess = true))
FTimecode Timecode;
/**
The desired number of frames (per second) for video to be displayed
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Frame Rate", AllowPrivateAccess = true))
FFrameRate FrameRate;
/**
The width and height of the last received video frame
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Resolution", AllowPrivateAccess = true))
FIntPoint Resolution;
/**
Indicates whether the timecode should be synced to the Source Timecode value
*/
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings",
META = (DisplayName = "Sync Timecode to Source", AllowPrivateAccess = true))
bool bSyncTimecodeToSource = true;
/**
Should perform the sRGB to Linear color space conversion
*/
UPROPERTY(BlueprintReadonly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Perform sRGB to Linear?", AllowPrivateAccess = true))
bool bPerformsRGBtoLinear = true;
/**
Information describing detailed information about the sender this receiver is currently connected to
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Connection Information", AllowPrivateAccess = true))
FNDIConnectionInformation ConnectionInformation;
/**
Information describing detailed information about the receiver performance when connected to an NDI sender
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Performance Data", AllowPrivateAccess = true))
FNDIReceiverPerformanceData PerformanceData;
/**
Provides an NDI Video Texture object to render videos frames from the source onto (optional)
*/
UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintSetter = "ChangeVideoTexture", Category = "Content",
AdvancedDisplay, META = (DisplayName = "Video Texture (optional)", AllowPrivateAccess = true))
UNDIMediaTexture2D* VideoTexture = nullptr;
public:
DECLARE_EVENT_OneParam(FNDIMediaReceiverConnectionEvent, FOnReceiverConnectionEvent,
UNDIMediaReceiver*) FOnReceiverConnectionEvent OnNDIReceiverConnectedEvent;
DECLARE_EVENT_OneParam(FNDIMediaReceiverDisconnectionEvent, FOnReceiverDisconnectionEvent,
UNDIMediaReceiver*) FOnReceiverDisconnectionEvent OnNDIReceiverDisconnectedEvent;
DECLARE_EVENT_TwoParams(FNDIMediaReceiverVideoCaptureEvent, FOnReceiverVideoCaptureEvent,
UNDIMediaReceiver*, const NDIlib_video_frame_v2_t&) FOnReceiverVideoCaptureEvent OnNDIReceiverVideoCaptureEvent;
DECLARE_EVENT_TwoParams(FNDIMediaReceiverAudioCaptureEvent, FOnReceiverAudioCaptureEvent,
UNDIMediaReceiver*, const NDIlib_audio_frame_v2_t&) FOnReceiverAudioCaptureEvent OnNDIReceiverAudioCaptureEvent;
DECLARE_EVENT_TwoParams(FNDIMediaReceiverMetadataCaptureEvent, FOnReceiverMetadataCaptureEvent,
UNDIMediaReceiver*, const NDIlib_metadata_frame_t&) FOnReceiverMetadataCaptureEvent OnNDIReceiverMetadataCaptureEvent;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On Video Received by Receiver", AllowPrivateAccess = true))
FNDIMediaReceiverVideoReceived OnReceiverVideoReceived;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On Audio Received by Receiver", AllowPrivateAccess = true))
FNDIMediaReceiverAudioReceived OnReceiverAudioReceived;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On MetaData Received by Receiver", AllowPrivateAccess = true))
FNDIMediaReceiverMetaDataReceived OnReceiverMetaDataReceived;
public:
UNDIMediaReceiver();
/**
Called before destroying the object. This is called immediately upon deciding to destroy the object,
to allow the object to begin an asynchronous cleanup process.
*/
void BeginDestroy() override;
/**
Attempts to perform initialization logic for creating a receiver through the NDI sdk api
*/
enum class EUsage
{
Standalone, // The receiver automatically captures its own video frame every engine render frame
Controlled // The user of the receiver manually triggers capturing a frame through CaptureConnectedVideo/Audio()
};
bool Initialize(const FNDIConnectionInformation& InConnectionInformation, EUsage InUsage);
bool Initialize(EUsage Inusage);
/**
Attempt to (re-)start the connection
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Start Connection"))
void StartConnection();
/**
Stop the connection
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Stop Connection"))
void StopConnection();
/**
Attempts to change the connection to another NDI sender source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Connection"))
void ChangeConnection(const FNDIConnectionInformation& InConnectionInformation);
/**
Attempts to change the Video Texture object used as the video frame capture object
*/
UFUNCTION(BlueprintSetter)
void ChangeVideoTexture(UNDIMediaTexture2D* InVideoTexture = nullptr);
/**
Attempts to generate the pcm data required by the 'AudioWave' object
*/
int32 GeneratePCMData(UNDIMediaSoundWave* AudioWave, uint8* PCMData, const int32 SamplesNeeded);
int32 GetAudioChannels();
/**
Attempts to register a sound wave object with this object
*/
void RegisterAudioWave(UNDIMediaSoundWave* InAudioWave = nullptr);
/**
This will send a metadata frame to the sender
The data is expected to be valid XML
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Metadata To Sender"))
void SendMetadataFrame(const FString& Data);
/**
This will send a metadata frame to the sender
The data will be formatted as: <Element>ElementData</Element>
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Metadata To Sender (Element + Data)"))
void SendMetadataFrameAttr(const FString& Element, const FString& ElementData);
/**
This will send a metadata frame to the sender
The data will be formatted as: <Element Key0="Value0" Key1="Value1" Keyn="Valuen"/>
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Metadata To Sender (Element + Attributes)"))
void SendMetadataFrameAttrs(const FString& Element, const TMap<FString,FString>& Attributes);
/**
This will set the up-stream tally notifications. If no streams are connected, it will automatically
send the tally state upon connection
*/
void SendTallyInformation(const bool& IsOnPreview, const bool& IsOnProgram);
/**
Attempts to immediately stop receiving frames from the connected NDI sender
*/
void Shutdown();
/**
Remove the AudioWave object from this object (if it was previously registered)
@param InAudioWave An NDIMediaSoundWave object registered with this object
*/
void UnregisterAudioWave(UNDIMediaSoundWave* InAudioWave = nullptr);
/**
Updates the DynamicMaterial with the VideoTexture of this object
*/
void UpdateMaterialTexture(class UMaterialInstanceDynamic* MaterialInstance, FString ParameterName);
/**
Attempts to capture a frame from the connected source. If a new frame is captured, broadcast it to
interested receivers through the capture event. Returns true if new data was captured.
*/
bool CaptureConnectedVideo();
bool CaptureConnectedAudio();
bool CaptureConnectedMetadata();
/**
Attempts to immediately update the 'VideoTexture' object with the captured video frame
*/
FTextureRHIRef DisplayFrame(const NDIlib_video_frame_v2_t& video_frame);
private:
void SetIsCurrentlyConnected(bool bConnected);
/**
Attempts to gather the performance metrics of the connection to the remote source
*/
void GatherPerformanceMetrics();
public:
/**
Set whether or not a RGB to Linear conversion is made
*/
void PerformsRGBToLinearConversion(bool Value);
/**
Returns the current framerate of the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Current Frame Rate"))
const FFrameRate& GetCurrentFrameRate() const;
/**
Returns the current resolution of the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Current Resolution"))
const FIntPoint& GetCurrentResolution() const;
/**
Returns the current timecode of the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Current Timecode"))
const FTimecode& GetCurrentTimecode() const;
/**
Returns the current connection information of the connected source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Current Connection Information"))
const FNDIConnectionInformation& GetCurrentConnectionInformation() const;
/**
Returns the current performance data of the receiver while connected to the source
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Get Performance Data"))
const FNDIReceiverPerformanceData& GetPerformanceData() const;
/** Returns a value indicating whether this object is currently connected to the sender source */
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Is Currently Connected"))
const bool GetIsCurrentlyConnected() const;
private:
/**
Perform the color conversion (if any) and bit copy from the gpu
*/
FTextureRHIRef DrawProgressiveVideoFrame(FRHICommandListImmediate& RHICmdList, const NDIlib_video_frame_v2_t& Result);
FTextureRHIRef DrawProgressiveVideoFrameAlpha(FRHICommandListImmediate& RHICmdList, const NDIlib_video_frame_v2_t& Result);
FTextureRHIRef DrawInterlacedVideoFrame(FRHICommandListImmediate& RHICmdList, const NDIlib_video_frame_v2_t& Result);
FTextureRHIRef DrawInterlacedVideoFrameAlpha(FRHICommandListImmediate& RHICmdList, const NDIlib_video_frame_v2_t& Result);
virtual bool Validate() const override
{
return true;
}
virtual FString GetUrl() const override;
FTextureResource* GetVideoTextureResource() const;
FTextureResource* GetInternalVideoTextureResource() const;
#if WITH_EDITORONLY_DATA
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
public:
virtual bool GetMediaOption(const FName& Key, bool DefaultValue) const override;
virtual int64 GetMediaOption(const FName& Key, int64 DefaultValue) const override;
virtual FString GetMediaOption(const FName& Key, const FString& DefaultValue) const override;
virtual bool HasMediaOption(const FName& Key) const override;
private:
int64_t LastFrameTimestamp = 0;
NDIlib_frame_format_type_e LastFrameFormatType = NDIlib_frame_format_type_max;
bool bIsCurrentlyConnected = false;
NDIlib_recv_instance_t p_receive_instance = nullptr;
NDIlib_framesync_instance_t p_framesync_instance = nullptr;
FCriticalSection RenderSyncContext;
FCriticalSection AudioSyncContext;
FCriticalSection MetadataSyncContext;
FCriticalSection ConnectionSyncContext;
TArray<UNDIMediaSoundWave*> AudioSourceCollection;
UNDIMediaTexture2D* InternalVideoTexture = nullptr;
FTextureRHIRef SourceTexture;
FTextureRHIRef SourceAlphaTexture;
FPooledRenderTargetDesc RenderTargetDescriptor;
TRefCountPtr<IPooledRenderTarget> RenderTarget;
enum class EDrawMode
{
Invalid,
Progressive,
ProgressiveAlpha,
Interlaced,
InterlacedAlpha
};
EDrawMode DrawMode = EDrawMode::Invalid;
FDelegateHandle FrameEndRTHandle;
FDelegateHandle VideoCaptureEventHandle;
};

View File

@@ -0,0 +1,362 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <NDIIOPluginAPI.h>
#include <RendererInterface.h>
#include <UObject/Object.h>
#include <Misc/FrameRate.h>
#include <Engine/TextureRenderTarget2D.h>
#include <Sound/SoundSubmix.h>
#include <Structures/NDIBroadcastConfiguration.h>
#include <Objects/Media/NDIMediaTexture2D.h>
#include <BaseMediaSource.h>
#include <Misc/EngineVersionComparison.h>
#include <string>
#include "NDIMediaSender.generated.h"
/**
A delegate used for notifications on property changes on the NDIMediaSender object
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaSenderPropertyChanged, UNDIMediaSender*, Sender);
/**
A delegate used for notifications on the NDIMediaSender object receiving metadata
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FNDIMediaSenderMetaDataReceived, UNDIMediaSender*, Sender, FString, Data);
/**
Delegates to notify just before and after the NDIMediaSender sends a video, audio, or metadata frame
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaSenderVideoPreSend, UNDIMediaSender*, Sender);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaSenderVideoSent, UNDIMediaSender*, Sender);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaSenderAudioPreSend, UNDIMediaSender*, Sender);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaSenderAudioSent, UNDIMediaSender*, Sender);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaSenderMetaDataPreSend, UNDIMediaSender*, Sender);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNDIMediaSenderMetaDataSent, UNDIMediaSender*, Sender);
/**
Defines a media object representing an NDI(R) Sender object. This object is used with the
NDI Broadcast Component to send Audio / Video / Metadata to a 'receiving' NDI object.
*/
UCLASS(BlueprintType, Blueprintable, HideCategories = ("Platforms"), Category = "NDI IO",
HideCategories = ("Information"), AutoCollapseCategories = ("Content"),
META = (DisplayName = "NDI Sender Object"))
class NDIIO_API UNDIMediaSender : public UBaseMediaSource
{
GENERATED_UCLASS_BODY()
private:
/** Describes a user-friendly name of the output stream to differentiate from other output streams on the current
* machine */
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Broadcast Settings",
META = (DisplayName = "Source Name", AllowPrivateAccess = true))
FString SourceName = TEXT("Unreal Engine Output");
/** Describes the output frame size while sending video frame over NDI */
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Broadcast Settings",
META = (DisplayName = "Frame Size", AllowPrivateAccess = true))
FIntPoint FrameSize = FIntPoint(1920, 1080);
/** Represents the desired number of frames (per second) for video to be sent over NDI */
UPROPERTY(BlueprintReadwrite, EditDefaultsOnly, Category = "Broadcast Settings",
META = (DisplayName = "Frame Rate", AllowPrivateAccess = true))
FFrameRate FrameRate = FFrameRate(60, 1);
/** Sets whether or not to output an alpha channel */
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Broadcast Settings",
META = (DisplayName="Output Alpha", AllowPrivateAccess = true))
bool OutputAlpha = false;
UPROPERTY(BlueprintReadonly, VisibleAnywhere, Category = "Broadcast Settings",
META = (DisplayName = "Alpha Remap Min", AllowPrivateAccess = true))
float AlphaMin = 0.f;
UPROPERTY(BlueprintReadonly, VisibleAnywhere, Category = "Broadcast Settings",
META = (DisplayName = "Alpha Remap Max", AllowPrivateAccess = true))
float AlphaMax = 1.f;
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Broadcast Settings",
META = (DisplayName="Enable Audio", AllowPrivateAccess = true))
bool bEnableAudio = true;
/** Sets whether or not to present PTZ capabilities */
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Broadcast Settings",
META = (DisplayName="Enable PTZ", AllowPrivateAccess = true))
bool bEnablePTZ = true;
/** Indicates the texture to send over NDI (optional) */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Content",
AdvancedDisplay, META = (DisplayName = "Render Target (optional)", AllowPrivateAccess = true))
UTextureRenderTarget2D* RenderTarget = nullptr;
/**
Should perform the Linear to sRGB color space conversion
*/
UPROPERTY(BlueprintReadonly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Perform Linear to sRGB?", AllowPrivateAccess = true))
bool bPerformLinearTosRGB = true;
public:
UPROPERTY()
FNDIMediaSenderPropertyChanged OnBroadcastConfigurationChanged;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On MetaData Received by Sender", AllowPrivateAccess = true))
FNDIMediaSenderMetaDataReceived OnSenderMetaDataReceived;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On Before Video Being Sent by Sender", AllowPrivateAccess = true))
FNDIMediaSenderVideoPreSend OnSenderVideoPreSend;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On Video Sent by Sender", AllowPrivateAccess = true))
FNDIMediaSenderVideoSent OnSenderVideoSent;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On Before Audio Being Sent by Sender", AllowPrivateAccess = true))
FNDIMediaSenderAudioPreSend OnSenderAudioPreSend;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On Audio Sent by Sender", AllowPrivateAccess = true))
FNDIMediaSenderAudioSent OnSenderAudioSent;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On Before MetaData Being Sent by Sender", AllowPrivateAccess = true))
FNDIMediaSenderMetaDataPreSend OnSenderMetaDataPreSend;
UPROPERTY(BlueprintAssignable, Category="NDI Events", META = (DisplayName = "On MetaData Sent by Sender", AllowPrivateAccess = true))
FNDIMediaSenderMetaDataSent OnSenderMetaDataSent;
public:
/**
Attempts to perform initialization logic for creating a sender through the NDI(R) sdk api
*/
void Initialize(USoundSubmix* SubmixCapture);
/**
Changes the name of the sender object as seen on the network for remote connections
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Source Name"))
void ChangeSourceName(const FString& InSourceName);
/**
Attempts to change the Broadcast information associated with this media object
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Change Broadcast Configuration"))
void ChangeBroadcastConfiguration(const FNDIBroadcastConfiguration& InConfiguration);
/**
This will send a metadata frame to all receivers
The data is expected to be valid XML
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Metadata To Receivers"))
void SendMetadataFrame(const FString& Data, bool AttachToVideoFrame = true);
/**
This will send a metadata frame to all receivers
The data will be formatted as: <Element>ElementData</Element>
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Metadata To Receivers (Element + Data)"))
void SendMetadataFrameAttr(const FString& Element, const FString& ElementData, bool AttachToVideoFrame = true);
/**
This will send a metadata frame to all receivers
The data will be formatted as: <Element Key0="Value0" Key1="Value1" Keyn="Valuen"/>
*/
UFUNCTION(BlueprintCallable, Category = "NDI IO", META = (DisplayName = "Send Metadata To Receivers (Element + Attributes)"))
void SendMetadataFrameAttrs(const FString& Element, const TMap<FString,FString>& Attributes, bool AttachToVideoFrame = true);
/**
Attempts to change the RenderTarget used in sending video frames over NDI
*/
void ChangeVideoTexture(UTextureRenderTarget2D* VideoTexture = nullptr);
/**
Change the alpha remapping settings
*/
void ChangeAlphaRemap(float AlphaMinIn, float AlphaMaxIn);
/**
Determines the current tally information. If you specify a timeout then it will wait until it has
changed, otherwise it will simply poll it and return the current tally immediately
@param IsOnPreview - A state indicating whether this source in on preview of a receiver
@param IsOnProgram - A state indicating whether this source is on program of a receiver
@param TimeOut - Indicates the amount of time to wait (in milliseconds) until a change has occurred
*/
void GetTallyInformation(bool& IsOnPreview, bool& IsOnProgram, uint32 Timeout = 0);
/**
Gets the current number of receivers connected to this source. This can be used to avoid rendering
when nothing is connected to the video source. which can significantly improve the efficiency if
you want to make a lot of sources available on the network
*/
void GetNumberOfConnections(int32& Result);
/**
Attempts to immediately stop sending frames over NDI to any connected receivers
*/
void Shutdown();
/**
Called before destroying the object. This is called immediately upon deciding to destroy the object,
to allow the object to begin an asynchronous cleanup process.
*/
virtual void BeginDestroy() override;
/**
Set whether or not a RGB to Linear conversion is made
*/
void PerformLinearTosRGBConversion(bool Value);
/**
Set whether or not to enable PTZ support
*/
void EnablePTZ(bool Value);
/**
Returns the Render Target used for sending a frame over NDI
*/
UTextureRenderTarget2D* GetRenderTarget();
const FIntPoint& GetFrameSize()
{
return this->FrameSize;
}
const FFrameRate& GetFrameRate()
{
return this->FrameRate;
}
private:
bool CreateSender();
/**
Attempts to get a metadata frame from the sender.
If there is one, the data is broadcast through OnSenderMetaDataReceived.
Returns true if metadata was received, false otherwise.
*/
bool GetMetadataFrame();
/**
This will attempt to generate an audio frame, add the frame to the stack and return immediately,
having scheduled the frame asynchronously.
*/
void TrySendAudioFrame(int64 time_code, float* AudioData, int32 NumSamples, int32 NumChannels, const int32 SampleRate, double AudioClock);
/**
This will attempt to generate a video frame, add the frame to the stack and return immediately,
having scheduled the frame asynchronously.
*/
void TrySendVideoFrame(int64 time_code = 0);
/**
Perform the color conversion (if any) and bit copy from the gpu
*/
bool DrawRenderTarget(FRHICommandListImmediate& RHICmdList);
/**
Change the render target configuration based on the passed in parameters
@param InFrameSize The frame size to resize the render target to
@param InFrameRate The frame rate at which we should be sending frames via NDI
*/
void ChangeRenderTargetConfiguration(FIntPoint InFrameSize, FFrameRate InFrameRate);
virtual bool Validate() const override
{
return true;
}
virtual FString GetUrl() const override
{
return FString();
}
FTextureResource* GetRenderTargetResource() const;
void PrepareDefaultTexture();
private:
std::atomic<bool> bIsChangingBroadcastSize { false };
FTimecode LastRenderTime;
FTextureRHIRef DefaultVideoTextureRHI;
TArray<float> SendAudioData;
NDIlib_video_frame_v2_t NDI_video_frame;
NDIlib_send_instance_t p_send_instance = nullptr;
FCriticalSection AudioSyncContext;
FCriticalSection RenderSyncContext;
/**
A texture with CPU readback
*/
class MappedTexture
{
private:
FTextureRHIRef Texture = nullptr;
void* pData = nullptr;
std::string MetaData;
FIntPoint FrameSize;
public:
~MappedTexture();
void Create(FIntPoint FrameSize);
void Destroy();
FIntPoint GetSizeXY() const;
void Resolve(FRHICommandListImmediate& RHICmdList, FRHITexture* SourceTextureRHI, const FResolveRect& Rect = FResolveRect(), const FResolveRect& DestRect = FResolveRect());
void Map(FRHICommandListImmediate& RHICmdList, int32& OutWidth, int32& OutHeight, int32& OutLineStride);
void* MappedData() const;
void Unmap(FRHICommandListImmediate& RHICmdList);
void AddMetaData(const FString& Data);
const std::string& GetMetaData() const;
private:
void PrepareTexture();
};
/**
Class for managing the sending of mapped texture data to an NDI video stream.
Sending is done asynchronously, so mapping and unmapping of texture data must
be managed so that CPU accessible texture content remains valid until the
sending of the frame is guaranteed to have been completed. This is achieved
by double-buffering readback textures.
*/
class MappedTextureASyncSender
{
private:
MappedTexture MappedTextures[2];
int32 CurrentIndex = 0;
public:
void Create(FIntPoint FrameSize);
void Destroy();
FIntPoint GetSizeXY() const;
void Resolve(FRHICommandListImmediate& RHICmdList, FRHITexture* SourceTextureRHI, const FResolveRect& Rect = FResolveRect(), const FResolveRect& DestRect = FResolveRect());
void Map(FRHICommandListImmediate& RHICmdList, int32& OutWidth, int32& OutHeight, int32& OutLineStride);
void Send(FRHICommandListImmediate& RHICmdList, NDIlib_send_instance_t p_send_instance, NDIlib_video_frame_v2_t& p_video_data);
void Flush(FRHICommandListImmediate& RHICmdList, NDIlib_send_instance_t p_send_instance);
void AddMetaData(const FString& Data);
};
MappedTextureASyncSender ReadbackTextures;
bool ReadbackTexturesHaveAlpha = false;
FPooledRenderTargetDesc RenderTargetDescriptor;
};

View File

@@ -0,0 +1,42 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Sound/SoundWaveProcedural.h>
#include "NDIMediaSoundWave.generated.h"
/**
Defines a SoundWave object used by an NDI Media Receiver object for capturing audio from
a network source
*/
UCLASS(NotBlueprintable, Category = "NDI IO", META = (DisplayName = "NDI Media Sound Wave"))
class NDIIO_API UNDIMediaSoundWave : public USoundWaveProcedural
{
GENERATED_UCLASS_BODY()
public:
/**
Set the Media Source of this object, so that when this object is called to 'GeneratePCMData' by the engine
we can request the media source to provide the pcm data from the current connected source
*/
void SetConnectionSource(class UNDIMediaReceiver* InMediaSource = nullptr);
protected:
/**
Called by the engine to generate pcm data to be 'heard' by audio listener objects
*/
virtual int32 OnGeneratePCMAudio(TArray<uint8>& OutAudio, int32 NumSamples) override final;
virtual bool IsReadyForFinishDestroy() override final;
private:
FCriticalSection SyncContext;
class UNDIMediaReceiver* MediaSource = nullptr;
};

View File

@@ -0,0 +1,49 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Engine/Texture.h>
#include <Misc/EngineVersionComparison.h>
#include <RHI.h>
#include <RHICommandList.h>
#include "NDIMediaTexture2D.generated.h"
/**
A Texture Object used by an NDI Media Receiver object for capturing video from
a network source
*/
UCLASS(NotBlueprintType, NotBlueprintable, HideDropdown,
HideCategories = (ImportSettings, Compression, Texture, Adjustments, Compositing, LevelOfDetail, Object),
META = (DisplayName = "NDI Media Texture 2D"))
class NDIIO_API UNDIMediaTexture2D : public UTexture
{
GENERATED_UCLASS_BODY()
public:
virtual float GetSurfaceHeight() const override;
virtual float GetSurfaceWidth() const override;
virtual float GetSurfaceDepth() const;
virtual uint32 GetSurfaceArraySize() const;
virtual ETextureClass GetTextureClass() const;
virtual void GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) override;
virtual EMaterialValueType GetMaterialType() const override;
virtual void UpdateTextureReference(FRHICommandList& RHICmdList, FTextureRHIRef Reference) final;
private:
virtual class FTextureResource* CreateResource() override;
void SetMyResource(FTextureResource* ResourceIn);
FTextureResource* GetMyResource();
const FTextureResource* GetMyResource() const;
};

View File

@@ -0,0 +1,54 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <ExternalTexture.h>
#include <TextureResource.h>
#include <Misc/EngineVersionComparison.h>
/**
A Texture Resource object used by the NDIMediaTexture2D object for capturing video
from a network source
*/
class NDIIO_API FNDIMediaTextureResource : public FTextureResource
{
public:
/**
Constructs a new instance of this object specifying a media texture owner
@param Owner The media object used as the owner for this object
*/
FNDIMediaTextureResource(class UNDIMediaTexture2D* Owner = nullptr);
#if (ENGINE_MAJOR_VERSION > 5) || ((ENGINE_MAJOR_VERSION == 5) && (ENGINE_MINOR_VERSION >= 3)) // 5.3 or later
/** FTextureResource Interface Implementation for 'InitDynamicRHI' */
virtual void InitRHI(FRHICommandListBase& RHICmdList) override;
/** FTextureResource Interface Implementation for 'ReleaseDynamicRHI' */
virtual void ReleaseRHI() override;
#else
/** FTextureResource Interface Implementation for 'InitDynamicRHI' */
virtual void InitDynamicRHI() override;
/** FTextureResource Interface Implementation for 'ReleaseDynamicRHI' */
virtual void ReleaseDynamicRHI() override;
#endif
/** FTextureResource Interface Implementation for 'GetResourceSize' */
SIZE_T GetResourceSize();
/** FTextureResource Interface Implementation for 'GetSizeX' */
virtual uint32 GetSizeX() const override;
/** FTextureResource Interface Implementation for 'GetSizeY' */
virtual uint32 GetSizeY() const override;
private:
class UNDIMediaTexture2D* MediaTexture = nullptr;
};

View File

@@ -0,0 +1,109 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Engine/TextureRenderTarget2D.h>
#include <AudioDevice.h>
#include <Misc/EngineVersionComparison.h>
#if (ENGINE_MAJOR_VERSION > 5) || ((ENGINE_MAJOR_VERSION == 5) && (ENGINE_MINOR_VERSION >= 3)) // 5.3 or later
#include <ISubmixBufferListener.h>
#endif
#include <Widgets/SWindow.h>
DECLARE_EVENT_OneParam(FNDICoreDelegates, FNDIConnectionServiceSendVideoEvent, int64)
DECLARE_EVENT_SixParams(FNDICoreDelegates, FNDIConnectionServiceSendAudioEvent, int64, float*, int32, int32, const int32, double)
/**
A service which runs and triggers updates for interested parties to be notified of
Audio and Video Frame events
*/
class NDIIO_API FNDIConnectionService final : public ISubmixBufferListener
{
public:
static FNDIConnectionServiceSendVideoEvent EventOnSendVideoFrame;
private:
static TMap<USoundSubmix*, FNDIConnectionServiceSendAudioEvent> SubmixSendAudioFrameEvents;
public:
/**
Constructs a new instance of this object
*/
FNDIConnectionService();
// Begin the service
bool Start();
// Stop the service
void Shutdown();
bool BeginBroadcastingActiveViewport();
void StopBroadcastingActiveViewport();
bool IsRunningInPIE() const
{
return bIsInPIEMode;
}
template <typename UserClass>
static void AddAudioSender(UserClass* InUserObject, USoundSubmix* Submix, typename TMemFunPtrType<false, UserClass, void (int64 /*time_code*/, float* /*AudioData*/, int32 /*NumSamples*/, int32 /*NumChannels*/, const int32 /*SampleRate*/, double /*AudioClock*/)>::Type InFunc)
{
FScopeLock Lock(&AudioSyncContext);
FNDIConnectionServiceSendAudioEvent& SendAudioEvent = SubmixSendAudioFrameEvents.FindOrAdd(Submix);
SendAudioEvent.AddUObject(InUserObject, InFunc);
}
template <typename UserClass>
static void RemoveAudioSender(UserClass* InUserObject)
{
FScopeLock Lock(&AudioSyncContext);
for (auto it = SubmixSendAudioFrameEvents.CreateIterator(); it; ++it)
{
it->Value.RemoveAll(InUserObject);
if (it->Value.IsBound() == false)
it.RemoveCurrent();
}
}
private:
// Handler for when the render thread frame has ended
void OnEndRenderFrame();
void BeginAudioCapture();
void StopAudioCapture();
void OnPostEngineInit();
void OnEnginePreExit();
// Handler for when the active viewport back buffer is about to be resized
void OnActiveViewportBackbufferPreResize(void* Backbuffer);
// Handler for when the back buffer is read to present to the end user
void OnActiveViewportBackbufferReadyToPresent(SWindow& Window, const FTextureRHIRef& Backbuffer);
FTextureResource* GetVideoTextureResource() const;
virtual void OnNewSubmixBuffer(const USoundSubmix* OwningSubmix, float* AudioData, int32 NumSamples, int32 NumChannels, const int32 SampleRate, double AudioClock) override final;
#if (ENGINE_MAJOR_VERSION > 5) || ((ENGINE_MAJOR_VERSION == 5) && (ENGINE_MINOR_VERSION >= 4)) // 5.4 or later
virtual const FString& GetListenerName() const override final;
#endif
private:
bool bIsInitialized = false;
bool bIsAudioInitialized = false;
bool bIsBroadcastingActiveViewport = false;
bool bIsInPIEMode = false;
static FCriticalSection AudioSyncContext;
static FCriticalSection RenderSyncContext;
UTextureRenderTarget2D* VideoTexture = nullptr;
class UNDIMediaSender* ActiveViewportSender = nullptr;
};

View File

@@ -0,0 +1,62 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <HAL/Runnable.h>
#include <HAL/ThreadSafeBool.h>
#include <Structures/NDIConnectionInformation.h>
/**
A Runnable object used for Finding NDI network Sources, and updating interested parties
*/
class NDIIO_API FNDIFinderService : public FRunnable
{
public:
FNDIFinderService();
// Begin the service
virtual bool Start();
// Stop the service
virtual void Shutdown();
public:
/** Get the available sources on the network */
static const TArray<FNDIConnectionInformation> GetNetworkSourceCollection();
/** Call to update an existing collection of network sources to match the current collection */
static bool UpdateSourceCollection(TArray<FNDIConnectionInformation>& InSourceCollection);
/** Event which is triggered when the collection of network sources has changed */
DECLARE_EVENT(FNDICoreDelegates, FNDISourceCollectionChangedEvent)
static FNDISourceCollectionChangedEvent EventOnNDISourceCollectionChanged;
protected:
/** FRunnable Interface implementation for 'Init' */
virtual bool Init() override;
/** FRunnable Interface implementation for 'Stop' */
virtual void Stop() override;
/** FRunnable Interface implementation for 'Run' */
virtual uint32 Run() override;
private:
bool UpdateNetworkSourceCollection();
private:
bool bShouldWaitOneFrame = true;
bool bIsNetworkSourceCollectionDirty = false;
FThreadSafeBool bIsThreadRunning;
FRunnableThread* p_RunnableThread = nullptr;
static TArray<FNDIConnectionInformation> NetworkSourceCollection;
};

View File

@@ -0,0 +1,61 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <Misc/FrameRate.h>
#include "NDIBroadcastConfiguration.generated.h"
/**
Describes essential properties used for modifying the broadcast configuration of an Sender object
*/
USTRUCT(BlueprintType, Blueprintable, Category = "NDI IO", META = (DisplayName = "NDI Broadcast Configuration"))
struct NDIIO_API FNDIBroadcastConfiguration
{
GENERATED_USTRUCT_BODY()
public:
/** Describes the output frame size while sending video frame over NDI */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Broadcast Settings", META = (DisplayName = "Frame Size"))
FIntPoint FrameSize = FIntPoint(1920, 1080);
/** Represents the desired number of frames (per second) for video to be sent over NDI */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Broadcast Settings", META = (DisplayName = "Frame Rate"))
FFrameRate FrameRate = FFrameRate(60, 1);
public:
/** Constructs a new instance of this object */
FNDIBroadcastConfiguration() = default;
/** Copies an existing instance to this object */
FNDIBroadcastConfiguration(const FNDIBroadcastConfiguration& other);
/** Copies existing instance properties to this object */
FNDIBroadcastConfiguration& operator=(const FNDIBroadcastConfiguration& other);
/** Destructs this object */
virtual ~FNDIBroadcastConfiguration() = default;
/** Compares this object to 'other' and returns a determination of whether they are equal */
bool operator==(const FNDIBroadcastConfiguration& other) const;
/** Compares this object to 'other" and returns a determination of whether they are NOT equal */
bool operator!=(const FNDIBroadcastConfiguration& other) const;
protected:
/** Attempts to serialize this object using an Archive object */
virtual FArchive& Serialize(FArchive& Ar);
private:
/** Operator override for serializing this object to an Archive object */
friend class FArchive& operator<<(FArchive& Ar, FNDIBroadcastConfiguration& Input)
{
return Input.Serialize(Ar);
}
};

View File

@@ -0,0 +1,92 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <NDIIOPluginAPI.h>
#include <Enumerations/NDISourceBandwidth.h>
#include <Serialization/Archive.h>
#include "NDIConnectionInformation.generated.h"
/**
Describes essential properties used for connection objects over NDI
*/
USTRUCT(BlueprintType, Blueprintable, Category = "NDI IO", META = (DisplayName = "NDI Connection Information"))
struct NDIIO_API FNDIConnectionInformation
{
GENERATED_USTRUCT_BODY()
public:
/** A user-friendly name of the source */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Properties", META = (DisplayName = "Source Name"))
FString SourceName = FString("");
/** The machine name of the source */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Properties", META = (DisplayName = "Machine Name"))
FString MachineName = FString("");
/** The stream name of the source */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Properties", META = (DisplayName = "Stream Name"))
FString StreamName = FString("");
/** A location on the network for which this source exists */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Properties", META = (DisplayName = "Url"))
FString Url = FString("");
/** Indicates the current bandwidth mode used for this connection */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Properties", META = (DisplayName = "Bandwidth"))
ENDISourceBandwidth Bandwidth = ENDISourceBandwidth::Highest;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Properties", META = (DisplayName = "Mute Audio"))
bool bMuteAudio = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Properties", META = (DisplayName = "Mute Video"))
bool bMuteVideo = false;
public:
/** Constructs a new instance of this object */
FNDIConnectionInformation() = default;
/** Copies an existing instance to this object */
FNDIConnectionInformation(const FNDIConnectionInformation& other);
/** Copies existing instance properties to this object */
FNDIConnectionInformation& operator=(const FNDIConnectionInformation& other);
/** Destructs this object */
virtual ~FNDIConnectionInformation() = default;
/** Implicit conversion to a base NDI bandwidth value */
operator NDIlib_recv_bandwidth_e() const;
/** Compares this object to 'other' and returns a determination of whether they are equal */
bool operator==(const FNDIConnectionInformation& other) const;
/** Compares this object to 'other" and returns a determination of whether they are NOT equal */
bool operator!=(const FNDIConnectionInformation& other) const;
public:
/** Resets the current parameters to the default property values */
void Reset();
/** Determines whether this object is valid connection information */
bool IsValid() const;
FString GetNDIName() const;
protected:
/** Attempts to serialize this object using an Archive object */
virtual FArchive& Serialize(FArchive& Ar);
private:
/** Operator override for serializing this object to an Archive object */
friend class FArchive& operator<<(FArchive& Ar, FNDIConnectionInformation& Input)
{
return Input.Serialize(Ar);
}
};

View File

@@ -0,0 +1,97 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <NDIIOPluginAPI.h>
#include <Serialization/Archive.h>
#include "NDIReceiverPerformanceData.generated.h"
/**
A structure holding data allowing you to determine the current performance levels of the receiver with the
ability to detect whether frames has been dropped
*/
USTRUCT(BlueprintType, Blueprintable, Category = "NDI IO", META = (DisplayName = "NDI Receiver Performance Data"))
struct NDIIO_API FNDIReceiverPerformanceData
{
GENERATED_USTRUCT_BODY()
public:
/**
The number of audio frames received from the NDI sender
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information", META = (DisplayName = "Audio Frames"))
int64 AudioFrames = 0;
/**
The number of video frames dropped in transit from an NDI sender
*/
UPROPERTY(BlueprintReadonly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Dropped Video Frames"))
int64 DroppedVideoFrames = 0;
/**
The number of audio frames dropped in transit from the NDI sender
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Dropped Audio Frames"))
int64 DroppedAudioFrames = 0;
/**
The number of metadata frames dropped in transit from the NDI sender
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information",
META = (DisplayName = "Dropped Metadata Frames"))
int64 DroppedMetadataFrames = 0;
/**
The number of metadata frames received from the NDI sender
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information", META = (DisplayName = "Metadata Frames"))
int64 MetadataFrames = 0;
/**
The number of video frames received from the NDI sender
*/
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Information", META = (DisplayName = "Video Frames"))
int64 VideoFrames = 0;
public:
/** Constructs a new instance of this object */
FNDIReceiverPerformanceData() = default;
/** Copies an existing instance to this object */
FNDIReceiverPerformanceData(const FNDIReceiverPerformanceData& other);
/** Copies existing instance properties to this object */
FNDIReceiverPerformanceData& operator=(const FNDIReceiverPerformanceData& other);
/** Destructs this object */
virtual ~FNDIReceiverPerformanceData() = default;
/** Compares this object to 'other' and returns a determination of whether they are equal */
bool operator==(const FNDIReceiverPerformanceData& other) const;
/** Compares this object to 'other" and returns a determination of whether they are NOT equal */
bool operator!=(const FNDIReceiverPerformanceData& other) const;
public:
/** Resets the current parameters to the default property values */
void Reset();
protected:
/** Attempts to serialize this object using an Archive object */
virtual FArchive& Serialize(FArchive& Ar);
private:
/** Operator override for serializing this object to an Archive object */
friend class FArchive& operator<<(FArchive& Ar, FNDIReceiverPerformanceData& Input)
{
return Input.Serialize(Ar);
}
};

View File

@@ -0,0 +1,131 @@
/*
Copyright (C) 2024 Vizrt NDI AB. All rights reserved.
This file and its use within a Product is bound by the terms of NDI SDK license that was provided
as part of the NDI SDK. For more information, please review the license and the NDI SDK documentation.
*/
#pragma once
#include <CoreMinimal.h>
#include <FastXml.h>
class NDIXmlElementParser
{
public:
virtual ~NDIXmlElementParser()
{}
// Start parsing this element
virtual bool ProcessOpen(const TCHAR* ElementName, const TCHAR* ElementData)
{
return true;
}
// Parse an attribute of this element
virtual bool ProcessAttribute(const TCHAR* AttributeName, const TCHAR* AttributeValue)
{
return true;
}
// Start parsing a sub-element
virtual TSharedRef<NDIXmlElementParser>* ProcessElement(const TCHAR* ElementName, const TCHAR* ElementData)
{
return nullptr;
}
// Finish parsing this element
virtual bool ProcessClose(const TCHAR* ElementName)
{
return true;
}
};
class NDIXmlElementParser_null : public NDIXmlElementParser
{
public:
};
class NDIXmlParser : public IFastXmlCallback
{
public:
virtual ~NDIXmlParser()
{}
void AddElementParser(FName ElementName, TSharedRef<NDIXmlElementParser> ElementParser)
{
ElementParsers.Add(ElementName, ElementParser);
}
virtual bool ProcessXmlDeclaration(const TCHAR* ElementData, int32 XmlFileLineNumber) override
{
return true;
}
virtual bool ProcessElement(const TCHAR* ElementName, const TCHAR* ElementData, int32 XmlFileLineNumber) override
{
if(ElementParserStack.Num() == 0)
{
TSharedRef<NDIXmlElementParser>* ParserPtr = ElementParsers.Find(ElementName);
if(ParserPtr == nullptr)
ParserPtr = &NullParser;
ElementParserStack.Push(*ParserPtr);
return (*ParserPtr)->ProcessOpen(ElementName, ElementData);
}
else
{
TSharedRef<NDIXmlElementParser>* ParserPtr = ElementParserStack.Last()->ProcessElement(ElementName, ElementData);
if(ParserPtr == nullptr)
ParserPtr = &NullParser;
ElementParserStack.Push(*ParserPtr);
return (*ParserPtr)->ProcessOpen(ElementName, ElementData);
}
//return false;
}
virtual bool ProcessAttribute(const TCHAR* AttributeName, const TCHAR* AttributeValue) override
{
if(ElementParserStack.Num() == 0)
{
return true;
}
else
{
return ElementParserStack.Last()->ProcessAttribute(AttributeName, AttributeValue);
}
//return false;
}
virtual bool ProcessClose(const TCHAR* ElementName) override
{
if(ElementParserStack.Num() == 0)
{
return true;
}
else
{
auto Parser = ElementParserStack.Pop();
return Parser->ProcessClose(ElementName);
}
//return false;
}
virtual bool ProcessComment(const TCHAR* Comment) override
{
return true;
}
protected:
TMap<FName, TSharedRef<NDIXmlElementParser> > ElementParsers;
TArray<TSharedRef<NDIXmlElementParser> > ElementParserStack;
TSharedRef<NDIXmlElementParser> NullParser { MakeShareable(new NDIXmlElementParser_null()) };
};