Преглед изворни кода

Merge pull request #1706 from pkviet/deckfix

decklink: Fix FC<->LFE channel swap for some devices
Colin Edwards пре 6 година
родитељ
комит
8429724d64

+ 3 - 2
plugins/decklink/DecklinkInput.cpp

@@ -1,4 +1,4 @@
-#include "DecklinkInput.hpp"
+#include "DecklinkInput.hpp"
 
 #include <util/threading.h>
 
@@ -61,7 +61,8 @@ bool DeckLinkInput::Activate(DeckLinkDevice *device, long long modeId)
 		    instance->GetActivePixelFormat() == pixelFormat &&
 		    instance->GetActiveColorSpace() == colorSpace &&
 		    instance->GetActiveColorRange() == colorRange &&
-		    instance->GetActiveChannelFormat() == channelFormat)
+		    instance->GetActiveChannelFormat() == channelFormat &&
+		    instance->GetActiveSwapState() == swap)
 			return false;
 	}
 

+ 1 - 0
plugins/decklink/DecklinkInput.hpp

@@ -47,4 +47,5 @@ public:
 	bool dwns = false;
 	std::string hash;
 	long long id;
+	bool swap = false;
 };

+ 30 - 5
plugins/decklink/audio-repack.c

@@ -42,13 +42,34 @@ int repack_squash(struct audio_repack *repack,
 	uint16_t *dst = (uint16_t *)repack->packet_buffer;
 
 	/*  Audio needs squashing in order to avoid resampling issues.
+	 * The condition checks for 7.1 audio for which no squash is needed.
 	 */
+	if (squash > 0) {
+		while (src != esrc) {
+			__m128i target = _mm_load_si128(src++);
+			_mm_storeu_si128((__m128i *)dst, target);
+			dst += 8 - squash;
+		}
+	}
+
+	return 0;
+}
+
+int repack_squash_swap(struct audio_repack *repack,
+	const uint8_t *bsrc, uint32_t frame_count)
+{
+	if (check_buffer(repack, frame_count) < 0)
+		return -1;
+	int squash = repack->extra_dst_size;
+	const __m128i *src = (__m128i *)bsrc;
+	const __m128i *esrc = src + frame_count;
+	uint16_t *dst = (uint16_t *)repack->packet_buffer;
 	while (src != esrc) {
 		__m128i target = _mm_load_si128(src++);
-		_mm_storeu_si128((__m128i *)dst, target);
+		__m128i buf = _mm_shufflelo_epi16(target, _MM_SHUFFLE(2, 3, 1, 0));
+		_mm_storeu_si128((__m128i *)dst, buf);
 		dst += 8 - squash;
 	}
-
 	return 0;
 }
 
@@ -59,11 +80,15 @@ int audio_repack_init(struct audio_repack *repack,
 
 	if (sample_bit != 16)
 		return -1;
-
+	int _audio_repack_ch[8] = { 3, 4, 5, 6, 5, 6, 8, 8 };
 	repack->base_src_size = 8 * (16 / 8);
-	repack->base_dst_size = (int)repack_mode * (16 / 8);
-	repack->extra_dst_size = 8 - (int)repack_mode;
+	repack->base_dst_size = _audio_repack_ch[repack_mode] * (16 / 8);
+	repack->extra_dst_size = 8 - _audio_repack_ch[repack_mode];
 	repack->repack_func = &repack_squash;
+	if (repack_mode == repack_mode_8to5ch_swap ||
+		repack_mode == repack_mode_8to6ch_swap ||
+		repack_mode == repack_mode_8ch_swap)
+		repack->repack_func = &repack_squash_swap;
 
 	return 0;
 }

+ 5 - 1
plugins/decklink/audio-repack.h

@@ -26,10 +26,14 @@ struct audio_repack {
 };
 
 enum _audio_repack_mode {
-	repack_mode_8to3ch=3,
+	repack_mode_8to3ch=0,
 	repack_mode_8to4ch,
 	repack_mode_8to5ch,
 	repack_mode_8to6ch,
+	repack_mode_8to5ch_swap,
+	repack_mode_8to6ch_swap,
+	repack_mode_8ch_swap,
+	repack_mode_8ch,
 };
 
 typedef enum _audio_repack_mode audio_repack_mode_t;

+ 3 - 0
plugins/decklink/const.h

@@ -10,6 +10,7 @@
 #define DEACTIVATE_WNS  "deactivate_when_not_showing"
 #define AUTO_START      "auto_start"
 #define KEYER           "keyer"
+#define SWAP            "swap"
 
 #define TEXT_DEVICE                 obs_module_text("Device")
 #define TEXT_MODE                   obs_module_text("Mode")
@@ -32,3 +33,5 @@
 #define TEXT_DWNS                   obs_module_text("DeactivateWhenNotShowing")
 #define TEXT_AUTO_START             obs_module_text("AutoStart")
 #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")

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

@@ -19,3 +19,5 @@ ChannelFormat.5_1ch="5.1ch"
 ChannelFormat.7_1ch="7.1ch"
 DeactivateWhenNotShowing="Deactivate when not showing"
 AutoStart="Auto start on launch"
+SwapFC-LFE="Swap FC <-> LFE"
+SwapFC-LFE.Tooltip="Swap Front Channel and LFE Channel"

+ 10 - 8
plugins/decklink/decklink-device-instance.cpp

