Files
obs-studio/plugins/coreaudio-encoder/windows-imports.h
Sebastian Beckmann 4ad3df3af8 coreaudio-encoder: Use canonical format enum instead of bitwise or
The enum members being getting the bitwise or here are from different
enums, and bitwise operations on members from different enums are
deprecated in C++20. kAudioFormatFlagsNativeFloatPacked is the
equivalent value (see its defintion), but removes the manual bitwise or.
2025-12-18 17:30:42 -05:00

483 lines
16 KiB
C

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ShlObj.h>
#include <util/dstr.h>
typedef unsigned long UInt32;
typedef signed long SInt32;
typedef signed long long SInt64;
typedef double Float64;
typedef SInt32 OSStatus;
typedef unsigned char Boolean;
typedef UInt32 AudioFormatPropertyID;
enum {
kVariableLengthArray = 1,
};
struct OpaqueAudioConverter;
typedef struct OpaqueAudioConverter *AudioConverterRef;
typedef UInt32 AudioConverterPropertyID;
struct AudioValueRange {
Float64 mMinimum;
Float64 mMaximum;
};
typedef struct AudioValueRange AudioValueRange;
struct AudioBuffer {
UInt32 mNumberChannels;
UInt32 mDataByteSize;
void *mData;
};
typedef struct AudioBuffer AudioBuffer;
struct AudioBufferList {
UInt32 mNumberBuffers;
AudioBuffer mBuffers[kVariableLengthArray];
};
typedef struct AudioBufferList AudioBufferList;
struct AudioStreamBasicDescription {
Float64 mSampleRate;
UInt32 mFormatID;
UInt32 mFormatFlags;
UInt32 mBytesPerPacket;
UInt32 mFramesPerPacket;
UInt32 mBytesPerFrame;
UInt32 mChannelsPerFrame;
UInt32 mBitsPerChannel;
UInt32 mReserved;
};
typedef struct AudioStreamBasicDescription AudioStreamBasicDescription;
struct AudioStreamPacketDescription {
SInt64 mStartOffset;
UInt32 mVariableFramesInPacket;
UInt32 mDataByteSize;
};
typedef struct AudioStreamPacketDescription AudioStreamPacketDescription;
typedef UInt32 AudioChannelLabel;
typedef UInt32 AudioChannelLayoutTag;
struct AudioChannelDescription {
AudioChannelLabel mChannelLabel;
UInt32 mChannelFlags;
float mCoordinates[3];
};
typedef struct AudioChannelDescription AudioChannelDescription;
struct AudioChannelLayout {
AudioChannelLayoutTag mChannelLayoutTag;
UInt32 mChannelBitmap;
UInt32 mNumberChannelDescriptions;
AudioChannelDescription mChannelDescriptions[kVariableLengthArray];
};
typedef struct AudioChannelLayout AudioChannelLayout;
struct AudioConverterPrimeInfo {
UInt32 leadingFrames;
UInt32 trailingFrames;
};
typedef struct AudioConverterPrimeInfo AudioConverterPrimeInfo;
typedef OSStatus (*AudioConverterComplexInputDataProc)(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData);
enum {
kAudioCodecPropertyNameCFString = 'lnam',
kAudioCodecPropertyManufacturerCFString = 'lmak',
kAudioCodecPropertyFormatCFString = 'lfor',
//kAudioCodecPropertyHasVariablePacketByteSizes = 'vpk?',
kAudioCodecPropertySupportedInputFormats = 'ifm#',
kAudioCodecPropertySupportedOutputFormats = 'ofm#',
kAudioCodecPropertyAvailableInputSampleRates = 'aisr',
kAudioCodecPropertyAvailableOutputSampleRates = 'aosr',
kAudioCodecPropertyAvailableBitRateRange = 'abrt',
kAudioCodecPropertyMinimumNumberInputPackets = 'mnip',
kAudioCodecPropertyMinimumNumberOutputPackets = 'mnop',
kAudioCodecPropertyAvailableNumberChannels = 'cmnc',
kAudioCodecPropertyDoesSampleRateConversion = 'lmrc',
kAudioCodecPropertyAvailableInputChannelLayoutTags = 'aicl',
kAudioCodecPropertyAvailableOutputChannelLayoutTags = 'aocl',
kAudioCodecPropertyInputFormatsForOutputFormat = 'if4o',
kAudioCodecPropertyOutputFormatsForInputFormat = 'of4i',
kAudioCodecPropertyFormatInfo = 'acfi',
};
enum {
kAudioCodecPropertyInputBufferSize = 'tbuf',
kAudioCodecPropertyPacketFrameSize = 'pakf',
kAudioCodecPropertyMaximumPacketByteSize = 'pakb',
kAudioCodecPropertyCurrentInputFormat = 'ifmt',
kAudioCodecPropertyCurrentOutputFormat = 'ofmt',
kAudioCodecPropertyMagicCookie = 'kuki',
kAudioCodecPropertyUsedInputBufferSize = 'ubuf',
kAudioCodecPropertyIsInitialized = 'init',
kAudioCodecPropertyCurrentTargetBitRate = 'brat',
kAudioCodecPropertyCurrentInputSampleRate = 'cisr',
kAudioCodecPropertyCurrentOutputSampleRate = 'cosr',
kAudioCodecPropertyQualitySetting = 'srcq',
kAudioCodecPropertyApplicableBitRateRange = 'brta',
kAudioCodecPropertyApplicableInputSampleRates = 'isra',
kAudioCodecPropertyApplicableOutputSampleRates = 'osra',
kAudioCodecPropertyPaddedZeros = 'pad0',
kAudioCodecPropertyPrimeMethod = 'prmm',
kAudioCodecPropertyPrimeInfo = 'prim',
kAudioCodecPropertyCurrentInputChannelLayout = 'icl ',
kAudioCodecPropertyCurrentOutputChannelLayout = 'ocl ',
kAudioCodecPropertySettings = 'acs ',
kAudioCodecPropertyFormatList = 'acfl',
kAudioCodecPropertyBitRateControlMode = 'acbf',
kAudioCodecPropertySoundQualityForVBR = 'vbrq',
kAudioCodecPropertyMinimumDelayMode = 'mdel'
};
enum {
kAudioCodecBitRateControlMode_Constant = 0,
kAudioCodecBitRateControlMode_LongTermAverage = 1,
kAudioCodecBitRateControlMode_VariableConstrained = 2,
kAudioCodecBitRateControlMode_Variable = 3,
};
enum {
kAudioFormatLinearPCM = 'lpcm',
kAudioFormatAC3 = 'ac-3',
kAudioFormat60958AC3 = 'cac3',
kAudioFormatAppleIMA4 = 'ima4',
kAudioFormatMPEG4AAC = 'aac ',
kAudioFormatMPEG4CELP = 'celp',
kAudioFormatMPEG4HVXC = 'hvxc',
kAudioFormatMPEG4TwinVQ = 'twvq',
kAudioFormatMACE3 = 'MAC3',
kAudioFormatMACE6 = 'MAC6',
kAudioFormatULaw = 'ulaw',
kAudioFormatALaw = 'alaw',
kAudioFormatQDesign = 'QDMC',
kAudioFormatQDesign2 = 'QDM2',
kAudioFormatQUALCOMM = 'Qclp',
kAudioFormatMPEGLayer1 = '.mp1',
kAudioFormatMPEGLayer2 = '.mp2',
kAudioFormatMPEGLayer3 = '.mp3',
kAudioFormatTimeCode = 'time',
kAudioFormatMIDIStream = 'midi',
kAudioFormatParameterValueStream = 'apvs',
kAudioFormatAppleLossless = 'alac',
kAudioFormatMPEG4AAC_HE = 'aach',
kAudioFormatMPEG4AAC_LD = 'aacl',
kAudioFormatMPEG4AAC_ELD = 'aace',
kAudioFormatMPEG4AAC_ELD_SBR = 'aacf',
kAudioFormatMPEG4AAC_ELD_V2 = 'aacg',
kAudioFormatMPEG4AAC_HE_V2 = 'aacp',
kAudioFormatMPEG4AAC_Spatial = 'aacs',
kAudioFormatAMR = 'samr',
kAudioFormatAudible = 'AUDB',
kAudioFormatiLBC = 'ilbc',
kAudioFormatDVIIntelIMA = 0x6D730011,
kAudioFormatMicrosoftGSM = 0x6D730031,
kAudioFormatAES3 = 'aes3',
};
enum {
kAudioFormatFlagIsFloat = (1L << 0),
kAudioFormatFlagIsBigEndian = (1L << 1),
kAudioFormatFlagIsSignedInteger = (1L << 2),
kAudioFormatFlagIsPacked = (1L << 3),
kAudioFormatFlagIsAlignedHigh = (1L << 4),
kAudioFormatFlagIsNonInterleaved = (1L << 5),
kAudioFormatFlagIsNonMixable = (1L << 6),
kAudioFormatFlagsAreAllClear = (1L << 31),
kLinearPCMFormatFlagIsFloat = kAudioFormatFlagIsFloat,
kLinearPCMFormatFlagIsBigEndian = kAudioFormatFlagIsBigEndian,
kLinearPCMFormatFlagIsSignedInteger = kAudioFormatFlagIsSignedInteger,
kLinearPCMFormatFlagIsPacked = kAudioFormatFlagIsPacked,
kLinearPCMFormatFlagIsAlignedHigh = kAudioFormatFlagIsAlignedHigh,
kLinearPCMFormatFlagIsNonInterleaved = kAudioFormatFlagIsNonInterleaved,
kLinearPCMFormatFlagIsNonMixable = kAudioFormatFlagIsNonMixable,
kLinearPCMFormatFlagsAreAllClear = kAudioFormatFlagsAreAllClear,
kAppleLosslessFormatFlag_16BitSourceData = 1,
kAppleLosslessFormatFlag_20BitSourceData = 2,
kAppleLosslessFormatFlag_24BitSourceData = 3,
kAppleLosslessFormatFlag_32BitSourceData = 4,
};
enum {
kAudioFormatFlagsNativeEndian = 0,
kAudioFormatFlagsNativeFloatPacked = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian |
kAudioFormatFlagIsPacked
};
enum {
// AudioStreamBasicDescription structure properties
kAudioFormatProperty_FormatInfo = 'fmti',
kAudioFormatProperty_FormatName = 'fnam',
kAudioFormatProperty_EncodeFormatIDs = 'acof',
kAudioFormatProperty_DecodeFormatIDs = 'acif',
kAudioFormatProperty_FormatList = 'flst',
kAudioFormatProperty_ASBDFromESDS = 'essd',
kAudioFormatProperty_ChannelLayoutFromESDS = 'escl',
kAudioFormatProperty_OutputFormatList = 'ofls',
kAudioFormatProperty_Encoders = 'aven',
kAudioFormatProperty_Decoders = 'avde',
kAudioFormatProperty_FormatIsVBR = 'fvbr',
kAudioFormatProperty_FormatIsExternallyFramed = 'fexf',
kAudioFormatProperty_AvailableEncodeBitRates = 'aebr',
kAudioFormatProperty_AvailableEncodeSampleRates = 'aesr',
kAudioFormatProperty_AvailableEncodeChannelLayoutTags = 'aecl',
kAudioFormatProperty_AvailableEncodeNumberChannels = 'avnc',
kAudioFormatProperty_ASBDFromMPEGPacket = 'admp',
//
// AudioChannelLayout structure properties
kAudioFormatProperty_BitmapForLayoutTag = 'bmtg',
kAudioFormatProperty_MatrixMixMap = 'mmap',
kAudioFormatProperty_ChannelMap = 'chmp',
kAudioFormatProperty_NumberOfChannelsForLayout = 'nchm',
kAudioFormatProperty_ValidateChannelLayout = 'vacl',
kAudioFormatProperty_ChannelLayoutForTag = 'cmpl',
kAudioFormatProperty_TagForChannelLayout = 'cmpt',
kAudioFormatProperty_ChannelLayoutName = 'lonm',
kAudioFormatProperty_ChannelLayoutSimpleName = 'lsnm',
kAudioFormatProperty_ChannelLayoutForBitmap = 'cmpb',
kAudioFormatProperty_ChannelName = 'cnam',
kAudioFormatProperty_ChannelShortName = 'csnm',
kAudioFormatProperty_TagsForNumberOfChannels = 'tagc',
kAudioFormatProperty_PanningMatrix = 'panm',
kAudioFormatProperty_BalanceFade = 'balf',
//
// ID3 tag (MP3 metadata) properties
kAudioFormatProperty_ID3TagSize = 'id3s',
kAudioFormatProperty_ID3TagToDictionary = 'id3d',
};
enum {
kAudioConverterPropertyMinimumInputBufferSize = 'mibs',
kAudioConverterPropertyMinimumOutputBufferSize = 'mobs',
kAudioConverterPropertyMaximumInputBufferSize = 'xibs',
kAudioConverterPropertyMaximumInputPacketSize = 'xips',
kAudioConverterPropertyMaximumOutputPacketSize = 'xops',
kAudioConverterPropertyCalculateInputBufferSize = 'cibs',
kAudioConverterPropertyCalculateOutputBufferSize = 'cobs',
kAudioConverterPropertyInputCodecParameters = 'icdp',
kAudioConverterPropertyOutputCodecParameters = 'ocdp',
kAudioConverterSampleRateConverterAlgorithm = 'srci',
kAudioConverterSampleRateConverterComplexity = 'srca',
kAudioConverterSampleRateConverterQuality = 'srcq',
kAudioConverterSampleRateConverterInitialPhase = 'srcp',
kAudioConverterCodecQuality = 'cdqu',
kAudioConverterPrimeMethod = 'prmm',
kAudioConverterPrimeInfo = 'prim',
kAudioConverterChannelMap = 'chmp',
kAudioConverterDecompressionMagicCookie = 'dmgc',
kAudioConverterCompressionMagicCookie = 'cmgc',
kAudioConverterEncodeBitRate = 'brat',
kAudioConverterEncodeAdjustableSampleRate = 'ajsr',
kAudioConverterInputChannelLayout = 'icl ',
kAudioConverterOutputChannelLayout = 'ocl ',
kAudioConverterApplicableEncodeBitRates = 'aebr',
kAudioConverterAvailableEncodeBitRates = 'vebr',
kAudioConverterApplicableEncodeSampleRates = 'aesr',
kAudioConverterAvailableEncodeSampleRates = 'vesr',
kAudioConverterAvailableEncodeChannelLayoutTags = 'aecl',
kAudioConverterCurrentOutputStreamDescription = 'acod',
kAudioConverterCurrentInputStreamDescription = 'acid',
kAudioConverterPropertySettings = 'acps',
kAudioConverterPropertyBitDepthHint = 'acbd',
kAudioConverterPropertyFormatList = 'flst',
};
enum {
kAudioConverterQuality_Max = 0x7F,
kAudioConverterQuality_High = 0x60,
kAudioConverterQuality_Medium = 0x40,
kAudioConverterQuality_Low = 0x20,
kAudioConverterQuality_Min = 0,
};
enum {
kAudio_UnimplementedError = -4,
kAudio_FileNotFoundError = -43,
kAudio_FilePermissionError = -54,
kAudio_TooManyFilesOpenError = -42,
kAudio_BadFilePathError = '!pth', // 0x21707468, 561017960
kAudio_ParamError = -50,
kAudio_MemFullError = -108,
kAudioConverterErr_FormatNotSupported = 'fmt?',
kAudioConverterErr_OperationNotSupported = 0x6F703F3F,
// 'op??', integer used because of trigraph
kAudioConverterErr_PropertyNotSupported = 'prop',
kAudioConverterErr_InvalidInputSize = 'insz',
kAudioConverterErr_InvalidOutputSize = 'otsz',
// e.g. byte size is not a multiple of the frame size
kAudioConverterErr_UnspecifiedError = 'what',
kAudioConverterErr_BadPropertySizeError = '!siz',
kAudioConverterErr_RequiresPacketDescriptionsError = '!pkd',
kAudioConverterErr_InputSampleRateOutOfRange = '!isr',
kAudioConverterErr_OutputSampleRateOutOfRange = '!osr',
};
typedef OSStatus (*AudioConverterNew_t)(const AudioStreamBasicDescription *inSourceFormat,
const AudioStreamBasicDescription *inDestinationFormat,
AudioConverterRef *outAudioConverter);
typedef OSStatus (*AudioConverterDispose_t)(AudioConverterRef inAudioConverter);
typedef OSStatus (*AudioConverterReset_t)(AudioConverterRef inAudioConverter);
typedef OSStatus (*AudioConverterGetProperty_t)(AudioConverterRef inAudioConverter,
AudioConverterPropertyID inPropertyID, UInt32 *ioPropertyDataSize,
void *outPropertyData);
typedef OSStatus (*AudioConverterGetPropertyInfo_t)(AudioConverterRef inAudioConverter,
AudioConverterPropertyID inPropertyID, UInt32 *outSize,
Boolean *outWritable);
typedef OSStatus (*AudioConverterSetProperty_t)(AudioConverterRef inAudioConverter,
AudioConverterPropertyID inPropertyID, UInt32 inPropertyDataSize,
const void *inPropertyData);
typedef OSStatus (*AudioConverterFillComplexBuffer_t)(AudioConverterRef inAudioConverter,
AudioConverterComplexInputDataProc inInputDataProc,
void *inInputDataProcUserData, UInt32 *ioOutputDataPacketSize,
AudioBufferList *outOutputData,
AudioStreamPacketDescription *outPacketDescription);
typedef OSStatus (*AudioFormatGetProperty_t)(AudioFormatPropertyID inPropertyID, UInt32 inSpecifierSize,
const void *inSpecifier, UInt32 *ioPropertyDataSize,
void *outPropertyData);
typedef OSStatus (*AudioFormatGetPropertyInfo_t)(AudioFormatPropertyID inPropertyID, UInt32 inSpecifierSize,
const void *inSpecifier, UInt32 *outPropertyDataSize);
static AudioConverterNew_t AudioConverterNew = NULL;
static AudioConverterDispose_t AudioConverterDispose = NULL;
static AudioConverterReset_t AudioConverterReset = NULL;
static AudioConverterGetProperty_t AudioConverterGetProperty = NULL;
static AudioConverterGetPropertyInfo_t AudioConverterGetPropertyInfo = NULL;
static AudioConverterSetProperty_t AudioConverterSetProperty = NULL;
static AudioConverterFillComplexBuffer_t AudioConverterFillComplexBuffer = NULL;
static AudioFormatGetProperty_t AudioFormatGetProperty = NULL;
static AudioFormatGetPropertyInfo_t AudioFormatGetPropertyInfo = NULL;
static HMODULE audio_toolbox = NULL;
static void release_lib(void)
{
if (audio_toolbox) {
FreeLibrary(audio_toolbox);
audio_toolbox = NULL;
}
}
static bool load_from_shell_path(REFKNOWNFOLDERID rfid, const wchar_t *subpath)
{
wchar_t *sh_path;
if (SHGetKnownFolderPath(rfid, 0, NULL, &sh_path) != S_OK) {
CA_LOG(LOG_WARNING, "Could not retrieve shell path");
return false;
}
wchar_t path[MAX_PATH];
_snwprintf(path, MAX_PATH, L"%s\\%s", sh_path, subpath);
CoTaskMemFree(sh_path);
SetDllDirectory(path);
audio_toolbox = LoadLibraryW(L"CoreAudioToolbox.dll");
SetDllDirectory(nullptr);
return !!audio_toolbox;
}
static bool load_lib(void)
{
/* -------------------------------------------- */
/* attempt to load from path */
audio_toolbox = LoadLibraryW(L"CoreAudioToolbox.dll");
if (!!audio_toolbox)
return true;
/* -------------------------------------------- */
/* attempt to load from known install locations */
struct path_list_t {
REFKNOWNFOLDERID rfid;
const wchar_t *subpath;
};
path_list_t path_list[] = {
{FOLDERID_ProgramFilesCommon, L"Apple\\Apple Application Support"},
{FOLDERID_ProgramFiles, L"iTunes"},
};
for (auto &val : path_list) {
if (load_from_shell_path(val.rfid, val.subpath)) {
return true;
}
}
return false;
}
static void unload_core_audio(void)
{
AudioConverterNew = NULL;
AudioConverterDispose = NULL;
AudioConverterReset = NULL;
AudioConverterGetProperty = NULL;
AudioConverterGetPropertyInfo = NULL;
AudioConverterSetProperty = NULL;
AudioConverterFillComplexBuffer = NULL;
AudioFormatGetProperty = NULL;
AudioFormatGetPropertyInfo = NULL;
release_lib();
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4706)
#endif
static bool load_core_audio(void)
{
if (!load_lib())
return false;
#define LOAD_SYM_FROM_LIB(sym, lib, dll) \
if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \
DWORD err = GetLastError(); \
CA_LOG(LOG_ERROR, "Couldn't load " #sym " from " dll ": %lu (0x%lx)", err, err); \
goto unload_everything; \
}
#define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, audio_toolbox, "CoreAudioToolbox.dll")
LOAD_SYM(AudioConverterNew);
LOAD_SYM(AudioConverterDispose);
LOAD_SYM(AudioConverterReset);
LOAD_SYM(AudioConverterGetProperty);
LOAD_SYM(AudioConverterGetPropertyInfo);
LOAD_SYM(AudioConverterSetProperty);
LOAD_SYM(AudioConverterFillComplexBuffer);
LOAD_SYM(AudioFormatGetProperty);
LOAD_SYM(AudioFormatGetPropertyInfo);
#undef LOAD_SYM
return true;
unload_everything:
unload_core_audio();
return false;
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif