0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 13:08:50 +02:00

decklink: Fix FC<->LFE channel swap for some devices

Fixes mantis issue https://obsproject.com/mantis/view.php?id=1379
For some devices with hdmi input, the Front Center channel and the LFE
channel are swapped. For some others they are not.
To solve the issue a new swap setting is added so that the user can
swap the two channels if needed.
This commit is contained in:
pkv 2019-03-01 09:59:58 +01:00
parent 748067c930
commit 05508ac895
9 changed files with 64 additions and 19 deletions

View File

@ -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;
}

View File

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

View File

@ -42,16 +42,37 @@ 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.
*/
while (src != esrc) {
__m128i target = _mm_load_si128(src++);
_mm_storeu_si128((__m128i *)dst, target);
dst += 8 - squash;
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++);
__m128i buf = _mm_shufflelo_epi16(target, _MM_SHUFFLE(2, 3, 1, 0));
_mm_storeu_si128((__m128i *)dst, buf);
dst += 8 - squash;
}
return 0;
}
int audio_repack_init(struct audio_repack *repack,
audio_repack_mode_t repack_mode, uint8_t sample_bit)
{
@ -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;
}

View File

@ -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;

View File

@ -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")

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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;}

View File

@ -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);