aja: Add audio channel selection to capture

Adapted audio repacker for 32-bit samples,

with an ifdef to use SIMD or C version.
This commit is contained in:
Paul Hindt
2023-02-15 10:38:39 -05:00
committed by Ryan Foster
parent 27ba216271
commit 003241511c
11 changed files with 509 additions and 26 deletions
+4 -1
View File
@@ -41,7 +41,10 @@ target_sources(
aja-widget-io.cpp
aja-widget-io.hpp
aja-card-manager.hpp
aja-ui-props.hpp)
aja-ui-props.hpp
audio-repack.c
audio-repack.h
audio-repack.hpp)
target_link_libraries(aja PRIVATE OBS::libobs AJA::LibAJANTV2)
+30 -13
View File
@@ -13,12 +13,13 @@ SourceProps::SourceProps()
pixelFormat{NTV2_FBF_INVALID},
sdiTransport{SDITransport::SingleLink},
sdi4kTransport{SDITransport4K::TwoSampleInterleave},
audioNumChannels{8},
audioSampleSize{4},
audioSampleRate{48000},
audioNumChannels{kDefaultAudioChannels},
audioSampleSize{kDefaultAudioSampleSize},
audioSampleRate{kDefaultAudioSampleRate},
vpids{},
autoDetect{false},
deactivateWhileNotShowing{false}
deactivateWhileNotShowing{false},
swapFrontCenterLFE{false}
{
}
@@ -30,12 +31,13 @@ SourceProps::SourceProps(NTV2DeviceID devID)
pixelFormat{NTV2_FBF_INVALID},
sdiTransport{SDITransport::SingleLink},
sdi4kTransport{SDITransport4K::TwoSampleInterleave},
audioNumChannels{8},
audioSampleSize{4},
audioSampleRate{48000},
audioNumChannels{kDefaultAudioChannels},
audioSampleSize{kDefaultAudioSampleSize},
audioSampleRate{kDefaultAudioSampleRate},
vpids{},
autoDetect{false},
deactivateWhileNotShowing{false}
deactivateWhileNotShowing{false},
swapFrontCenterLFE{false}
{
}
@@ -54,6 +56,7 @@ SourceProps::SourceProps(const SourceProps &props)
vpids = props.vpids;
autoDetect = props.autoDetect;
deactivateWhileNotShowing = props.deactivateWhileNotShowing;
swapFrontCenterLFE = props.swapFrontCenterLFE;
}
SourceProps::SourceProps(SourceProps &&props)
@@ -71,6 +74,7 @@ SourceProps::SourceProps(SourceProps &&props)
vpids = props.vpids;
autoDetect = props.autoDetect;
deactivateWhileNotShowing = props.deactivateWhileNotShowing;
swapFrontCenterLFE = props.swapFrontCenterLFE;
}
void SourceProps::operator=(const SourceProps &props)
@@ -88,6 +92,7 @@ void SourceProps::operator=(const SourceProps &props)
vpids = props.vpids;
autoDetect = props.autoDetect;
deactivateWhileNotShowing = props.deactivateWhileNotShowing;
swapFrontCenterLFE = props.swapFrontCenterLFE;
}
void SourceProps::operator=(SourceProps &&props)
@@ -105,6 +110,7 @@ void SourceProps::operator=(SourceProps &&props)
vpids = props.vpids;
autoDetect = props.autoDetect;
deactivateWhileNotShowing = props.deactivateWhileNotShowing;
swapFrontCenterLFE = props.swapFrontCenterLFE;
}
bool SourceProps::operator==(const SourceProps &props)
@@ -120,7 +126,8 @@ bool SourceProps::operator==(const SourceProps &props)
audioNumChannels == props.audioNumChannels &&
audioSampleSize == props.audioSampleSize &&
audioSampleRate == props.audioSampleRate &&
deactivateWhileNotShowing == props.deactivateWhileNotShowing);
deactivateWhileNotShowing == props.deactivateWhileNotShowing &&
swapFrontCenterLFE == props.swapFrontCenterLFE);
}
bool SourceProps::operator!=(const SourceProps &props)
@@ -196,9 +203,19 @@ audio_format SourceProps::AudioFormat() const
speaker_layout SourceProps::SpeakerLayout() const
{
if (audioNumChannels == 2)
if (audioNumChannels == 1)
return SPEAKERS_MONO;
else if (audioNumChannels == 2)
return SPEAKERS_STEREO;
// NTV2 is always at least 8ch on modern boards
else if (audioNumChannels == 3)
return SPEAKERS_2POINT1;
else if (audioNumChannels == 4)
return SPEAKERS_4POINT0;
else if (audioNumChannels == 5)
return SPEAKERS_4POINT1;
else if (audioNumChannels == 6)
return SPEAKERS_5POINT1;
// NTV2 card is always set to at least 8ch
return SPEAKERS_7POINT1;
}
@@ -213,8 +230,8 @@ OutputProps::OutputProps(NTV2DeviceID devID)
pixelFormat{NTV2_FBF_INVALID},
sdi4kTransport{SDITransport4K::TwoSampleInterleave},
audioNumChannels{8},
audioSampleSize{4},
audioSampleRate{48000}
audioSampleSize{kDefaultAudioSampleSize},
audioSampleRate{kDefaultAudioSampleRate}
{
}
+1
View File
@@ -47,6 +47,7 @@ public:
uint32_t audioSampleRate;
bool autoDetect;
bool deactivateWhileNotShowing;
bool swapFrontCenterLFE;
};
class OutputProps {
+2 -2
View File
@@ -152,7 +152,7 @@ void Routing::StartSourceAudio(const SourceProps &props, CNTV2Card *card)
audioSys, NTV2InputSourceToAudioSource(inputSrc),
NTV2InputSourceToEmbeddedAudioInput(inputSrc));
card->SetNumberAudioChannels(props.audioNumChannels, audioSys);
card->SetNumberAudioChannels(kDefaultAudioChannels, audioSys);
card->SetAudioRate(props.AudioRate(), audioSys);
card->SetAudioBufferSize(NTV2_AUDIO_BUFFER_BIG, audioSys);
@@ -188,7 +188,7 @@ void Routing::StartSourceAudio(const SourceProps &props, CNTV2Card *card)
for (int a = 0; a < NTV2DeviceGetNumAudioSystems(card->GetDeviceID());
a++) {
card->SetAudioLoopBack(NTV2_AUDIO_LOOPBACK_OFF,
card->SetAudioLoopBack(NTV2_AUDIO_LOOPBACK_ON,
NTV2AudioSystem(a));
}
+98 -9
View File
@@ -18,6 +18,30 @@
#endif
#define NTV2_AUDIOSIZE_MAX (401 * 1024)
static constexpr int kDefaultAudioCaptureChannels = 2;
static inline audio_repack_mode_t ConvertRepackFormat(speaker_layout format,
bool swap = false)
{
switch (format) {
case SPEAKERS_STEREO:
return repack_mode_8to2ch;
case SPEAKERS_2POINT1:
return repack_mode_8to3ch;
case SPEAKERS_4POINT0:
return repack_mode_8to4ch;
case SPEAKERS_4POINT1:
return swap ? repack_mode_8to5ch_swap : repack_mode_8to5ch;
case SPEAKERS_5POINT1:
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;
}
}
AJASource::AJASource(obs_source_t *source)
: mVideoBuffer{},
mAudioBuffer{},
@@ -283,7 +307,6 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
// etc...
ULWord currentCardFrame = GetIndexForNTV2Channel(framestore) * 2;
card->WaitForInputFieldID(NTV2_FIELD0, channel);
currentCardFrame ^= 1;
card->SetInputFrame(framestore, currentCardFrame);
@@ -293,6 +316,11 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
obs_data_t *settings = obs_source_get_settings(ajaSource->mSource);
AudioRepacker *audioRepacker = new AudioRepacker(
ConvertRepackFormat(sourceProps.SpeakerLayout(),
sourceProps.swapFrontCenterLFE),
sourceProps.audioSampleSize * 8);
while (ajaSource->IsCapturing()) {
if (card->GetModelName() == "(Not Found)") {
os_sleep_ms(250);
@@ -340,15 +368,35 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
ResetAudioBufferOffsets(card, audioSystem, offsets);
} else {
offsets.lastAddress = offsets.currentAddress;
uint32_t sampleCount = offsets.bytesRead /
(kDefaultAudioChannels *
sourceProps.audioSampleSize);
obs_source_audio audioPacket;
audioPacket.samples_per_sec = 48000;
audioPacket.format = AUDIO_FORMAT_32BIT;
audioPacket.speakers = SPEAKERS_7POINT1;
audioPacket.frames = offsets.bytesRead / 32;
audioPacket.samples_per_sec =
sourceProps.audioSampleRate;
audioPacket.format = sourceProps.AudioFormat();
audioPacket.speakers = sourceProps.SpeakerLayout();
audioPacket.frames = sampleCount;
audioPacket.timestamp =
get_sample_time(audioPacket.frames, 48000);
audioPacket.data[0] = (uint8_t *)ajaSource->mAudioBuffer
.GetHostPointer();
get_sample_time(audioPacket.frames,
sourceProps.audioSampleRate);
uint8_t *hostAudioBuffer =
(uint8_t *)ajaSource->mAudioBuffer
.GetHostPointer();
if (sourceProps.audioNumChannels >= 2 &&
sourceProps.audioNumChannels <= 6) {
/* Repack 8ch audio to fit specified OBS speaker layout */
audioRepacker->repack(hostAudioBuffer,
sampleCount);
audioPacket.data[0] =
(*audioRepacker)->packet_buffer;
} else {
/* Silence, or pass-through 8ch of audio */
if (sourceProps.audioNumChannels == 0)
memset(hostAudioBuffer, 0,
offsets.bytesRead);
audioPacket.data[0] = hostAudioBuffer;
}
obs_source_output_audio(ajaSource->mSource,
&audioPacket);
}
@@ -395,7 +443,10 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
}
blog(LOG_INFO, "AJASource::Capturethread: Thread loop stopped");
if (audioRepacker) {
delete audioRepacker;
audioRepacker = nullptr;
}
ajaSource->GenerateTestPattern(sourceProps.videoFormat,
sourceProps.pixelFormat,
NTV2_TestPatt_Black);
@@ -682,6 +733,8 @@ bool aja_source_device_changed(void *data, obs_properties_t *props,
obs_properties_get(props, kUIPropSDITransport.id);
obs_property_t *sdi_4k_list =
obs_properties_get(props, kUIPropSDITransport4K.id);
obs_property_t *channel_format_list =
obs_properties_get(props, kUIPropChannelFormat.id);
obs_property_list_clear(vid_fmt_list);
obs_property_list_add_int(vid_fmt_list, obs_module_text("Auto"),
@@ -702,6 +755,22 @@ bool aja_source_device_changed(void *data, obs_properties_t *props,
obs_property_list_clear(sdi_4k_list);
populate_sdi_4k_transport_list(sdi_4k_list);
obs_property_list_clear(channel_format_list);
obs_property_list_add_int(channel_format_list, TEXT_CHANNEL_FORMAT_NONE,
0);
obs_property_list_add_int(channel_format_list,
TEXT_CHANNEL_FORMAT_2_0CH, 2);
obs_property_list_add_int(channel_format_list,
TEXT_CHANNEL_FORMAT_2_1CH, 3);
obs_property_list_add_int(channel_format_list,
TEXT_CHANNEL_FORMAT_4_0CH, 4);
obs_property_list_add_int(channel_format_list,
TEXT_CHANNEL_FORMAT_4_1CH, 5);
obs_property_list_add_int(channel_format_list,
TEXT_CHANNEL_FORMAT_5_1CH, 6);
obs_property_list_add_int(channel_format_list,
TEXT_CHANNEL_FORMAT_7_1CH, 8);
populate_io_selection_input_list(cardID, ajaSource->GetName(), deviceID,
io_select_list);
@@ -904,8 +973,12 @@ static void aja_source_update(void *data, obs_data_t *settings)
obs_data_get_int(settings, kUIPropSDITransport.id));
auto sdi_t4k_select = static_cast<SDITransport4K>(
obs_data_get_int(settings, kUIPropSDITransport4K.id));
auto num_audio_channels =
obs_data_get_int(settings, kUIPropChannelFormat.id);
bool deactivateWhileNotShowing =
obs_data_get_bool(settings, kUIPropDeactivateWhenNotShowing.id);
bool swapFrontCenterLFE =
obs_data_get_bool(settings, kUIPropChannelSwap_FC_LFE.id);
const std::string &wantCardID =
obs_data_get_string(settings, kUIPropDevice.id);
@@ -989,6 +1062,8 @@ static void aja_source_update(void *data, obs_data_t *settings)
? SDITransport::Unknown
: static_cast<SDITransport>(sdi_trx_select);
want_props.sdi4kTransport = sdi_t4k_select;
want_props.audioNumChannels = (uint32_t)num_audio_channels;
want_props.swapFrontCenterLFE = swapFrontCenterLFE;
want_props.vpids.clear();
want_props.deactivateWhileNotShowing = deactivateWhileNotShowing;
if (aja::IsIOSelectionSDI(io_select)) {
@@ -1099,11 +1174,21 @@ static obs_properties_t *aja_source_get_properties(void *data)
obs_properties_add_list(props, kUIPropSDITransport4K.id,
obs_module_text(kUIPropSDITransport4K.text),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_properties_add_list(props, kUIPropChannelFormat.id,
obs_module_text(kUIPropChannelFormat.text),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_t *swap = obs_properties_add_bool(
props, kUIPropChannelSwap_FC_LFE.id,
obs_module_text(kUIPropChannelSwap_FC_LFE.text));
obs_property_set_long_description(swap,
kUIPropChannelSwap_FC_LFE.tooltip);
obs_properties_add_bool(
props, kUIPropDeactivateWhenNotShowing.id,
obs_module_text(kUIPropDeactivateWhenNotShowing.text));
obs_properties_add_bool(props, kUIPropBuffering.id,
obs_module_text(kUIPropBuffering.text));
obs_properties_add_bool(props, kUIPropBuffering.id,
obs_module_text(kUIPropBuffering.text));
obs_property_set_modified_callback(vid_fmt_list,
aja_video_format_changed);
@@ -1128,6 +1213,10 @@ void aja_source_get_defaults(obs_data_t *settings)
obs_data_set_default_int(
settings, kUIPropSDITransport4K.id,
static_cast<long long>(SDITransport4K::TwoSampleInterleave));
obs_data_set_default_int(settings, kUIPropChannelFormat.id,
kDefaultAudioCaptureChannels);
obs_data_set_default_bool(settings, kUIPropChannelSwap_FC_LFE.id,
false);
obs_data_set_default_bool(settings, kUIPropDeactivateWhenNotShowing.id,
false);
}
+1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "aja-props.hpp"
#include "audio-repack.hpp"
#include <obs-module.h>
+21 -1
View File
@@ -107,4 +107,24 @@ static const UIProperty kUIPropMultiViewAudioSource = {
"ui_prop_multi_view_audio_source",
"Multi View Audio Source",
"",
};
};
static const UIProperty kUIPropChannelFormat = {
"ui_prop_channel_format",
"ChannelFormat",
"",
};
static const UIProperty kUIPropChannelSwap_FC_LFE = {
"ui_prop_channel_swap_fc_lfe",
"SwapFC-LFE",
"SwapFC-LFE.Tooltip",
};
#define TEXT_CHANNEL_FORMAT_NONE obs_module_text("ChannelFormat.None")
#define TEXT_CHANNEL_FORMAT_2_0CH obs_module_text("ChannelFormat.2_0ch")
#define TEXT_CHANNEL_FORMAT_2_1CH obs_module_text("ChannelFormat.2_1ch")
#define TEXT_CHANNEL_FORMAT_4_0CH obs_module_text("ChannelFormat.4_0ch")
#define TEXT_CHANNEL_FORMAT_4_1CH obs_module_text("ChannelFormat.4_1ch")
#define TEXT_CHANNEL_FORMAT_5_1CH obs_module_text("ChannelFormat.5_1ch")
#define TEXT_CHANNEL_FORMAT_7_1CH obs_module_text("ChannelFormat.7_1ch")
+268
View File
@@ -0,0 +1,268 @@
#include "audio-repack.h"
#define USE_SIMD
#ifdef USE_SIMD
#include <util/sse-intrin.h>
#endif
#define NUM_CHANNELS 8 /* max until OBS supports higher channel counts */
int check_buffer(struct audio_repack *repack, uint32_t frame_count)
{
const uint32_t new_size =
frame_count * repack->base_dst_size + repack->pad_dst_size;
if (repack->packet_size < new_size) {
repack->packet_buffer =
brealloc(repack->packet_buffer, new_size);
if (!repack->packet_buffer)
return -1;
repack->packet_size = new_size;
}
return 0;
}
#ifdef USE_SIMD
/*
* Squash array of 8ch to new channel count
* 16-bit PCM, SIMD version
* For instance:
* 2.1:
*
* | FL | FR | LFE | emp | emp | emp |emp |emp |
* | | |
* | FL | FR | LFE |
*/
int repack_squash16(struct audio_repack *repack, const uint8_t *bsrc,
uint32_t frame_count)
{
if (check_buffer(repack, frame_count) < 0)
return -1;
int squash = repack->squash_count;
const __m128i *src = (__m128i *)bsrc;
const __m128i *end = src + frame_count;
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 != end) {
__m128i target = _mm_load_si128(src++);
_mm_storeu_si128((__m128i *)dst, target);
dst += NUM_CHANNELS - squash;
}
}
return 0;
}
/*
* Squash array of 8ch and swap Front Center channel with LFE
* 16-bit PCM, SIMD version
* For instance:
* 2.1:
*
* | FL | FR | FC | LFE | RL | RR | LC | RC |
* | | |
* | FL | FR | LFE | FC | RL | RR | LC | RC |
*/
int repack_squash_swap16(struct audio_repack *repack, const uint8_t *bsrc,
uint32_t frame_count)
{
if (check_buffer(repack, frame_count) < 0)
return -1;
int squash = repack->squash_count;
const __m128i *src = (__m128i *)bsrc;
const __m128i *end = src + frame_count;
uint16_t *dst = (uint16_t *)repack->packet_buffer;
while (src != end) {
__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 += NUM_CHANNELS - squash;
}
return 0;
}
/*
* Squash array of 8ch to new channel count
* 32-bit PCM, SIMD version
*/
int repack_squash32(struct audio_repack *repack, const uint8_t *bsrc,
uint32_t frame_count)
{
if (check_buffer(repack, frame_count) < 0)
return -1;
int squash = repack->squash_count;
const __m128i *src = (__m128i *)bsrc;
const __m128i *end =
(__m128i *)(bsrc + (frame_count * repack->base_src_size));
uint32_t *dst = (uint32_t *)repack->packet_buffer;
if (squash > 0) {
while (src != end) {
__m128i tgt_lo = _mm_loadu_si128(src++);
__m128i tgt_hi = _mm_loadu_si128(src++);
_mm_storeu_si128((__m128i *)dst, tgt_lo);
dst += 4;
_mm_storeu_si128((__m128i *)dst, tgt_hi);
dst += 4;
dst -= squash;
}
}
return 0;
}
/*
* Squash array of 8ch to new channel count and swap FC with LFE
* 32-bit PCM, SIMD version
*/
int repack_squash_swap32(struct audio_repack *repack, const uint8_t *bsrc,
uint32_t frame_count)
{
if (check_buffer(repack, frame_count) < 0)
return -1;
int squash = repack->squash_count;
const __m128i *src = (__m128i *)bsrc;
const __m128i *end =
(__m128i *)(bsrc + (frame_count * repack->base_src_size));
uint32_t *dst = (uint32_t *)repack->packet_buffer;
while (src != end) {
__m128i tgt_lo = _mm_shuffle_epi32(_mm_loadu_si128(src++),
_MM_SHUFFLE(2, 3, 1, 0));
__m128i tgt_hi = _mm_loadu_si128(src++);
_mm_storeu_si128((__m128i *)dst, tgt_lo);
dst += 4;
_mm_storeu_si128((__m128i *)dst, tgt_hi);
dst += 4;
dst -= squash;
}
return 0;
}
#else
/*
* Squash array of 8ch to new channel count
* 16-bit or 32-bit PCM, C version
*/
int repack_squash(struct audio_repack *repack, const uint8_t *bsrc,
uint32_t frame_count)
{
if (check_buffer(repack, frame_count) < 0)
return -1;
int squash = repack->squash_count;
const uint8_t *src = bsrc;
const uint8_t *end = src + frame_count * repack->base_src_size;
uint8_t *dst = repack->packet_buffer;
uint32_t new_channel_count = NUM_CHANNELS - squash;
if (squash > 0) {
while (src != end) {
memcpy(dst, src,
repack->bytes_per_sample * new_channel_count);
dst += (new_channel_count * repack->bytes_per_sample);
src += NUM_CHANNELS * repack->bytes_per_sample;
}
}
return 0;
}
void shuffle_8ch(uint8_t *dst, const uint8_t *src, size_t szb, int ch1, int ch2,
int ch3, int ch4, int ch5, int ch6, int ch7, int ch8)
{
/* shuffle 8 channels of audio */
for (size_t i = 0; i < szb; i++) {
dst[0 * szb + i] = src[ch1 * szb + i];
dst[1 * szb + i] = src[ch2 * szb + i];
dst[2 * szb + i] = src[ch3 * szb + i];
dst[3 * szb + i] = src[ch4 * szb + i];
dst[4 * szb + i] = src[ch5 * szb + i];
dst[5 * szb + i] = src[ch6 * szb + i];
dst[6 * szb + i] = src[ch7 * szb + i];
dst[7 * szb + i] = src[ch8 * szb + i];
}
}
/*
* Squash array of 8ch to new channel count and swap FC with LFE
* 16-bit or 32-bit PCM, C version
*/
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->squash_count;
const uint8_t *src = bsrc;
const uint8_t *end = src + (frame_count * repack->base_src_size);
uint8_t *dst = repack->packet_buffer;
uint32_t new_channel_count = NUM_CHANNELS - squash;
if (squash > 0) {
while (src != end) {
shuffle_8ch(dst, src, 4, 0, 1, 3, 2, 4, 5, 6, 7);
dst += (new_channel_count * repack->bytes_per_sample);
src += (NUM_CHANNELS * repack->bytes_per_sample);
}
}
return 0;
}
#endif
int audio_repack_init(struct audio_repack *repack,
audio_repack_mode_t repack_mode, uint8_t bits_per_sample)
{
memset(repack, 0, sizeof(*repack));
if (bits_per_sample != 16 && bits_per_sample != 32)
return -1;
int _audio_repack_ch[9] = {2, 3, 4, 5, 6, 5, 6, 8, 8};
int bytes_per_sample = (bits_per_sample / 8);
repack->bytes_per_sample = bytes_per_sample;
repack->base_src_size = NUM_CHANNELS * bytes_per_sample;
repack->base_dst_size =
_audio_repack_ch[repack_mode] * bytes_per_sample;
uint32_t squash_count = NUM_CHANNELS - _audio_repack_ch[repack_mode];
repack->pad_dst_size = squash_count * bytes_per_sample;
repack->squash_count = squash_count;
#ifdef USE_SIMD
if (bits_per_sample == 16) {
repack->repack_func = &repack_squash16;
if (repack_mode == repack_mode_8to5ch_swap ||
repack_mode == repack_mode_8to6ch_swap ||
repack_mode == repack_mode_8ch_swap)
repack->repack_func = &repack_squash_swap16;
} else if (bits_per_sample == 32) {
repack->repack_func = &repack_squash32;
if (repack_mode == repack_mode_8to5ch_swap ||
repack_mode == repack_mode_8to6ch_swap ||
repack_mode == repack_mode_8ch_swap)
repack->repack_func = &repack_squash_swap32;
}
#else
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;
#endif
return 0;
}
void audio_repack_free(struct audio_repack *repack)
{
if (repack->packet_buffer)
bfree(repack->packet_buffer);
memset(repack, 0, sizeof(*repack));
}
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#include <obs.h>
struct audio_repack;
typedef int (*audio_repack_func_t)(struct audio_repack *, const uint8_t *,
uint32_t);
struct audio_repack {
uint8_t *packet_buffer;
uint32_t packet_size;
uint32_t base_src_size;
uint32_t base_dst_size;
uint32_t pad_dst_size;
uint32_t squash_count;
uint32_t bytes_per_sample;
audio_repack_func_t repack_func;
};
enum _audio_repack_mode {
repack_mode_8to2ch = 0,
repack_mode_8to3ch,
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;
extern int audio_repack_init(struct audio_repack *repack,
audio_repack_mode_t repack_mode,
uint8_t bits_per_sample);
extern void audio_repack_free(struct audio_repack *repack);
#ifdef __cplusplus
}
#endif
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "audio-repack.h"
class AudioRepacker {
struct audio_repack arepack;
public:
inline AudioRepacker(audio_repack_mode_t repack_mode,
int bits_per_sample)
{
audio_repack_init(&arepack, repack_mode, bits_per_sample);
}
inline ~AudioRepacker() { audio_repack_free(&arepack); }
inline int repack(const uint8_t *src, uint32_t frame_size)
{
return (*arepack.repack_func)(&arepack, src, frame_size);
}
inline operator struct audio_repack *() { return &arepack; }
inline struct audio_repack *operator->() { return &arepack; }
};
+10
View File
@@ -15,3 +15,13 @@ IOSelect="Select..."
SDITransport="SDI Transport"
SDITransport4K="SDI 4K Transport"
Auto="Auto"
ChannelFormat="Channel"
ChannelFormat.None="None"
ChannelFormat.2_0ch="2ch"
ChannelFormat.2_1ch="2.1ch"
ChannelFormat.4_0ch="4ch"
ChannelFormat.4_1ch="4.1ch"
ChannelFormat.5_1ch="5.1ch"
ChannelFormat.7_1ch="7.1ch"
SwapFC-LFE="Swap FC and LFE"
SwapFC-LFE.Tooltip="Swap Front Center Channel and LFE Channel"