diff options
author | Doris Verria <doris.verria@qt.io> | 2022-03-28 02:09:24 +0200 |
---|---|---|
committer | Doris Verria <doris.verria@qt.io> | 2022-04-05 13:17:40 +0200 |
commit | 934c9b6dee03b8b71bd71f06d03185c56f94bd76 (patch) | |
tree | 4b2a8cac9d378761372e579207dec69cd07bb839 | |
parent | 315d0f848a67c33390e787c094c16d496601a042 (diff) | |
download | qtmultimedia-934c9b6dee03b8b71bd71f06d03185c56f94bd76.tar.gz |
darwin: Don't specify source format hint for audio recording
We were initializing the audio writer input with a format hint equal
to the audio capture device's active format. This is wrong as we
can't ensure that the captured audio buffers will be in that same
format. This caused failure in recording because the captured audio
buffers had the kAudioFormatFlagIsNonInterleaved set, while the format
hint didn't, causing the internal calls to the AudioConverter to fail
with errors.
To fix, do not specify a format hint but instead setup the audio
settings dictionary with the necessary keys. Force a default
value for AVNumberOfChannelsKey since it is now required, and for
recording with more than 2 channels, provide a supported channel
layout.
Fixes: QTBUG-98262
Done-with: Vladimir Belyavsky <belyavskyv@gmail.com>
Change-Id: I537d82e729c91a66d85aaa61c563a1ecd1a91af3
Reviewed-by: Vladimir Belyavsky <belyavskyv@gmail.com>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit 980c145069c589085b4dee4b4c2b69e3b1a0adc3)
Reviewed-by: Doris Verria <doris.verria@qt.io>
4 files changed, 55 insertions, 18 deletions
diff --git a/src/multimedia/platform/darwin/camera/avfcamerautility.mm b/src/multimedia/platform/darwin/camera/avfcamerautility.mm index 444162523..f5c90bb77 100644 --- a/src/multimedia/platform/darwin/camera/avfcamerautility.mm +++ b/src/multimedia/platform/darwin/camera/avfcamerautility.mm @@ -711,4 +711,37 @@ std::optional<QList<UInt32>> qt_supported_channel_counts_for_format(int codecId) return result; } +QList<UInt32> qt_supported_channel_layout_tags_for_format(int codecId, int noChannels) +{ + QList<UInt32> result; + AudioStreamBasicDescription sf = {}; + sf.mFormatID = codecId; + sf.mChannelsPerFrame = noChannels; + UInt32 size; + OSStatus err = AudioFormatGetPropertyInfo( + kAudioFormatProperty_AvailableEncodeChannelLayoutTags, + sizeof(sf), + &sf, + &size); + + if (err != noErr) + return result; + + UInt32 noTags = (UInt32)size / sizeof(UInt32); + AudioChannelLayoutTag tagsArr[noTags]; + + err = AudioFormatGetProperty(kAudioFormatProperty_AvailableEncodeChannelLayoutTags, + sizeof(sf), + &sf, + &size, + tagsArr); + if (err != noErr) + return result; + + for (UInt32 i = 0; i < noTags; i++) + result << tagsArr[i]; + + return result; +} + QT_END_NAMESPACE diff --git a/src/multimedia/platform/darwin/camera/avfcamerautility_p.h b/src/multimedia/platform/darwin/camera/avfcamerautility_p.h index 26a023be9..00ff4bb29 100644 --- a/src/multimedia/platform/darwin/camera/avfcamerautility_p.h +++ b/src/multimedia/platform/darwin/camera/avfcamerautility_p.h @@ -195,6 +195,7 @@ void qt_set_framerate_limits(AVCaptureDevice *captureDevice, AVCaptureConnection QList<AudioValueRange> qt_supported_sample_rates_for_format(int codecId); QList<AudioValueRange> qt_supported_bit_rates_for_format(int codecId); std::optional<QList<UInt32>> qt_supported_channel_counts_for_format(int codecId); +QList<UInt32> qt_supported_channel_layout_tags_for_format(int codecId, int noChannels); QT_END_NAMESPACE diff --git a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm b/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm index 61f248c72..243f8455a 100644 --- a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm +++ b/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm @@ -529,12 +529,8 @@ using AVFAtomicInt64 = QAtomicInteger<qint64>; m_audioWriterInput.reset(); if (m_audioQueue) { - CMFormatDescriptionRef sourceFormat = session->audioCaptureDevice() - ? session->audioCaptureDevice().activeFormat.formatDescription - : 0; m_audioWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio - outputSettings:m_audioSettings - sourceFormatHint:sourceFormat]); + outputSettings:m_audioSettings]); if (!m_audioWriterInput) { qWarning() << Q_FUNC_INFO << "failed to create audio writer input"; // But we still can record video. diff --git a/src/multimedia/platform/darwin/camera/avfmediaencoder.mm b/src/multimedia/platform/darwin/camera/avfmediaencoder.mm index 87e7a357f..b669dd960 100644 --- a/src/multimedia/platform/darwin/camera/avfmediaencoder.mm +++ b/src/multimedia/platform/darwin/camera/avfmediaencoder.mm @@ -139,12 +139,14 @@ static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettin { NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + // Codec int codecId = QDarwinFormatInfo::audioFormatForCodec(encoderSettings.mediaFormat().audioCodec()); [settings setObject:[NSNumber numberWithInt:codecId] forKey:AVFormatIDKey]; // Setting AVEncoderQualityKey is not allowed when format ID is alac or lpcm if (codecId != kAudioFormatAppleLossless && codecId != kAudioFormatLinearPCM && encoderSettings.encodingMode() == QMediaRecorder::ConstantQualityEncoding) { + // AudioQuality int quality; switch (encoderSettings.quality()) { case QMediaRecorder::VeryLowQuality: @@ -166,6 +168,7 @@ static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettin } [settings setObject:[NSNumber numberWithInt:quality] forKey:AVEncoderAudioQualityKey]; } else { + // BitRate bool isBitRateSupported = false; int bitRate = encoderSettings.audioBitRate(); if (bitRate > 0) { @@ -183,6 +186,7 @@ static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettin } } + // SampleRate int sampleRate = encoderSettings.audioSampleRate(); bool isSampleRateSupported = false; if (sampleRate >= 8000 && sampleRate <= 192000) { @@ -194,7 +198,11 @@ static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettin } } } + if (!isSampleRateSupported) + sampleRate = 44100; + [settings setObject:[NSNumber numberWithInt:sampleRate] forKey:AVSampleRateKey]; + // Channels int channelCount = encoderSettings.audioChannelCount(); bool isChannelCountSupported = false; if (channelCount > 0) { @@ -213,16 +221,20 @@ static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettin } } -#ifdef Q_OS_IOS - // Some keys are mandatory only on iOS - if (!isSampleRateSupported) { - sampleRate = 44100; - isSampleRateSupported = true; +if (isChannelCountSupported && channelCount > 2) { + AudioChannelLayout channelLayout; + memset(&channelLayout, 0, sizeof(AudioChannelLayout)); + auto channelLayoutTags = qt_supported_channel_layout_tags_for_format(codecId, channelCount); + if (channelLayoutTags.size()) { + channelLayout.mChannelLayoutTag = channelLayoutTags.first(); + [settings setObject:[NSData dataWithBytes: &channelLayout length: sizeof(channelLayout)] forKey:AVChannelLayoutKey]; + } else { + isChannelCountSupported = false; + } } - if (!isChannelCountSupported) { + if (!isChannelCountSupported) channelCount = 2; - isChannelCountSupported = true; - } + [settings setObject:[NSNumber numberWithInt:channelCount] forKey:AVNumberOfChannelsKey]; if (codecId == kAudioFormatAppleLossless) [settings setObject:[NSNumber numberWithInt:24] forKey:AVEncoderBitDepthHintKey]; @@ -233,11 +245,6 @@ static NSDictionary *avfAudioSettings(const QMediaEncoderSettings &encoderSettin [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsFloatKey]; [settings setObject:[NSNumber numberWithInt:NO] forKey:AVLinearPCMIsNonInterleaved]; } -#endif - if (isSampleRateSupported) - [settings setObject:[NSNumber numberWithInt:sampleRate] forKey:AVSampleRateKey]; - if (isChannelCountSupported) - [settings setObject:[NSNumber numberWithInt:channelCount] forKey:AVNumberOfChannelsKey]; return settings; } |