@@ -38,7 +38,7 @@ static inline int ConvertChannelFormat(speaker_layout format)
 	}
 }
 
-static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format)
+static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format, bool swap)
 {
 	switch (format) {
 	case SPEAKERS_2POINT1:
@@ -46,10 +46,11 @@ static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format)
 	case SPEAKERS_4POINT0:
 		return repack_mode_8to4ch;
 	case SPEAKERS_4POINT1:
-		return repack_mode_8to5ch;
+		return swap? repack_mode_8to5ch_swap:repack_mode_8to5ch;
 	case SPEAKERS_5POINT1:
-		return repack_mode_8to6ch;
+		return swap ? repack_mode_8to6ch_swap : repack_mode_8to6ch;
 	case SPEAKERS_7POINT1:
+		return swap ? repack_mode_8ch_swap: repack_mode_8ch;
 	default:
 		assert(false && "No repack requested");
 		return (audio_repack_mode_t)-1;
@@ -98,8 +99,8 @@ void DeckLinkDeviceInstance::HandleAudioPacket(
 	if (channelFormat != SPEAKERS_UNKNOWN &&
 	    channelFormat != SPEAKERS_MONO &&
 	    channelFormat != SPEAKERS_STEREO &&
-	    channelFormat != SPEAKERS_7POINT1 &&
-	    maxdevicechannel >= 8) {
+	    (channelFormat != SPEAKERS_7POINT1 || static_cast<DeckLinkInput*>(decklink)->swap)
+	    && maxdevicechannel >= 8) {
 
 		if (audioRepacker->repack((uint8_t *)bytes, frameCount) < 0) {
 			LOG(LOG_ERROR, "Failed to convert audio packet data");
@@ -226,6 +227,7 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
 
 	channelFormat = static_cast<DeckLinkInput*>(decklink)->GetChannelFormat();
 	currentPacket.speakers = channelFormat;
+	swap = static_cast<DeckLinkInput*>(decklink)->swap;
 
 	int maxdevicechannel = device->GetMaxChannel();
 
@@ -240,11 +242,11 @@ bool DeckLinkDeviceInstance::StartCapture(DeckLinkDeviceMode *mode_)
 		if (channelFormat != SPEAKERS_UNKNOWN &&
 		    channelFormat != SPEAKERS_MONO &&
 		    channelFormat != SPEAKERS_STEREO &&
-		    channelFormat != SPEAKERS_7POINT1 &&
-		    maxdevicechannel >= 8) {
+		    (channelFormat != SPEAKERS_7POINT1 || swap)
+		    && maxdevicechannel >= 8) {
 
 			const audio_repack_mode_t repack_mode = ConvertRepackFormat
-					(channelFormat);
+					(channelFormat, swap);
 			audioRepacker = new AudioRepacker(repack_mode);
 		}
 	}

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

@@ -29,6 +29,7 @@ protected:
 	uint64_t                lastVideoTS = 0;
 	AudioRepacker           *audioRepacker = nullptr;
 	speaker_layout          channelFormat = SPEAKERS_STEREO;
+	bool                    swap;
 
 	IDeckLinkMutableVideoFrame *decklinkOutputFrame = nullptr;
 
@@ -54,6 +55,7 @@ public:
 	inline video_colorspace GetActiveColorSpace() const {return colorSpace;}
 	inline video_range_type GetActiveColorRange() const {return colorRange;}
 	inline speaker_layout GetActiveChannelFormat() const {return channelFormat;}
+	inline bool GetActiveSwapState() const {return swap;}
 
 	inline DeckLinkDeviceMode *GetMode() const {return mode;}
 

+ 6 - 1
plugins/decklink/decklink-source.cpp

@@ -70,8 +70,9 @@ static void decklink_update(void *data, obs_data_t *settings)
 	decklink->SetColorSpace(colorSpace);
 	decklink->SetColorRange(colorRange);
 	decklink->SetChannelFormat(channelFormat);
-	decklink->Activate(device, id);
 	decklink->hash = std::string(hash);
+	decklink->swap = obs_data_get_bool(settings, SWAP);
+	decklink->Activate(device, id);
 }
 
 static void decklink_show(void *data)
@@ -101,6 +102,7 @@ static void decklink_get_defaults(obs_data_t *settings)
 	obs_data_set_default_int(settings, COLOR_SPACE, VIDEO_CS_DEFAULT);
 	obs_data_set_default_int(settings, COLOR_RANGE, VIDEO_RANGE_DEFAULT);
 	obs_data_set_default_int(settings, CHANNEL_FORMAT, SPEAKERS_STEREO);
+	obs_data_set_default_bool(settings, SWAP, false);
 }
 
 static const char *decklink_get_name(void*)
@@ -260,6 +262,9 @@ static obs_properties_t *decklink_get_properties(void *data)
 	obs_property_list_add_int(list, TEXT_CHANNEL_FORMAT_7_1CH,
 			SPEAKERS_7POINT1);
 
+	obs_property_t *swap = obs_properties_add_bool(props, SWAP, TEXT_SWAP);
+	obs_property_set_long_description(swap, TEXT_SWAP_TOOLTIP);
+
 	obs_properties_add_bool(props, BUFFERING, TEXT_BUFFERING);
 
 	obs_properties_add_bool(props, DEACTIVATE_WNS, TEXT_DWNS);