mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-03-22 08:21:57 -04:00
aja: Refactor, clean-up and fix bugs in the signal routing system, and add SDITransport UI option to assist signal routing.
This commit is contained in:
committed by
Colin Edwards
parent
d78971b4db
commit
f09137a2e0
@@ -65,7 +65,6 @@ AJAOutput::AJAOutput(CNTV2Card *card, const std::string &cardID,
|
||||
mOutputID{outputID},
|
||||
mDeviceIndex{deviceIndex},
|
||||
mDeviceID{deviceID},
|
||||
mFrameTimes{},
|
||||
mAudioPlayCursor{0},
|
||||
mAudioWriteCursor{0},
|
||||
mAudioWrapAddress{0},
|
||||
@@ -140,31 +139,17 @@ void AJAOutput::Initialize(const OutputProps &props)
|
||||
props.pixelFormat);
|
||||
|
||||
mCard->SetOutputFrame(props.Channel(), mWriteCardFrame);
|
||||
|
||||
mCard->WaitForOutputVerticalInterrupt(props.Channel());
|
||||
|
||||
const auto &cardFrameRate =
|
||||
GetNTV2FrameRateFromVideoFormat(props.videoFormat);
|
||||
|
||||
ULWord fpsNum = 0;
|
||||
ULWord fpsDen = 0;
|
||||
GetFramesPerSecond(cardFrameRate, fpsNum, fpsDen);
|
||||
mFrameRateNum = fpsNum;
|
||||
mFrameRateDen = fpsDen;
|
||||
mFrameTimes.cardFrameTime =
|
||||
(1000000000ULL / (uint64_t)(fpsNum / fpsDen));
|
||||
mFrameTimes.cardFps = (double)(fpsNum / fpsDen);
|
||||
mFrameTimes.obsFps = obs_get_active_fps();
|
||||
if (mFrameTimes.obsFps < 1.0)
|
||||
mFrameTimes.obsFps = 30.0;
|
||||
mFrameTimes.obsFrameTime =
|
||||
(1000000000ULL / (uint64_t)mFrameTimes.obsFps);
|
||||
|
||||
mVideoDelay = ((int64_t)mNumCardFrames - 0) * 1000000 * mFrameRateDen /
|
||||
mFrameRateNum;
|
||||
|
||||
mAudioRate = props.audioSampleRate;
|
||||
|
||||
SetOutputProps(props);
|
||||
}
|
||||
|
||||
@@ -510,7 +495,7 @@ uint32_t AJAOutput::get_frame_count()
|
||||
}
|
||||
|
||||
// Perform DMA of audio samples to AJA card while taking into account wrapping around the
|
||||
// ends of the card's audio buffer (size set to 4MB in Routing::ConfigureOutputAudio).
|
||||
// ends of the card's audio buffer (size set to 4MB in aja::Routing::ConfigureOutputAudio).
|
||||
void AJAOutput::dma_audio_samples(NTV2AudioSystem audioSys, uint32_t *data,
|
||||
size_t size)
|
||||
{
|
||||
@@ -780,28 +765,8 @@ bool aja_output_device_changed(void *data, obs_properties_t *props,
|
||||
populate_output_device_list(list);
|
||||
|
||||
const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
|
||||
|
||||
size_t itemCount = obs_property_list_item_count(list);
|
||||
bool itemFound = false;
|
||||
|
||||
for (size_t i = 0; i < itemCount; i++) {
|
||||
const char *itemCardID = obs_property_list_item_string(list, i);
|
||||
if (strcmp(cardID, itemCardID) == 0) {
|
||||
itemFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemFound) {
|
||||
obs_property_list_insert_string(list, 0, cardID, cardID);
|
||||
obs_property_list_item_disable(list, 0, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!cardID) {
|
||||
blog(LOG_ERROR, "aja_output_device_changed: Card ID is null!");
|
||||
if (!cardID)
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *outputID =
|
||||
obs_data_get_string(settings, kUIPropAJAOutputID.id);
|
||||
@@ -828,8 +793,10 @@ bool aja_output_device_changed(void *data, obs_properties_t *props,
|
||||
obs_properties_get(props, kUIPropVideoFormatSelect.id);
|
||||
obs_property_t *pix_fmt_list =
|
||||
obs_properties_get(props, kUIPropPixelFormatSelect.id);
|
||||
obs_property_t *sdi_trx_list =
|
||||
obs_properties_get(props, kUIPropSDITransport.id);
|
||||
obs_property_t *sdi_4k_list =
|
||||
obs_properties_get(props, kUIPropSDI4KTransport.id);
|
||||
obs_properties_get(props, kUIPropSDITransport4K.id);
|
||||
|
||||
const NTV2DeviceID deviceID = cardEntry->GetDeviceID();
|
||||
populate_io_selection_output_list(cardID, outputID, deviceID,
|
||||
@@ -850,6 +817,11 @@ bool aja_output_device_changed(void *data, obs_properties_t *props,
|
||||
obs_property_list_clear(pix_fmt_list);
|
||||
populate_pixel_format_list(deviceID, pix_fmt_list);
|
||||
|
||||
IOSelection io_select = static_cast<IOSelection>(
|
||||
obs_data_get_int(settings, kUIPropOutput.id));
|
||||
obs_property_list_clear(sdi_trx_list);
|
||||
populate_sdi_transport_list(sdi_trx_list, io_select);
|
||||
|
||||
obs_property_list_clear(sdi_4k_list);
|
||||
populate_sdi_4k_transport_list(sdi_4k_list);
|
||||
|
||||
@@ -863,11 +835,9 @@ bool aja_output_dest_changed(obs_properties_t *props, obs_property_t *list,
|
||||
|
||||
blog(LOG_DEBUG, "AJA Output Dest Changed");
|
||||
|
||||
int dest = obs_data_get_int(settings, kUIPropOutput.id);
|
||||
|
||||
size_t itemCount = obs_property_list_item_count(list);
|
||||
bool itemFound = false;
|
||||
|
||||
int dest = obs_data_get_int(settings, kUIPropOutput.id);
|
||||
size_t itemCount = obs_property_list_item_count(list);
|
||||
for (size_t i = 0; i < itemCount; i++) {
|
||||
int itemDest = obs_property_list_item_int(list, i);
|
||||
if (dest == itemDest) {
|
||||
@@ -875,29 +845,12 @@ bool aja_output_dest_changed(obs_properties_t *props, obs_property_t *list,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemFound) {
|
||||
obs_property_list_insert_int(list, 0, "", dest);
|
||||
obs_property_list_item_disable(list, 0, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
|
||||
if (!cardID) {
|
||||
blog(LOG_ERROR, "aja_output_dest_changed: Card ID is null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &cardManager = aja::CardManager::Instance();
|
||||
cardManager.EnumerateCards();
|
||||
auto cardEntry = cardManager.GetCardEntry(cardID);
|
||||
if (!cardEntry) {
|
||||
blog(LOG_ERROR,
|
||||
"aja_output_dest_changed: Card entry not found for %s",
|
||||
cardID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Revert to "Select..." if desired IOSelection is already in use
|
||||
auto io_select = static_cast<IOSelection>(
|
||||
obs_data_get_int(settings, kUIPropOutput.id));
|
||||
@@ -916,6 +869,13 @@ bool aja_output_dest_changed(obs_properties_t *props, obs_property_t *list,
|
||||
}
|
||||
}
|
||||
|
||||
obs_property_t *sdi_trx_list =
|
||||
obs_properties_get(props, kUIPropSDITransport.id);
|
||||
obs_property_list_clear(sdi_trx_list);
|
||||
populate_sdi_transport_list(sdi_trx_list, io_select);
|
||||
obs_property_set_visible(sdi_trx_list,
|
||||
aja::IsIOSelectionSDI(io_select));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -971,7 +931,6 @@ static void *aja_output_create(obs_data_t *settings, obs_output_t *output)
|
||||
}
|
||||
|
||||
NTV2DeviceID deviceID = card->GetDeviceID();
|
||||
|
||||
OutputProps outputProps(deviceID);
|
||||
outputProps.ioSelect = static_cast<IOSelection>(
|
||||
obs_data_get_int(settings, kUIPropOutput.id));
|
||||
@@ -980,20 +939,19 @@ static void *aja_output_create(obs_data_t *settings, obs_output_t *output)
|
||||
"aja_output_create: Select a valid AJA Output IOSelection!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
outputProps.videoFormat = static_cast<NTV2VideoFormat>(
|
||||
obs_data_get_int(settings, kUIPropVideoFormatSelect.id));
|
||||
outputProps.pixelFormat = static_cast<NTV2PixelFormat>(
|
||||
obs_data_get_int(settings, kUIPropPixelFormatSelect.id));
|
||||
outputProps.sdi4kTransport = static_cast<SDI4KTransport>(
|
||||
obs_data_get_int(settings, kUIPropSDI4KTransport.id));
|
||||
|
||||
outputProps.sdiTransport = static_cast<SDITransport>(
|
||||
obs_data_get_int(settings, kUIPropSDITransport.id));
|
||||
outputProps.sdi4kTransport = static_cast<SDITransport4K>(
|
||||
obs_data_get_int(settings, kUIPropSDITransport4K.id));
|
||||
outputProps.audioNumChannels = kDefaultAudioChannels;
|
||||
outputProps.audioSampleSize = kDefaultAudioSampleSize;
|
||||
outputProps.audioSampleRate = kDefaultAudioSampleRate;
|
||||
|
||||
if (NTV2_IS_4K_VIDEO_FORMAT(outputProps.videoFormat) &&
|
||||
outputProps.sdi4kTransport == SDI4KTransport::Squares) {
|
||||
outputProps.sdi4kTransport == SDITransport4K::Squares) {
|
||||
if (outputProps.ioSelect == IOSelection::SDI1_2) {
|
||||
outputProps.ioSelect = IOSelection::SDI1_2_Squares;
|
||||
} else if (outputProps.ioSelect == IOSelection::SDI3_4) {
|
||||
@@ -1025,7 +983,6 @@ static void *aja_output_create(obs_data_t *settings, obs_output_t *output)
|
||||
auto ajaOutput = new AJAOutput(card, cardID, outputID,
|
||||
(UWord)cardEntry->GetCardIndex(),
|
||||
deviceID);
|
||||
|
||||
ajaOutput->Initialize(outputProps);
|
||||
ajaOutput->ClearVideoQueue();
|
||||
ajaOutput->ClearAudioQueue();
|
||||
@@ -1066,9 +1023,7 @@ static bool aja_output_start(void *data)
|
||||
|
||||
const std::string &cardID = ajaOutput->mCardID;
|
||||
auto &cardManager = aja::CardManager::Instance();
|
||||
|
||||
cardManager.EnumerateCards();
|
||||
|
||||
auto cardEntry = cardManager.GetCardEntry(cardID);
|
||||
if (!cardEntry) {
|
||||
blog(LOG_DEBUG,
|
||||
@@ -1115,14 +1070,14 @@ static bool aja_output_start(void *data)
|
||||
}
|
||||
|
||||
// Configures crosspoint routing on AJA card
|
||||
if (!Routing::ConfigureOutputRoute(outputProps, NTV2_MODE_DISPLAY,
|
||||
card)) {
|
||||
if (!aja::Routing::ConfigureOutputRoute(outputProps, NTV2_MODE_DISPLAY,
|
||||
card)) {
|
||||
blog(LOG_ERROR,
|
||||
"aja_output_start: Error configuring output route!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Routing::ConfigureOutputAudio(outputProps, card);
|
||||
aja::Routing::ConfigureOutputAudio(outputProps, card);
|
||||
|
||||
const auto &formatDesc = outputProps.FormatDesc();
|
||||
struct video_scale_info scaler = {};
|
||||
@@ -1166,26 +1121,22 @@ static void aja_output_stop(void *data, uint64_t ts)
|
||||
blog(LOG_ERROR, "aja_output_stop: Plugin instance is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto outputProps = ajaOutput->GetOutputProps();
|
||||
const std::string &cardID = ajaOutput->mCardID;
|
||||
auto &cardManager = aja::CardManager::Instance();
|
||||
|
||||
cardManager.EnumerateCards();
|
||||
|
||||
auto cardEntry = cardManager.GetCardEntry(cardID);
|
||||
if (!cardEntry) {
|
||||
blog(LOG_ERROR, "aja_output_stop: Card Entry not found for %s",
|
||||
cardID.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
CNTV2Card *card = ajaOutput->GetCard();
|
||||
if (!card) {
|
||||
blog(LOG_ERROR, "aja_output_stop: Card instance is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto outputProps = ajaOutput->GetOutputProps();
|
||||
if (!cardEntry->ReleaseOutputSelection(outputProps.ioSelect,
|
||||
card->GetDeviceID(),
|
||||
ajaOutput->mOutputID)) {
|
||||
@@ -1194,15 +1145,13 @@ static void aja_output_stop(void *data, uint64_t ts)
|
||||
aja::IOSelectionToString(outputProps.ioSelect).c_str(),
|
||||
cardID.c_str());
|
||||
}
|
||||
|
||||
auto audioSystem = outputProps.AudioSystem();
|
||||
|
||||
ajaOutput->GenerateTestPattern(outputProps.videoFormat,
|
||||
outputProps.pixelFormat,
|
||||
NTV2_TestPatt_Black);
|
||||
|
||||
obs_output_end_data_capture(ajaOutput->GetOBSOutput());
|
||||
|
||||
auto audioSystem = outputProps.AudioSystem();
|
||||
card->StopAudioOutput(audioSystem);
|
||||
|
||||
blog(LOG_INFO, "AJA Output stopped.");
|
||||
@@ -1234,28 +1183,28 @@ static void aja_output_raw_audio(void *data, struct audio_data *frames)
|
||||
static obs_properties_t *aja_output_get_properties(void *data)
|
||||
{
|
||||
obs_properties_t *props = obs_properties_create();
|
||||
|
||||
obs_property_t *device_list = obs_properties_add_list(
|
||||
props, kUIPropDevice.id, obs_module_text(kUIPropDevice.text),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
|
||||
obs_property_t *output_list = obs_properties_add_list(
|
||||
props, kUIPropOutput.id, obs_module_text(kUIPropOutput.text),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
|
||||
obs_property_t *vid_fmt_list = obs_properties_add_list(
|
||||
props, kUIPropVideoFormatSelect.id,
|
||||
obs_module_text(kUIPropVideoFormatSelect.text),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
|
||||
obs_properties_add_list(props, kUIPropPixelFormatSelect.id,
|
||||
obs_module_text(kUIPropPixelFormatSelect.text),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
|
||||
obs_properties_add_list(props, kUIPropSDI4KTransport.id,
|
||||
obs_module_text(kUIPropSDI4KTransport.text),
|
||||
obs_properties_add_list(props, kUIPropSDITransport.id,
|
||||
obs_module_text(kUIPropSDITransport.text),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_properties_add_list(props, kUIPropSDITransport.id,
|
||||
obs_module_text(kUIPropSDITransport.text),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
obs_properties_add_list(props, kUIPropSDITransport4K.id,
|
||||
obs_module_text(kUIPropSDITransport4K.text),
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
|
||||
obs_properties_add_bool(props, kUIPropAutoStartOutput.id,
|
||||
obs_module_text(kUIPropAutoStartOutput.text));
|
||||
|
||||
@@ -1265,7 +1214,6 @@ static obs_properties_t *aja_output_get_properties(void *data)
|
||||
aja_output_dest_changed);
|
||||
obs_property_set_modified_callback2(device_list,
|
||||
aja_output_device_changed, data);
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
@@ -1274,13 +1222,6 @@ static const char *aja_output_get_name(void *)
|
||||
return obs_module_text(kUIPropOutputModule.text);
|
||||
}
|
||||
|
||||
// NOTE(paulh): Drop-down defaults are set on a clean launch in aja-output-ui code.
|
||||
// Otherwise we load the settings stored in the ajaOutputProps/ajaPreviewOutputProps.json configs.
|
||||
void aja_output_get_defaults(obs_data_t *settings)
|
||||
{
|
||||
obs_data_set_default_bool(settings, kUIPropAutoStartOutput.id, false);
|
||||
}
|
||||
|
||||
struct obs_output_info create_aja_output_info()
|
||||
{
|
||||
struct obs_output_info aja_output_info = {};
|
||||
@@ -1295,8 +1236,6 @@ struct obs_output_info create_aja_output_info()
|
||||
aja_output_info.raw_video = aja_output_raw_video;
|
||||
aja_output_info.raw_audio = aja_output_raw_audio;
|
||||
aja_output_info.update = aja_output_update;
|
||||
aja_output_info.get_defaults = aja_output_get_defaults;
|
||||
aja_output_info.get_properties = aja_output_get_properties;
|
||||
|
||||
return aja_output_info;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user