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,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;
};