decklink: Fix automatic pixel format detection

master
Colin Edwards 2020-12-16 14:44:37 -06:00 committed by Jim
parent 20bb465047
commit 8285141ba5
9 changed files with 76 additions and 28 deletions

View File

@ -100,7 +100,7 @@ bool DeckLinkInput::Activate(DeckLinkDevice *device, long long modeId,
return false;
}
if (!instance->StartCapture(mode, bmdVideoConnection,
if (!instance->StartCapture(mode, allow10Bit, bmdVideoConnection,
bmdAudioConnection)) {
instance = nullptr;
return false;

View File

@ -50,6 +50,7 @@ public:
std::string hash;
long long id;
bool swap = false;
bool allow10Bit = false;
BMDVideoConnection videoConnection;
BMDAudioConnection audioConnection;
};

View File

@ -1,11 +1,14 @@
#include "OBSVideoFrame.h"
OBSVideoFrame::OBSVideoFrame(long width, long height)
OBSVideoFrame::OBSVideoFrame(long width, long height,
BMDPixelFormat pixelFormat)
{
int bpp = 2;
this->width = width;
this->height = height;
this->rowBytes = width * 2;
this->data = new unsigned char[width * height * 2 + 1];
this->rowBytes = width * bpp;
this->data = new unsigned char[width * height * bpp + 1];
this->pixelFormat = pixelFormat;
}
HRESULT OBSVideoFrame::SetFlags(BMDFrameFlags newFlags)

View File

@ -15,7 +15,7 @@ private:
unsigned char *data;
public:
OBSVideoFrame(long width, long height);
OBSVideoFrame(long width, long height, BMDPixelFormat pixelFormat);
HRESULT STDMETHODCALLTYPE SetFlags(BMDFrameFlags newFlags) override;

View File

@ -13,6 +13,7 @@
#define AUTO_START "auto_start"
#define KEYER "keyer"
#define SWAP "swap"
#define ALLOW_10_BIT "allow_10_bit"
#define TEXT_DEVICE obs_module_text("Device")
#define TEXT_VIDEO_CONNECTION obs_module_text("VideoConnection")
@ -39,3 +40,4 @@
#define TEXT_ENABLE_KEYER obs_module_text("Keyer")
#define TEXT_SWAP obs_module_text("SwapFC-LFE")
#define TEXT_SWAP_TOOLTIP obs_module_text("SwapFC-LFE.Tooltip")
#define TEXT_ALLOW_10_BIT obs_module_text("Allow10Bit")

View File

@ -23,3 +23,4 @@ SwapFC-LFE="Swap FC and LFE"
SwapFC-LFE.Tooltip="Swap Front Center Channel and LFE Channel"
VideoConnection="Video Connection"
AudioConnection="Audio Connection"
Allow10Bit="Allow 10 Bit (Required for SDI captions, may cause performance overhead)"

View File

@ -24,10 +24,10 @@ static inline enum video_format ConvertPixelFormat(BMDPixelFormat format)
return VIDEO_FORMAT_BGRX;
default:
case bmdFormat8BitYUV:;
case bmdFormat8BitYUV:
case bmdFormat10BitYUV:;
return VIDEO_FORMAT_UYVY;
}
return VIDEO_FORMAT_UYVY;
}
static inline int ConvertChannelFormat(speaker_layout format)
@ -168,21 +168,28 @@ void DeckLinkDeviceInstance::HandleVideoFrame(
packets->Release();
}
IDeckLinkVideoConversion *frameConverter =
CreateVideoConversionInstance();
IDeckLinkVideoFrame *frame;
if (videoFrame->GetPixelFormat() != convertFrame->GetPixelFormat()) {
IDeckLinkVideoConversion *frameConverter =
CreateVideoConversionInstance();
frameConverter->ConvertFrame(videoFrame, convertFrame);
frameConverter->ConvertFrame(videoFrame, convertFrame);
frame = convertFrame;
} else {
frame = videoFrame;
}
void *bytes;
if (convertFrame->GetBytes(&bytes) != S_OK) {
if (frame->GetBytes(&bytes) != S_OK) {
LOG(LOG_WARNING, "Failed to get video frame data");
return;
}
currentFrame.data[0] = (uint8_t *)bytes;
currentFrame.linesize[0] = (uint32_t)convertFrame->GetRowBytes();
currentFrame.width = (uint32_t)convertFrame->GetWidth();
currentFrame.height = (uint32_t)convertFrame->GetHeight();
currentFrame.linesize[0] = (uint32_t)frame->GetRowBytes();
currentFrame.width = (uint32_t)frame->GetWidth();
currentFrame.height = (uint32_t)frame->GetHeight();
currentFrame.timestamp = timestamp;
obs_source_output_video2(
@ -326,10 +333,22 @@ void DeckLinkDeviceInstance::SetupVideoFormat(DeckLinkDeviceMode *mode_)
currentFrame.color_range_min,
currentFrame.color_range_max);
if (convertFrame) {
delete convertFrame;
delete convertFrame;
BMDPixelFormat convertFormat;
switch (pixelFormat) {
case bmdFormat8BitBGRA:
convertFormat = bmdFormat8BitBGRA;
break;
default:
case bmdFormat10BitYUV:
case bmdFormat8BitYUV:;
convertFormat = bmdFormat8BitYUV;
break;
}
convertFrame = new OBSVideoFrame(mode_->GetWidth(), mode_->GetHeight());
convertFrame = new OBSVideoFrame(mode_->GetWidth(), mode_->GetHeight(),
convertFormat);
#ifdef LOG_SETUP_VIDEO_FORMAT
LOG(LOG_INFO, "Setup video format: %s, %s, %s",
@ -340,6 +359,7 @@ void DeckLinkDeviceInstance::SetupVideoFormat(DeckLinkDeviceMode *mode_)
}
bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_,
bool allow10Bit_,
BMDVideoConnection bmdVideoConnection,
BMDAudioConnection bmdAudioConnection)
{
@ -392,7 +412,11 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_,
bool isauto = mode_->GetName() == "Auto";
if (isauto) {
displayMode = bmdModeNTSC;
pixelFormat = bmdFormat10BitYUV;
if (allow10Bit) {
pixelFormat = bmdFormat10BitYUV;
} else {
pixelFormat = bmdFormat8BitYUV;
}
flags = bmdVideoInputEnableFormatDetection;
} else {
displayMode = mode_->GetDisplayMode();
@ -401,6 +425,8 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_,
flags = bmdVideoInputFlagDefault;
}
allow10Bit = allow10Bit_;
const HRESULT videoResult =
input->EnableVideoInput(displayMode, pixelFormat, flags);
if (videoResult != S_OK) {
@ -631,15 +657,22 @@ HRESULT STDMETHODCALLTYPE DeckLinkDeviceInstance::VideoInputFormatChanged(
{
if (events & bmdVideoInputColorspaceChanged) {
switch (detectedSignalFlags) {
case bmdDetectedVideoInputRGB444:
if (detectedSignalFlags & bmdDetectedVideoInputRGB444) {
pixelFormat = bmdFormat8BitBGRA;
break;
default:
case bmdDetectedVideoInputYCbCr422:
pixelFormat = bmdFormat10BitYUV;
break;
}
if (detectedSignalFlags & bmdDetectedVideoInputYCbCr422) {
if (detectedSignalFlags &
bmdDetectedVideoInput10BitDepth) {
if (allow10Bit) {
pixelFormat = bmdFormat10BitYUV;
} else {
pixelFormat = bmdFormat8BitYUV;
}
}
if (detectedSignalFlags &
bmdDetectedVideoInput8BitDepth) {
pixelFormat = bmdFormat8BitYUV;
}
}
}

View File

@ -35,6 +35,7 @@ protected:
AudioRepacker *audioRepacker = nullptr;
speaker_layout channelFormat = SPEAKERS_STEREO;
bool swap;
bool allow10Bit;
OBSVideoFrame *convertFrame = nullptr;
IDeckLinkMutableVideoFrame *decklinkOutputFrame = nullptr;
@ -85,7 +86,7 @@ public:
inline DeckLinkDeviceMode *GetMode() const { return mode; }
bool StartCapture(DeckLinkDeviceMode *mode,
bool StartCapture(DeckLinkDeviceMode *mode, bool allow10Bit,
BMDVideoConnection bmdVideoConnection,
BMDAudioConnection bmdAudioConnection);
bool StopCapture(void);

View File

@ -80,6 +80,7 @@ static void decklink_update(void *data, obs_data_t *settings)
decklink->SetChannelFormat(channelFormat);
decklink->hash = std::string(hash);
decklink->swap = obs_data_get_bool(settings, SWAP);
decklink->allow10Bit = obs_data_get_bool(settings, ALLOW_10_BIT);
decklink->Activate(device, id, videoConnection, audioConnection);
}
@ -247,6 +248,9 @@ static bool mode_id_changed(obs_properties_t *props, obs_property_t *list,
list = obs_properties_get(props, PIXEL_FORMAT);
obs_property_set_visible(list, id != MODE_ID_AUTO);
auto allow10BitProp = obs_properties_get(props, ALLOW_10_BIT);
obs_property_set_visible(allow10BitProp, id == MODE_ID_AUTO);
return true;
}
@ -277,6 +281,7 @@ static obs_properties_t *decklink_get_properties(void *data)
OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(list, "8-bit YUV", bmdFormat8BitYUV);
obs_property_list_add_int(list, "10-bit YUV", bmdFormat10BitYUV);
obs_property_list_add_int(list, "8-bit BGRA", bmdFormat8BitBGRA);
list = obs_properties_add_list(props, COLOR_SPACE, TEXT_COLOR_SPACE,
@ -322,6 +327,8 @@ static obs_properties_t *decklink_get_properties(void *data)
obs_properties_add_bool(props, DEACTIVATE_WNS, TEXT_DWNS);
obs_properties_add_bool(props, ALLOW_10_BIT, TEXT_ALLOW_10_BIT);
UNUSED_PARAMETER(data);
return props;
}