Hello, we are trying to use the NdiMedia plugin to implment Ndi sending feature by ourselves. We added a class to NdiMedia plugin, which is called UNdiMediaSender. We managed to initialize NDI and create a sender instance inside the UNdiMediaSender class. However, when we try to send video frame using NDIlib_send_send_video_v2 or NDIlib_send_send_video_async_v2 method, UE4 crashed.
I’ve read another issue in which you mentioned that the sending feature is on the way, which is a cool news. At this moment, we want to know how to fix this crash problem. Thank you very much.
Our code is something like this: ( Sorry for the ugly layout )
Please search “Crash Happens Here” to locate the crash point.
NdiMediaSender.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "NdiMediaSender.generated.h"
UCLASS(BlueprintType)
class NDIMEDIA_API UNdiMediaSender : public UObject
{
GENERATED_BODY()
public:
UNdiMediaSender();
public:
UFUNCTION(BlueprintCallable, Category = NDI)
void Initialize();
UFUNCTION(BlueprintCallable, Category = NDI)
void Tick();
public:
//~ UObject interface
virtual void BeginDestroy() override;
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
};
NdiMediaSender.cpp
#include "NdiMediaSender.h"
#include "Ndi.h"
#include "NdiMediaPrivate.h"
static std::atomic exit_loop(false);
static void sigint_handler(int)
{
exit_loop = true;
}
NDIlib_send_create_t NDI_send_create_desc;
NDIlib_send_instance_t pNDI_send;
NDIlib_video_frame_v2_t NDI_video_frame;
const int xres = 720;
const int yres = 480;
UNdiMediaSender::UNdiMediaSender()
{
}
void UNdiMediaSender::Initialize()
{
if (!NDIlib_initialize())
{
UE_LOG(LogTemp, Warning, TEXT("Can not run NDI"));
return;
}
UE_LOG(LogTemp, Warning, TEXT("NDI library initialized"));
// Catch interrupt so that we can shut down gracefully
signal(SIGINT, sigint_handler);
// Create an NDI source that is called "My Video" and is clocked to the video.
NDI_send_create_desc.p_ndi_name = "My Video";
// We create the NDI sender
pNDI_send = NDIlib_send_create(&NDI_send_create_desc);
if (!pNDI_send) return;
UE_LOG(LogTemp, Warning, TEXT("NDI sender created"));
// We are going to create a 1920x1080 interlaced frame at 29.97Hz.
NDI_video_frame.xres = xres;
NDI_video_frame.yres = yres;
NDI_video_frame.FourCC = NDIlib_FourCC_type_BGRX;
NDI_video_frame.frame_format_type = NDIlib_frame_format_type_interleaved;
NDI_video_frame.p_data = (uint8_t*)malloc(xres * yres * 4);
NDI_video_frame.line_stride_in_bytes = xres * 4;
}
void UNdiMediaSender::Tick()
{
UE_LOG(LogTemp, Warning, TEXT("Tick"));
// Fill in the buffer. It is likely that you would do something much smarter than this.
memset((void*)NDI_video_frame.p_data, 255, xres * yres * 4);
UE_LOG(LogTemp, Warning, TEXT("memset done"));
// Crash Happens Here !
NDIlib_send_send_video_async_v2(pNDI_send, &NDI_video_frame);
UE_LOG(LogTemp, Warning, TEXT("video sent"));
}
/* UObject interface
*****************************************************************************/
void UNdiMediaSender::BeginDestroy()
{
Super::BeginDestroy();
// Free the video frame
free(NDI_video_frame.p_data);
// Destroy the NDI sender
NDIlib_send_destroy(pNDI_send);
// Not required, but nice
NDIlib_destroy();
}
#if WITH_EDITOR
void UNdiMediaSender::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
}
#endif //WITH_EDITOR