Skip to content

Commit

Permalink
Merge pull request #712 from MediaArea/format
Browse files Browse the repository at this point in the history
DeckLink: Allow selection of video/audio source and format
  • Loading branch information
dericed authored Jul 12, 2023
2 parents 7b527fb + 53490ea commit 174653c
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 15 deletions.
28 changes: 28 additions & 0 deletions Source/CLI/CLI_Help.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,34 @@ return_value Help(ostream& Out, const char* Name, bool Full)
" Base name of files storing buggy frames per take\n"
" Default is output file name.\n"
"\n"
#ifdef ENABLE_DECKLINK
" --decklink-video-mode <mode>\n"
" Select DeckLink video mode.\n"
" value may be:\n"
" ntsc Set video mode to NTSC (default).\n"
" pal Set video mode to PAL.\n"
"\n"
" --decklink-video-source <source>\n"
" Select DeckLink video source.\n"
" value may be:\n"
" sdi Set video source to SDI.\n"
" hdmi Set video source to HDMI.\n"
" optical Set video source to optical SDI.\n"
" component Set video source to component input.\n"
" composite Set video source to composite input (default).\n"
" s_video Set video source to S-Video input.\n"
"\n"
" --decklink-audio-source <source>\n"
" Select DeckLink audio source.\n"
" value may be:\n"
" embedded Set audio source to embedded inpit.\n"
" aes_ebu Set audio source to AES-EBU input.\n"
" analog Set audio source to analog input (default).\n"
" analog_xlr Set audio source to analog(XLR) input.\n"
" analog_rca Set audio source to analog(RCA) input.\n"
" microphone Set audio source to microphone input.\n"
"\n"
#endif
"If no output file name is provided, XML output is displayed on console output."
"\n"
<< endl;
Expand Down
81 changes: 81 additions & 0 deletions Source/CLI/CommandLine_Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,87 @@ return_value Parse(Core &C, int argc, const char* argv_ansi[], const MediaInfoNa
Control_Port = argv_ansi[i];
}
#endif
#ifdef ENABLE_DECKLINK
else if (!strcmp(argv_ansi[i], "--decklink-video-mode"))
{
if (++i >= argc)
{
if (C.Err)
*C.Err << "Error: missing video mode after " << argv_ansi[i - 1] << ".\n";
ReturnValue = ReturnValue_ERROR;
continue;
}
if (!strcmp(argv_ansi[i], "ntsc"))
DeckLinkVideoMode = 0;
else if (!strcmp(argv_ansi[i], "pal"))
DeckLinkVideoMode = 1;
else
{
if (C.Err)
*C.Err << "Error: unknown decklink video mode " << argv_ansi[i] << ".\n";
ReturnValue = ReturnValue_ERROR;
continue;
}
}
else if (!strcmp(argv_ansi[i], "--decklink-video-source"))
{
if (++i >= argc)
{
if (C.Err)
*C.Err << "Error: missing video source after " << argv_ansi[i - 1] << ".\n";
ReturnValue = ReturnValue_ERROR;
continue;
}
if (!strcmp(argv_ansi[i], "sdi"))
DeckLinkVideoSource = 0;
else if (!strcmp(argv_ansi[i], "hdmi"))
DeckLinkVideoSource = 1;
else if (!strcmp(argv_ansi[i], "optical"))
DeckLinkVideoSource = 2;
else if (!strcmp(argv_ansi[i], "component"))
DeckLinkVideoSource = 3;
else if (!strcmp(argv_ansi[i], "composite"))
DeckLinkVideoSource = 4;
else if (!strcmp(argv_ansi[i], "s_video"))
DeckLinkVideoSource = 5;
else
{
if (C.Err)
*C.Err << "Error: unknown decklink video source " << argv_ansi[i] << ".\n";
ReturnValue = ReturnValue_ERROR;
continue;
}
}
else if (!strcmp(argv_ansi[i], "--decklink-audio-source"))
{
if (++i >= argc)
{
if (C.Err)
*C.Err << "Error: missing audio source after " << argv_ansi[i - 1] << ".\n";
ReturnValue = ReturnValue_ERROR;
continue;
}
if (!strcmp(argv_ansi[i], "embedded"))
DeckLinkAudioSource = 0;
else if (!strcmp(argv_ansi[i], "aes_ebu"))
DeckLinkAudioSource = 1;
else if (!strcmp(argv_ansi[i], "analog"))
DeckLinkAudioSource = 2;
else if (!strcmp(argv_ansi[i], "analog_xlr"))
DeckLinkAudioSource = 3;
else if (!strcmp(argv_ansi[i], "analog_rca"))
DeckLinkAudioSource = 4;
else if (!strcmp(argv_ansi[i], "microphone"))
DeckLinkAudioSource = 5;
else
{
if (C.Err)
*C.Err << "Error: unknown decklink audio source " << argv_ansi[i] << ".\n";
ReturnValue = ReturnValue_ERROR;
continue;
}
}
#endif
else if (!strcmp(argv_ansi[i], "--device") || !strcmp(argv_ansi[i], "-device"))
{
if (++i >= argc)
Expand Down
77 changes: 66 additions & 11 deletions Source/Common/DecklinkWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,32 @@
using namespace std;

//---------------------------------------------------------------------------
struct frame
static uint32_t decklink_video_modes[Decklink_Video_Mode_Max] =
{
size_t Size;
uint8_t* Data;
bmdModeNTSC,
bmdModePAL
};

//---------------------------------------------------------------------------
static uint32_t decklink_video_sources[Decklink_Video_Source_Max] =
{
bmdVideoConnectionSDI,
bmdVideoConnectionHDMI,
bmdVideoConnectionOpticalSDI,
bmdVideoConnectionComponent,
bmdVideoConnectionComposite,
bmdVideoConnectionSVideo
};

//---------------------------------------------------------------------------
static uint32_t decklink_audio_sources[Decklink_Audio_Source_Max] =
{
bmdAudioConnectionEmbedded,
bmdAudioConnectionAESEBU,
bmdAudioConnectionAnalog,
bmdAudioConnectionAnalogXLR,
bmdAudioConnectionAnalogRCA,
bmdAudioConnectionMicrophone
};

typedef CFStringRef PlatformStr;
Expand Down Expand Up @@ -196,8 +218,12 @@ void DecklinkWrapper::Init()
}

