|
| 1 | +// |
| 2 | +// FFmpegChannelLayoutsMapper.swift |
| 3 | +// Aural |
| 4 | +// |
| 5 | +// Copyright © 2021 Kartik Venugopal. All rights reserved. |
| 6 | +// |
| 7 | +// This software is licensed under the MIT software license. |
| 8 | +// See the file "LICENSE" in the project root directory for license terms. |
| 9 | +// |
1 | 10 | import AVFoundation |
2 | 11 |
|
3 | 12 | /// |
4 | | -/// Helps map ffmpeg channel layout identifiers to their corresponding AVFoundation channel layout tags. |
| 13 | +/// Helps map ffmpeg channel layout identifiers to their corresponding **AVFoundation** channel layout tags. |
5 | 14 | /// |
6 | 15 | /// This is required when setting the format for an audio buffer that is to be scheduled for playback, so that |
7 | 16 | /// upmixing / downmixing can be performed correctly. |
8 | 17 | /// |
9 | | -struct ChannelLayouts { |
| 18 | +struct FFmpegChannelLayoutsMapper { |
10 | 19 |
|
11 | 20 | /// |
12 | 21 | /// A comprehensive mapping of ffmpeg layout identifiers to their corresponding AVFoundation channel layout tags. |
@@ -69,11 +78,9 @@ struct ChannelLayouts { |
69 | 78 | // L R C LFE Rls Rrs Ls Rs |
70 | 79 | CH_LAYOUT_7POINT1: kAudioChannelLayoutTag_WAVE_7_1, |
71 | 80 |
|
72 | | - // MARK: The following mappings are not exact, but the closest possible matches. --------------------------------------- |
| 81 | + // MARK: The following mappings are not exact, but the closest possible matches. |
73 | 82 | // NOTE - Some channels may be dropped entirely. |
74 | 83 |
|
75 | | - // TODO: Create custom AudioChannelLayouts and AVAudioChannelLayouts with exact channel mappings |
76 | | - |
77 | 84 | // L R C Cs Ls Rs -> L R C Cs |
78 | 85 | CH_LAYOUT_6POINT0: kAudioChannelLayoutTag_DVD_8, |
79 | 86 |
|
@@ -121,74 +128,18 @@ struct ChannelLayouts { |
121 | 128 | static func mapLayout(ffmpegLayout: Int) -> AVAudioChannelLayout? { |
122 | 129 |
|
123 | 130 | if let layoutTag = layoutsMap[ffmpegLayout] { |
124 | | - |
125 | | - // NOTE - It's safe to force unwrap the optional AVAudioChannelLayout |
126 | | - // because we are using only valid pre-defined channel layout tags. |
127 | | - return AVAudioChannelLayout(layoutTag: layoutTag)! |
| 131 | + return AVAudioChannelLayout(layoutTag: layoutTag) |
128 | 132 | } |
129 | 133 |
|
130 | 134 | return nil |
131 | 135 | } |
132 | 136 |
|
133 | | - /// |
134 | | - /// Provides a human-readable string for a given channel layout. |
135 | | - /// |
136 | | - /// - Parameter channelLayout: The identifier for an ffmpeg channel layout. |
137 | | - /// |
138 | | - /// - Parameter channelCount: The number of channels in **channelLayout**. |
139 | | - /// |
140 | | - /// - returns: A human-readable string describing the given channel layout. |
141 | | - /// |
142 | 137 | static func readableString(for channelLayout: Int64, channelCount: Int32) -> String { |
143 | 138 |
|
144 | 139 | let layoutStringPointer = UnsafeMutablePointer<Int8>.allocate(capacity: 100) |
145 | | - av_get_channel_layout_string(layoutStringPointer, 100, channelCount, UInt64(channelLayout)) |
146 | | - |
147 | 140 | defer {layoutStringPointer.deallocate()} |
148 | 141 |
|
| 142 | + av_get_channel_layout_string(layoutStringPointer, 100, channelCount, UInt64(channelLayout)) |
149 | 143 | return String(cString: layoutStringPointer).replacingOccurrences(of: "(", with: " (").capitalized |
150 | 144 | } |
151 | | - |
152 | | - // MARK: Debugging functions ------------------------------------------------------ |
153 | | - |
154 | | - static func printLayouts() { |
155 | | - |
156 | | - for layout in layoutsMap.keys.sorted(by: {$0 < $1}).map({UInt64($0)}) { |
157 | | - printLayout(layout, av_get_channel_layout_nb_channels(layout)) |
158 | | - } |
159 | | - } |
160 | | - |
161 | | - static func printLayout(_ layout: UInt64, _ channelCount: Int32) { |
162 | | - |
163 | | - let layoutString = UnsafeMutablePointer<Int8>.allocate(capacity: 100) |
164 | | - av_get_channel_layout_string(layoutString, 100, channelCount, layout) |
165 | | - |
166 | | - var channelNames: [String] = [] |
167 | | - for index in 0..<channelCount { |
168 | | - channelNames.append(String(cString: av_get_channel_name(av_channel_layout_extract_channel(UInt64(layout), index)))) |
169 | | - } |
170 | | - |
171 | | - let ls = String(cString: layoutString) |
172 | | - let ffLay = channelNames.joined(separator: " ") |
173 | | - let avfLay = AVFLayout(ffLay) |
174 | | - |
175 | | - print("\nLayout:", layout, ls, ffLay) |
176 | | - print("AVF Layout:", avfLay) |
177 | | - } |
178 | | - |
179 | | - static func AVFLayout(_ lyt: String) -> String { |
180 | | - |
181 | | - return lyt |
182 | | - .replacingOccurrences(of: "BL", with: "Rls") |
183 | | - .replacingOccurrences(of: "BR", with: "Rrs") |
184 | | - .replacingOccurrences(of: "BC", with: "Cs") |
185 | | - .replacingOccurrences(of: "SL", with: "Ls") |
186 | | - .replacingOccurrences(of: "SR", with: "Rs") |
187 | | - .replacingOccurrences(of: "FLC", with: "Lc") |
188 | | - .replacingOccurrences(of: "FRC", with: "Rc") |
189 | | - .replacingOccurrences(of: "FL", with: "L") |
190 | | - .replacingOccurrences(of: "FR", with: "R") |
191 | | - .replacingOccurrences(of: "FC", with: "C") |
192 | | - |
193 | | - } |
194 | 145 | } |
0 commit comments