Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

517 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#define MSWindows 1
#define AJA_WINDOWS 1
#define AJA_NO_AUTOIMPORT 1
#include "AJALib.h"
#include "GPUTextureTransfer.h"
#include "AutoDetectChannel.h"
#include "DeviceScanner.h"
#include "InputChannel.h"
#include "Misc/Timecode.h"
#include "OutputChannel.h"
#include "SyncChannel.h"
#include "TimecodeChannel.h"
#include "VideoFormats.h"
#include "Helpers.h"
#include <cwchar>
namespace AJA
{
/*
* Timecode
*/
FTimecode::FTimecode()
: Hours(0)
, Minutes(0)
, Seconds(0)
, Frames(0)
, bDropFrame(false)
{}
bool FTimecode::operator== (const FTimecode& Other) const
{
return Other.Hours == Hours
&& Other.Minutes == Minutes
&& Other.Seconds == Seconds
&& Other.Frames == Frames;
}
/*
* String Helpers
*/
// unicode to wide
std::wstring s2ws(const std::string& str)
{
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0) + 1;
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
// wide to unicode
std::string ws2s(const std::wstring& wstr)
{
int size_needed = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), 0, 0, 0, 0);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), &strTo[0], size_needed, 0, 0);
return strTo;
}
/* AJAVideoFrameFormats implementation
*****************************************************************************/
AJADeviceScanner::AJADeviceScanner()
{
Scanner = new AJA::Private::DeviceScanner();
}
AJADeviceScanner::~AJADeviceScanner()
{
delete Scanner;
}
int32_t AJADeviceScanner::GetNumDevices() const
{
return Scanner->GetNumDevices();
}
bool AJADeviceScanner::GetDeviceTextId(int32_t InDeviceIndex, AJADeviceScanner::FormatedTextType& OutTextId) const
{
return Scanner->GetDeviceTextId(InDeviceIndex, OutTextId);
}
bool AJADeviceScanner::GetDeviceInfo(int32_t InDeviceIndex, DeviceInfo& OutDeviceInfo) const
{
return Scanner->GetDeviceInfo(InDeviceIndex, OutDeviceInfo);
}
/* AJAVideoFrameFormats implementation
*****************************************************************************/
AJAVideoFormats::VideoFormatDescriptor::VideoFormatDescriptor()
: bIsValid(false)
{}
AJAVideoFormats::AJAVideoFormats(int32_t InDeviceId)
{
Formats = new AJA::Private::VideoFormatsScanner(InDeviceId);
}
AJAVideoFormats::~AJAVideoFormats()
{
delete Formats;
}
int32_t AJAVideoFormats::GetNumSupportedFormat() const
{
return (int32_t)Formats->FormatList.size();
}
AJAVideoFormats::VideoFormatDescriptor AJAVideoFormats::GetSupportedFormat(int32_t InIndex) const
{
if (InIndex < Formats->FormatList.size())
{
return Formats->FormatList[InIndex];
}
return AJAVideoFormats::VideoFormatDescriptor();
}
AJAVideoFormats::VideoFormatDescriptor AJAVideoFormats::GetVideoFormat(FAJAVideoFormat InVideoFormatIndex)
{
return Private::VideoFormatsScanner::GetVideoFormat(InVideoFormatIndex);
}
std::string AJAVideoFormats::VideoFormatToString(FAJAVideoFormat InVideoFormatIndex)
{
NTV2VideoFormat NativeVideoFormat;
if (!AJA::Private::Helpers::TryVideoFormatIndexToNTV2VideoFormat(InVideoFormatIndex, NativeVideoFormat))
{
return "";
}
return NTV2VideoFormatToString(NativeVideoFormat);
}
bool AJAVideoFormats::VideoFormatToString(FAJAVideoFormat InVideoFormatIndex, char* OutCStr, uint32_t MaxLen)
{
if (!OutCStr || (MaxLen < 1))
{
return false;
}
std::string VideoFormatStdStr = VideoFormatToString(InVideoFormatIndex);
if (!VideoFormatStdStr.length() || (VideoFormatStdStr.length() >= MaxLen))
{
OutCStr[0] = '\0';
return false;
}
return !strcpy_s(OutCStr, MaxLen, VideoFormatStdStr.c_str());
}
/* IAJASyncChannelCallbackInterface implementation
*****************************************************************************/
IAJASyncChannelCallbackInterface::IAJASyncChannelCallbackInterface()
{}
IAJASyncChannelCallbackInterface::~IAJASyncChannelCallbackInterface()
{}
/* AJASyncChannelOptions implementation
*****************************************************************************/
AJASyncChannelOptions::AJASyncChannelOptions(const TCHAR* DebugName)
: CallbackInterface(nullptr)
, TransportType(ETransportType::TT_SdiSingle)
, ChannelIndex(-1)
, TimecodeFormat(AJA::ETimecodeFormat::TCF_LTC)
, bOutput(false)
, bWaitForFrameToBeReady(false)
, bAutoDetectFormat(false)
{
}
/* AJASyncChannel implementation
*****************************************************************************/
AJASyncChannel::AJASyncChannel()
{
Channel = new Private::SyncChannel();
}
bool AJASyncChannel::Initialize(const AJADeviceOptions& InDevice, const AJASyncChannelOptions& InOption)
{
return Channel->Initialize(InDevice, InOption);
}
void AJASyncChannel::Uninitialize()
{
Channel->Uninitialize();
}
AJASyncChannel::~AJASyncChannel()
{
delete Channel;
}
bool AJASyncChannel::WaitForSync() const
{
return Channel ? Channel->WaitForSync() : false;
}
bool AJASyncChannel::GetTimecode(FTimecode& OutTimecode) const
{
return Channel ? Channel->GetTimecode(OutTimecode) : false;
}
bool AJASyncChannel::GetSyncCount(uint32_t& OutCount) const
{
return Channel ? Channel->GetSyncCount(OutCount) : false;
}
bool AJASyncChannel::GetVideoFormat(FAJAVideoFormat& OutVideoFormat)
{
if (!Channel)
{
return false;
}
NTV2VideoFormat NativeVideoFormat;
const bool bValidFormat = Channel->GetVideoFormat(NativeVideoFormat);
OutVideoFormat = FAJAVideoFormat(NativeVideoFormat);
return bValidFormat;
}
/* IAJATimecodeChannelCallbackInterface implementation
*****************************************************************************/
IAJATimecodeChannelCallbackInterface::IAJATimecodeChannelCallbackInterface()
{}
IAJATimecodeChannelCallbackInterface::~IAJATimecodeChannelCallbackInterface()
{}
/* AJATimecodeChannelOptions implementation
*****************************************************************************/
AJATimecodeChannelOptions::AJATimecodeChannelOptions(const TCHAR* DebugName)
: CallbackInterface(nullptr)
, bUseDedicatedPin(false)
, bReadTimecodeFromReferenceIn(false)
, LTCSourceIndex(1)
, LTCFrameRateNumerator(0)
, LTCFrameRateDenominator(1)
, TransportType(ETransportType::TT_SdiSingle)
, ChannelIndex(-1)
, TimecodeFormat(AJA::ETimecodeFormat::TCF_LTC)
, bAutoDetectFormat(false)
{
}
/* AJASyncChannel implementation
*****************************************************************************/
AJATimecodeChannel::AJATimecodeChannel()
{
Channel = new Private::TimecodeChannel();
}
bool AJATimecodeChannel::Initialize(const AJADeviceOptions& InDevice, const AJATimecodeChannelOptions& InOption)
{
return Channel->Initialize(InDevice, InOption);
}
void AJATimecodeChannel::Uninitialize()
{
Channel->Uninitialize();
}
AJATimecodeChannel::~AJATimecodeChannel()
{
delete Channel;
}
bool AJATimecodeChannel::GetTimecode(FTimecode& OutTimecode) const
{
return Channel ? Channel->GetTimecode(OutTimecode) : false;
}
/* AJAInputFrameData implementation
*****************************************************************************/
AJAInputFrameData::AJAInputFrameData()
:FramesDropped(0)
{}
/* AJAOutputFrameData implementation
*****************************************************************************/
AJAOutputFrameData::AJAOutputFrameData()
: FramesLost(0)
{}
/* AJAAncillaryFrameData implementation
*****************************************************************************/
AJAAncillaryFrameData::AJAAncillaryFrameData()
{
memset(this, 0, sizeof(AJAAncillaryFrameData));
}
/* AJAAudioFrameData implementation
*****************************************************************************/
AJAAudioFrameData::AJAAudioFrameData()
{
memset(this, 0, sizeof(AJAAudioFrameData));
}
/* AJAVideoFrameData implementation
*****************************************************************************/
AJAVideoFrameData::AJAVideoFrameData()
{
memset(this, 0, sizeof(AJAVideoFrameData));
}
/* AJARequestInputBufferData implementation
*****************************************************************************/
AJARequestInputBufferData::AJARequestInputBufferData()
{
memset(this, 0, sizeof(AJARequestInputBufferData));
}
/* AJARequestedInputBufferData implementation
*****************************************************************************/
AJARequestedInputBufferData::AJARequestedInputBufferData()
{
memset(this, 0, sizeof(AJARequestedInputBufferData));
}
/* IAJAInputOutputChannelCallbackInterface implementation
*****************************************************************************/
IAJAInputOutputChannelCallbackInterface::IAJAInputOutputChannelCallbackInterface()
{
}
/* AJAInputOutputChannelOptions implementation
*****************************************************************************/
AJAInputOutputChannelOptions::AJAInputOutputChannelOptions(const TCHAR* DebugName, uint32_t InChannelIndex)
: CallbackInterface(nullptr)
, NumberOfAudioChannel(8)
, TransportType(ETransportType::TT_SdiSingle)
, ChannelIndex(InChannelIndex)
, SynchronizeChannelIndex(InChannelIndex)
, KeyChannelIndex(InChannelIndex)
, OutputNumberOfBuffers(2)
, VideoFormatIndex(NTV2VideoFormat::NTV2_FORMAT_1080p_3000)
, PixelFormat(AJA::EPixelFormat::PF_8BIT_YCBCR)
, TimecodeFormat(AJA::ETimecodeFormat::TCF_LTC)
, OutputReferenceType(EAJAReferenceType::EAJA_REFERENCETYPE_FREERUN)
, Options(0)
{
bUseVideo = true;
bDisplayWarningIfDropFrames = true;
}
/* AJAInputChannel implementation
*****************************************************************************/
AJAInputChannel::AJAInputChannel()
{
Channel = new Private::InputChannel();
}
bool AJAInputChannel::Initialize(const AJADeviceOptions& InDevice, const AJAInputOutputChannelOptions& Options)
{
return Channel->Initialize(InDevice, Options);
}
void AJAInputChannel::Uninitialize()
{
Channel->Uninitialize();
}
AJAInputChannel::~AJAInputChannel()
{
delete Channel;
}
uint32_t AJAInputChannel::GetFrameDropCount() const
{
return Channel ? Channel->GetCurrentAutoCirculateStatus().GetDroppedFrameCount() : 0;
}
const AJAInputOutputChannelOptions& AJAInputChannel::GetOptions() const
{
static AJAInputOutputChannelOptions InvalidOptions(TEXT("InvalidOptions"), 0);
return Channel ? Channel->GetOptions() : InvalidOptions;
}
const AJADeviceOptions& AJAInputChannel::GetDeviceOptions() const
{
static AJADeviceOptions InvalidOptions(0);
return Channel ? Channel->GetDeviceOptions() : InvalidOptions;
}
/* AJAOutputFrameBufferData implementation
*****************************************************************************/
const uint32_t AJAOutputFrameBufferData::InvalidFrameIdentifier = static_cast<uint32_t>(-1);
AJAOutputFrameBufferData::AJAOutputFrameBufferData()
: FrameIdentifier(InvalidFrameIdentifier)
, bEvenFrame(false)
{
}
/* AJAOutputChannel implementation
*****************************************************************************/
AJAOutputChannel::AJAOutputChannel()
{
Channel = new Private::OutputChannel();
}
bool AJAOutputChannel::Initialize(const AJADeviceOptions& InDevice, const AJAInputOutputChannelOptions& Options)
{
return Channel->Initialize(InDevice, Options);
}
void AJAOutputChannel::Uninitialize(TPromise<void> Promise)
{
Channel->Uninitialize(MoveTemp(Promise));
}
AJAOutputChannel::~AJAOutputChannel()
{
delete Channel;
}
bool AJAOutputChannel::SetAncillaryFrameData(const AJAOutputFrameBufferData& InFrameData, uint8_t* AncillaryBuffer, uint32_t AncillaryBufferSize)
{
return Channel ? Channel->SetAncillaryFrameData(InFrameData, AncillaryBuffer, AncillaryBufferSize) : false;
}
bool AJAOutputChannel::SetAudioFrameData(const AJAOutputFrameBufferData& InFrameData, uint8_t* AudioBuffer, uint32_t AudioBufferSize)
{
return Channel ? Channel->SetAudioFrameData(InFrameData, AudioBuffer, AudioBufferSize) : false;
}
bool AJAOutputChannel::SetVideoFrameData(const AJAOutputFrameBufferData& InFrameData, uint8_t* VideoBuffer, uint32_t VideoBufferSize)
{
return Channel ? Channel->SetVideoFrameData(InFrameData, VideoBuffer, VideoBufferSize) : false;
}
bool AJAOutputChannel::SetVideoFrameData(const AJAOutputFrameBufferData& InFrameData, FRHITexture* RHITexture)
{
return Channel ? Channel->SetVideoFrameData(InFrameData, RHITexture) : false;
}
bool AJAOutputChannel::DMAWriteAudio(const uint8* Buffer, int32 BufferSize)
{
return Channel ? Channel->DMAWriteAudio(Buffer, BufferSize) : false;
}
bool AJAOutputChannel::ShouldCaptureThisFrame(::FTimecode Timecode, uint32 SourceFrameNumber)
{
return Channel ? Channel->ShouldCaptureThisFrame(Timecode, SourceFrameNumber) : false;
}
bool AJAOutputChannel::GetOutputDimension(uint32_t& OutWidth, uint32_t& OutHeight) const
{
return Channel ? Channel->GetOutputDimension(OutWidth, OutHeight) : false;
}
int32_t AJAOutputChannel::GetNumAudioSamplesPerFrame(const AJAOutputFrameBufferData& InFrameData) const
{
return Channel ? Channel->GetNumAudioSamplesPerFrame(InFrameData) : 0;
}
/* AJAAutoDetectChannel implementation
*****************************************************************************/
IAJAAutoDetectCallbackInterface::IAJAAutoDetectCallbackInterface()
{
}
IAJAAutoDetectCallbackInterface::~IAJAAutoDetectCallbackInterface()
{
}
AJAAutoDetectChannel::AutoDetectChannelData::AutoDetectChannelData()
: DetectedVideoFormat(0)
, ChannelIndex(0)
{}
AJAAutoDetectChannel::AJAAutoDetectChannel()
{
AutoChannel = new AJA::Private::AutoDetectChannel();
}
AJAAutoDetectChannel::~AJAAutoDetectChannel()
{
delete AutoChannel;
}
bool AJAAutoDetectChannel::Initialize(IAJAAutoDetectCallbackInterface* InCallbackInterface)
{
return AutoChannel->Initialize(InCallbackInterface);
}
void AJAAutoDetectChannel::Uninitialize()
{
AutoChannel->Uninitialize();
}
int32_t AJAAutoDetectChannel::GetNumOfChannelData() const
{
return (int32_t)AutoChannel->GetFoundChannels().size();
}
AJAAutoDetectChannel::AutoDetectChannelData AJAAutoDetectChannel::GetChannelData(int32_t InIndex) const
{
std::vector<AJAAutoDetectChannel::AutoDetectChannelData> FoundChannel = AutoChannel->GetFoundChannels();
if (InIndex < FoundChannel.size() && InIndex >= 0)
{
return FoundChannel[InIndex];
}
return AJAAutoDetectChannel::AutoDetectChannelData();
}
}