//---------------------------------------------------------------------------
DecklinkWrapper::DecklinkWrapper(size_t DeviceIndex, ControllerBaseWrapper* Controller, bool Native) :
Controller(Controller)
DecklinkWrapper::DecklinkWrapper(size_t DeviceIndex,
decklink_video_mode Mode,
decklink_video_source VideoSrc,
decklink_audio_source AudioSrc,
ControllerBaseWrapper* Controller,
bool Native) : Controller(Controller)
{
IDeckLinkIterator* DeckLinkIterator = CreateDeckLinkIteratorInstance();
if (!DeckLinkIterator)
Expand All @@ -217,6 +243,10 @@ DecklinkWrapper::DecklinkWrapper(size_t DeviceIndex, ControllerBaseWrapper* Cont
if (!DeckLinkDevice)
throw error("Device not found.");

DeckLinkVideoMode = decklink_video_modes[Mode < Decklink_Video_Mode_Max ? Mode : Decklink_Video_Mode_NTSC];
DeckLinkVideoSource = decklink_video_sources[VideoSrc < Decklink_Video_Source_Max ? VideoSrc : Decklink_Video_Source_Composite];
DeckLinkAudioSource = decklink_audio_sources[AudioSrc < Decklink_Audio_Source_Max ? AudioSrc : Decklink_Audio_Source_Analog];

if (!Controller && Native)
{
BMDDeckControlError Error;
Expand Down Expand Up @@ -258,8 +288,12 @@ DecklinkWrapper::DecklinkWrapper(size_t DeviceIndex, ControllerBaseWrapper* Cont
}

//---------------------------------------------------------------------------
DecklinkWrapper::DecklinkWrapper(string DeviceID, ControllerBaseWrapper* Controller, bool Native) :
Controller(Controller)
DecklinkWrapper::DecklinkWrapper(string DeviceID,
decklink_video_mode Mode,
decklink_video_source VideoSrc,
decklink_audio_source AudioSrc,
ControllerBaseWrapper* Controller,
bool Native) : Controller(Controller)
{
IDeckLinkIterator* DeckLinkIterator = CreateDeckLinkIteratorInstance();
if (!DeckLinkIterator)
Expand Down Expand Up @@ -291,6 +325,10 @@ DecklinkWrapper::DecklinkWrapper(string DeviceID, ControllerBaseWrapper* Control
if (!DeckLinkDevice)
throw error("Device not found.");

DeckLinkVideoMode = decklink_video_modes[Mode < Decklink_Video_Mode_Max ? Mode : Decklink_Video_Mode_NTSC];
DeckLinkVideoSource = decklink_video_sources[VideoSrc < Decklink_Video_Source_Max ? VideoSrc : Decklink_Video_Source_Composite];
DeckLinkAudioSource = decklink_audio_sources[AudioSrc < Decklink_Audio_Source_Max ? AudioSrc : Decklink_Audio_Source_Analog];

if (!Controller && Native)
{
BMDDeckControlError Error;
Expand Down Expand Up @@ -489,6 +527,20 @@ void DecklinkWrapper::CreateCaptureSession(FileWrapper* Wrapper_)
if (DeckLinkDevice->QueryInterface(IID_IDeckLinkInput, (void **)&DeckLinkInput) != S_OK)
return;

bool VideoModeIsSupported = false;
if (DeckLinkInput->DoesSupportVideoMode(DeckLinkVideoSource,
DeckLinkVideoMode,
bmdFormat10BitYUV,
bmdNoVideoInputConversion,
bmdVideoInputFlagDefault,
NULL,
&VideoModeIsSupported) != S_OK || !VideoModeIsSupported)
{
DeckLinkInput->Release();
DeckLinkInput=nullptr;
return;
}

if (DeckLinkDevice->QueryInterface(IID_IDeckLinkConfiguration, (void **)&DeckLinkConfiguration) != S_OK)
{
DeckLinkInput->Release();
Expand All @@ -497,8 +549,8 @@ void DecklinkWrapper::CreateCaptureSession(FileWrapper* Wrapper_)
return;
}

if (DeckLinkConfiguration->SetInt(bmdDeckLinkConfigVideoInputConnection, bmdVideoConnectionComposite) != S_OK ||
DeckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioInputConnection, bmdAudioConnectionAnalog) != S_OK)
if (DeckLinkConfiguration->SetInt(bmdDeckLinkConfigVideoInputConnection, DeckLinkVideoSource) != S_OK ||
DeckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioInputConnection, DeckLinkAudioSource) != S_OK)
{
DeckLinkConfiguration->Release();
DeckLinkConfiguration=nullptr;
Expand All @@ -510,12 +562,15 @@ void DecklinkWrapper::CreateCaptureSession(FileWrapper* Wrapper_)
if (Merge_OutputFileName)
{
Output = ofstream(Merge_OutputFileName, ios_base::binary | ios_base::trunc);
MatroskaWriter = new matroska_writer(&Output, 720, 486, 30000, 1001, false);
uint32_t Lines = DeckLinkVideoMode == bmdModeNTSC ? 486 : 576;
uint32_t Num = DeckLinkVideoMode == bmdModeNTSC ? 30000 : 25;
uint32_t Den = DeckLinkVideoMode == bmdModeNTSC ? 1001 : 1;
MatroskaWriter = new matroska_writer(&Output, 720, Lines, Num, Den, false);
}

DeckLinkCaptureDelegate = new CaptureDelegate(MatroskaWriter);

if (DeckLinkInput->EnableVideoInput(bmdModeNTSC, bmdFormat10BitYUV, bmdVideoInputFlagDefault) != S_OK ||
if (DeckLinkInput->EnableVideoInput(DeckLinkVideoMode, bmdFormat10BitYUV, bmdVideoInputFlagDefault) != S_OK ||
DeckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, 2) != S_OK ||
DeckLinkInput->SetCallback(DeckLinkCaptureDelegate) != S_OK)
{
Expand Down
49 changes: 47 additions & 2 deletions Source/Common/DecklinkWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,36 @@
#include "Common/ProcessFileWrapper.h"
#include "Common/Output_Mkv.h"

//***************************************************************************
// Types
//***************************************************************************

enum decklink_video_mode {
Decklink_Video_Mode_NTSC,
Decklink_Video_Mode_PAL,
Decklink_Video_Mode_Max
};

enum decklink_video_source {
Decklink_Video_Source_SDI,
Decklink_Video_Source_HDMI,
Decklink_Video_Source_Optical,
Decklink_Video_Source_Component,
Decklink_Video_Source_Composite,
Decklink_Video_Source_SVideo,
Decklink_Video_Source_Max
};

enum decklink_audio_source {
Decklink_Audio_Source_Embedded,
Decklink_Audio_Source_AESEBU,
Decklink_Audio_Source_Analog,
Decklink_Audio_Source_AnalogXLR,
Decklink_Audio_Source_AnalogRCA,
Decklink_Audio_Source_Microphone,
Decklink_Audio_Source_Max
};

//***************************************************************************
// Class DecklinkWrapper
//***************************************************************************
Expand Down Expand Up @@ -78,8 +108,18 @@ class DecklinkWrapper : public BaseWrapper {
};

// Constructor/Destructor
DecklinkWrapper(std::size_t DeviceIndex, ControllerBaseWrapper* Controller = nullptr, bool Native = false);
DecklinkWrapper(std::string DeviceID, ControllerBaseWrapper* Controller = nullptr, bool Native = false);
DecklinkWrapper(std::size_t DeviceIndex,
decklink_video_mode Mode = Decklink_Video_Mode_NTSC,
decklink_video_source VideoSrc = Decklink_Video_Source_Composite,
decklink_audio_source AudioSrc = Decklink_Audio_Source_Analog,
ControllerBaseWrapper* Controller = nullptr,
bool Native = false);
DecklinkWrapper(std::string DeviceID,
decklink_video_mode Mode = Decklink_Video_Mode_NTSC,
decklink_video_source VideoSrc = Decklink_Video_Source_Composite,
decklink_audio_source AudioSrc = Decklink_Audio_Source_Analog,
ControllerBaseWrapper* Controller = nullptr,
bool Native = false);
~DecklinkWrapper();

// Functions
Expand Down Expand Up @@ -109,6 +149,11 @@ class DecklinkWrapper : public BaseWrapper {
CaptureDelegate* DeckLinkCaptureDelegate = nullptr;
StatusDelegate* DeckLinkStatusDelegate = nullptr;

//Config
uint32_t DeckLinkVideoMode;
uint32_t DeckLinkVideoSource;
uint32_t DeckLinkAudioSource;

// Control
ControllerBaseWrapper* Controller = nullptr;
IDeckLinkDeckControl* DeckLinkDeckControl = nullptr;
Expand Down
5 changes: 5 additions & 0 deletions Source/Common/Merge.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ extern const char* Merge_OutputFileName;
#ifdef ENABLE_SONY9PIN
extern const char* Control_Port;
#endif
#ifdef ENABLE_DECKLINK
extern uint8_t DeckLinkVideoMode;
extern uint8_t DeckLinkVideoSource;
extern uint8_t DeckLinkAudioSource;
#endif
extern size_t Merge_Rewind_Count;
extern uint8_t MergeInfo_Format;
extern uint8_t Verbosity;
Expand Down
17 changes: 15 additions & 2 deletions Source/Common/ProcessFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ const char* Control_Port = nullptr;
#endif
#ifdef ENABLE_DECKLINK
bool DeckLinkNativeControl = false;
uint8_t DeckLinkVideoMode = (uint8_t)Decklink_Video_Mode_NTSC;
uint8_t DeckLinkVideoSource = (uint8_t)Decklink_Video_Source_Composite;
uint8_t DeckLinkAudioSource = (uint8_t)Decklink_Audio_Source_Analog;
#endif
bool InControl = false;
string Device = "";
Expand Down Expand Up @@ -254,9 +257,19 @@ void file::Parse(const String& FileName)
#endif
#ifdef ENABLE_DECKLINK
else if ((Device_Pos-=Device_Offset) < (Device_Offset=DecklinkWrapper::GetDeviceCount()))
try { Capture = new DecklinkWrapper(Device_Pos, Controller, DeckLinkNativeControl); } catch(...) {}
try { Capture = new DecklinkWrapper(Device_Pos,
(decklink_video_mode)DeckLinkVideoMode,
(decklink_video_source)DeckLinkVideoSource,
(decklink_audio_source)DeckLinkAudioSource,
Controller,
DeckLinkNativeControl); } catch(...) {}
else if (DecklinkWrapper::GetDeviceIndex(Device) != (size_t)-1)
try { Capture = new DecklinkWrapper(Device, Controller, DeckLinkNativeControl); } catch(...) {}
try { Capture = new DecklinkWrapper(Device,
(decklink_video_mode)DeckLinkVideoMode,
(decklink_video_source)DeckLinkVideoSource,
(decklink_audio_source)DeckLinkAudioSource,
Controller,
DeckLinkNativeControl); } catch(...) {}
#endif
#ifdef ENABLE_LNX1394
else if ((Device_Pos-=Device_Offset) < (Device_Offset=LinuxWrapper::GetDeviceCount()))
Expand Down

0 comments on commit 174653c

Please sign in to comment.