浏览代码

decklink: Fix automatic pixel format detection

Colin Edwards 4 年之前
父节点
当前提交
8285141ba5

+ 1 - 1
plugins/decklink/DecklinkInput.cpp

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

+ 1 - 0
plugins/decklink/DecklinkInput.hpp

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

+ 6 - 3
plugins/decklink/OBSVideoFrame.cpp

@@ -1,11 +1,14 @@
 #include "OBSVideoFrame.h"
 #include "OBSVideoFrame.h"
 
 
-OBSVideoFrame::OBSVideoFrame(long width, long height)
+OBSVideoFrame::OBSVideoFrame(long width, long height,
+			     BMDPixelFormat pixelFormat)
 {
 {
+	int bpp = 2;
 	this->width = width;
 	this->width = width;
 	this->height = height;
 	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)
 HRESULT OBSVideoFrame::SetFlags(BMDFrameFlags newFlags)

+ 1 - 1
plugins/decklink/OBSVideoFrame.h

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

+ 2 - 0
plugins/decklink/const.h

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

+ 1 - 0
plugins/decklink/data/locale/en-US.ini

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

+ 55 - 22
plugins/decklink/decklink-device-instance.cpp

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

+ 2 - 1
plugins/decklink/decklink-device-instance.hpp

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

+ 7 - 0
plugins/decklink/decklink-source.cpp

@@ -80,6 +80,7 @@ static void decklink_update(void *data, obs_data_t *settings)
 	decklink->SetChannelFormat(channelFormat);
 	decklink->SetChannelFormat(channelFormat);
 	decklink->hash = std::string(hash);
 	decklink->hash = std::string(hash);
 	decklink->swap = obs_data_get_bool(settings, SWAP);
 	decklink->swap = obs_data_get_bool(settings, SWAP);
+	decklink->allow10Bit = obs_data_get_bool(settings, ALLOW_10_BIT);
 	decklink->Activate(device, id, videoConnection, audioConnection);
 	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);
 	list = obs_properties_get(props, PIXEL_FORMAT);
 	obs_property_set_visible(list, id != MODE_ID_AUTO);
 	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;
 	return true;
 }
 }
 
 
@@ -277,6 +281,7 @@ static obs_properties_t *decklink_get_properties(void *data)
 				       OBS_COMBO_FORMAT_INT);
 				       OBS_COMBO_FORMAT_INT);
 
 
 	obs_property_list_add_int(list, "8-bit YUV", bmdFormat8BitYUV);
 	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);
 	obs_property_list_add_int(list, "8-bit BGRA", bmdFormat8BitBGRA);
 
 
 	list = obs_properties_add_list(props, COLOR_SPACE, TEXT_COLOR_SPACE,
 	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, DEACTIVATE_WNS, TEXT_DWNS);
 
 
+	obs_properties_add_bool(props, ALLOW_10_BIT, TEXT_ALLOW_10_BIT);
+
 	UNUSED_PARAMETER(data);
 	UNUSED_PARAMETER(data);
 	return props;
 	return props;
 }
 }