From 22d8b8c13235bd079f891515e46e702f1128cc76 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Mon, 7 Feb 2022 02:06:51 -0800 Subject: [PATCH] Implement channel config fields for inputs This implements channel masks for inputs where applicable, namely the CoreAudio decoder, FFmpeg, FLAC, and WavPack. All others will still use guessing from the channel number. Signed-off-by: Christopher Snowhill --- Plugins/CoreAudio/CoreAudioDecoder.h | 1 + Plugins/CoreAudio/CoreAudioDecoder.m | 50 ++++++++++++++++++++++++++++ Plugins/FFMPEG/FFMPEGDecoder.h | 1 + Plugins/FFMPEG/FFMPEGDecoder.m | 2 ++ Plugins/Flac/FlacDecoder.h | 1 + Plugins/Flac/FlacDecoder.m | 35 +++++++++++++++++-- Plugins/WavPack/WavPackDecoder.h | 1 + Plugins/WavPack/WavPackDecoder.m | 2 ++ 8 files changed, 90 insertions(+), 3 deletions(-) diff --git a/Plugins/CoreAudio/CoreAudioDecoder.h b/Plugins/CoreAudio/CoreAudioDecoder.h index 4c5919f73..39e1d0766 100644 --- a/Plugins/CoreAudio/CoreAudioDecoder.h +++ b/Plugins/CoreAudio/CoreAudioDecoder.h @@ -43,6 +43,7 @@ int bitsPerSample; BOOL floatingPoint; int channels; + uint32_t channelConfig; float frequency; long totalFrames; diff --git a/Plugins/CoreAudio/CoreAudioDecoder.m b/Plugins/CoreAudio/CoreAudioDecoder.m index 7eb0af21a..cb64eb6a9 100644 --- a/Plugins/CoreAudio/CoreAudioDecoder.m +++ b/Plugins/CoreAudio/CoreAudioDecoder.m @@ -28,6 +28,33 @@ - (BOOL)readInfoFromExtAudioFileRef; @end +static int ffat_get_channel_id(AudioChannelLabel label) { + if(label == 0) + return -1; + else if(label <= kAudioChannelLabel_LFEScreen) + return label - 1; + else if(label <= kAudioChannelLabel_RightSurround) + return label + 4; + else if(label <= kAudioChannelLabel_CenterSurround) + return label + 1; + else if(label <= kAudioChannelLabel_RightSurroundDirect) + return label + 23; + else if(label <= kAudioChannelLabel_TopBackRight) + return label - 1; + else if(label < kAudioChannelLabel_RearSurroundLeft) + return -1; + else if(label <= kAudioChannelLabel_RearSurroundRight) + return label - 29; + else if(label <= kAudioChannelLabel_RightWide) + return label - 4; + else if(label == kAudioChannelLabel_LFE2) + return -1; + else if(label == kAudioChannelLabel_Mono) + return 2; // Front center + else + return -1; +} + static OSStatus readProc(void *clientData, SInt64 position, UInt32 requestCount, @@ -177,6 +204,28 @@ static SInt64 getSizeProc(void *clientData) { return NO; } + err = AudioFileGetPropertyInfo(afi, kAudioFilePropertyChannelLayout, &size, NULL); + if(err != noErr || size == 0) { + err = ExtAudioFileDispose(_in); + return NO; + } + AudioChannelLayout *acl = malloc(size); + err = AudioFileGetProperty(afi, kAudioFilePropertyChannelLayout, &size, acl); + if(err != noErr) { + free(acl); + err = ExtAudioFileDispose(_in); + return NO; + } + + uint32_t config = 0; + for(uint32_t i = 0; i < acl->mNumberChannelDescriptions; ++i) { + int channelNumber = ffat_get_channel_id(acl->mChannelDescriptions[i].mChannelLabel); + if(channelNumber >= 0) + config |= 1 << channelNumber; + } + + channelConfig = config; + bitrate = (_bitrate + 500) / 1000; CFStringRef formatName; @@ -330,6 +379,7 @@ static SInt64 getSizeProc(void *clientData) { - (NSDictionary *)properties { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels], @"channels", + [NSNumber numberWithInt:channelConfig], @"channelConfig", [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample", [NSNumber numberWithBool:floatingPoint], @"floatingPoint", [NSNumber numberWithInt:bitrate], @"bitrate", diff --git a/Plugins/FFMPEG/FFMPEGDecoder.h b/Plugins/FFMPEG/FFMPEGDecoder.h index 2ee76e21b..b3681a75e 100644 --- a/Plugins/FFMPEG/FFMPEGDecoder.h +++ b/Plugins/FFMPEG/FFMPEGDecoder.h @@ -17,6 +17,7 @@ id source; BOOL seekable; int channels; + uint32_t channelConfig; int bitsPerSample; BOOL floatingPoint; BOOL lossy; diff --git a/Plugins/FFMPEG/FFMPEGDecoder.m b/Plugins/FFMPEG/FFMPEGDecoder.m index 59ae5a564..d060c0242 100644 --- a/Plugins/FFMPEG/FFMPEGDecoder.m +++ b/Plugins/FFMPEG/FFMPEGDecoder.m @@ -249,6 +249,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { frequency = codecCtx->sample_rate; channels = codecCtx->channels; + channelConfig = (uint32_t)codecCtx->channel_layout; floatingPoint = NO; switch(codecCtx->sample_fmt) { @@ -616,6 +617,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { - (NSDictionary *)properties { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels], @"channels", + [NSNumber numberWithInt:channelConfig], @"channelConfig", [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample", [NSNumber numberWithBool:(bitsPerSample == 8)], @"Unsigned", [NSNumber numberWithFloat:frequency], @"sampleRate", diff --git a/Plugins/Flac/FlacDecoder.h b/Plugins/Flac/FlacDecoder.h index 94b011db9..2d75f2e8f 100644 --- a/Plugins/Flac/FlacDecoder.h +++ b/Plugins/Flac/FlacDecoder.h @@ -26,6 +26,7 @@ int bitsPerSample; int channels; + uint32_t channelConfig; float frequency; long totalFrames; diff --git a/Plugins/Flac/FlacDecoder.m b/Plugins/Flac/FlacDecoder.m index e90c47755..5ccdccfb1 100644 --- a/Plugins/Flac/FlacDecoder.m +++ b/Plugins/Flac/FlacDecoder.m @@ -12,6 +12,28 @@ @implementation FlacDecoder +static const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK"; + +static FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask) { + int offset; + uint32_t val; + char *p; + FLAC__ASSERT(object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 > (offset = FLAC__metadata_object_vorbiscomment_find_entry_from(object, /*offset=*/0, CHANNEL_MASK_TAG))) + return false; + if(object->data.vorbis_comment.comments[offset].length < strlen(CHANNEL_MASK_TAG) + 4) + return false; + if(0 == (p = strchr((const char *)object->data.vorbis_comment.comments[offset].entry, '='))) /* should never happen, but just in case */ + return false; + if(strncasecmp(p, "=0x", 3)) + return false; + if(sscanf(p + 3, "%x", &val) != 1) + return false; + *channel_mask = val; + return true; +} + FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte blockBuffer[], size_t *bytes, void *client_data) { FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data; long bytesRead = [[flacDecoder source] read:blockBuffer amount:*bytes]; @@ -168,11 +190,12 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta flacDecoder->totalFrames = metadata->data.stream_info.total_samples; - [flacDecoder willChangeValueForKey:@"properties"]; - [flacDecoder didChangeValueForKey:@"properties"]; - flacDecoder->hasStreamInfo = YES; } + + if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + (void)flac__utils_get_channel_mask_tag(metadata, &flacDecoder->channelConfig); + } } void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { @@ -208,6 +231,11 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS FLAC__stream_decoder_process_until_end_of_metadata(decoder); + if(hasStreamInfo) { + [self willChangeValueForKey:@"properties"]; + [self didChangeValueForKey:@"properties"]; + } + blockBuffer = malloc(SAMPLE_blockBuffer_SIZE); return YES; @@ -305,6 +333,7 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS - (NSDictionary *)properties { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels], @"channels", + [NSNumber numberWithInt:channelConfig], @"channelConfig", [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample", [NSNumber numberWithFloat:frequency], @"sampleRate", [NSNumber numberWithDouble:totalFrames], @"totalFrames", diff --git a/Plugins/WavPack/WavPackDecoder.h b/Plugins/WavPack/WavPackDecoder.h index 3987d78ba..e635dfa3e 100644 --- a/Plugins/WavPack/WavPackDecoder.h +++ b/Plugins/WavPack/WavPackDecoder.h @@ -39,6 +39,7 @@ int bitsPerSample; int channels; + uint32_t channelConfig; BOOL floatingPoint; int bitrate; float frequency; diff --git a/Plugins/WavPack/WavPackDecoder.m b/Plugins/WavPack/WavPackDecoder.m index 97613845e..ccdabbdfc 100644 --- a/Plugins/WavPack/WavPackDecoder.m +++ b/Plugins/WavPack/WavPackDecoder.m @@ -144,6 +144,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) { } channels = WavpackGetNumChannels(wpc); + channelConfig = WavpackGetChannelMask(wpc); bitsPerSample = WavpackGetBitsPerSample(wpc); frequency = WavpackGetSampleRate(wpc); @@ -282,6 +283,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) { - (NSDictionary *)properties { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels], @"channels", + [NSNumber numberWithInt:channelConfig], @"channelConfig", [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample", [NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithFloat:frequency], @"sampleRate",