react-native-compressor 1.8.16 → 1.8.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -9
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +58 -27
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt +49 -0
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt +2 -6
- package/android/src/main/java/com/reactnativecompressor/Utils/createVideoThumbnail.kt +0 -2
- package/ios/Audio/AudioHelper.swift +49 -0
- package/ios/Audio/AudioMain.swift +46 -82
- package/ios/Audio/AudioOptions.swift +37 -0
- package/ios/Audio/FormatConverter/FormatConverter+Compressed.swift +326 -0
- package/ios/Audio/FormatConverter/FormatConverter+PCM.swift +239 -0
- package/ios/Audio/FormatConverter/FormatConverter+Utilities.swift +103 -0
- package/ios/Audio/FormatConverter/FormatConverter.swift +264 -0
- package/ios/Compressor.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/ios/Video/NextLevelSessionExporter.swift +694 -0
- package/ios/Video/VideoMain.swift +1 -2
- package/lib/commonjs/Audio/index.js +1 -3
- package/lib/commonjs/Audio/index.js.map +1 -1
- package/lib/commonjs/utils/index.js +0 -2
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/module/Audio/index.js +1 -3
- package/lib/module/Audio/index.js.map +1 -1
- package/lib/module/utils/index.js +0 -3
- package/lib/module/utils/index.js.map +1 -1
- package/lib/typescript/Audio/index.d.ts.map +1 -1
- package/lib/typescript/utils/index.d.ts +4 -1
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/react-native-compressor.podspec +0 -1
- package/src/Audio/index.tsx +1 -3
- package/src/utils/index.tsx +5 -2
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/
|
|
2
|
+
|
|
3
|
+
import AVFoundation
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
FormatConverter wraps the more complex AVFoundation and CoreAudio audio conversions in an easy to use format.
|
|
7
|
+
```swift
|
|
8
|
+
let options = FormatConverter.Options()
|
|
9
|
+
|
|
10
|
+
// any options left nil will adopt the value of the input file
|
|
11
|
+
options.format = "wav"
|
|
12
|
+
options.sampleRate = 48000
|
|
13
|
+
options.bitDepth = 24
|
|
14
|
+
|
|
15
|
+
let converter = FormatConverter(inputURL: oldURL, outputURL: newURL, options: options)
|
|
16
|
+
|
|
17
|
+
converter.start { error in
|
|
18
|
+
// the error will be nil on success
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
*/
|
|
22
|
+
public class FormatConverter {
|
|
23
|
+
// MARK: - properties
|
|
24
|
+
|
|
25
|
+
/// The source audio file
|
|
26
|
+
public var inputURL: URL?
|
|
27
|
+
|
|
28
|
+
/// The audio file to be created after conversion
|
|
29
|
+
public var outputURL: URL?
|
|
30
|
+
|
|
31
|
+
/// Options for conversion
|
|
32
|
+
public var options: Options?
|
|
33
|
+
|
|
34
|
+
// MARK: - private properties
|
|
35
|
+
|
|
36
|
+
// The reader needs to exist outside the start func otherwise the async nature of the
|
|
37
|
+
// AVAssetWriterInput will lose its reference
|
|
38
|
+
var reader: AVAssetReader?
|
|
39
|
+
var writer: AVAssetWriter?
|
|
40
|
+
|
|
41
|
+
// MARK: - initialization
|
|
42
|
+
|
|
43
|
+
/// init with input, output and options - then start()
|
|
44
|
+
public init(inputURL: URL,
|
|
45
|
+
outputURL: URL,
|
|
46
|
+
options: Options? = nil)
|
|
47
|
+
{
|
|
48
|
+
self.inputURL = inputURL
|
|
49
|
+
self.outputURL = outputURL
|
|
50
|
+
self.options = options ?? Options()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
deinit {
|
|
54
|
+
reader = nil
|
|
55
|
+
writer = nil
|
|
56
|
+
inputURL = nil
|
|
57
|
+
outputURL = nil
|
|
58
|
+
options = nil
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// MARK: - functions
|
|
62
|
+
|
|
63
|
+
/// The entry point for file conversion
|
|
64
|
+
/// - Parameter completionHandler: the callback that will be triggered when process has completed.
|
|
65
|
+
public func start(completionHandler: FormatConverterCallback? = nil) {
|
|
66
|
+
guard let inputURL = inputURL else {
|
|
67
|
+
completionHandler?(Self.createError(message: "Input file can't be nil."))
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
guard let outputURL = outputURL else {
|
|
72
|
+
completionHandler?(Self.createError(message: "Output file can't be nil."))
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let inputFormat = AudioFileFormat(rawValue: inputURL.pathExtension.lowercased()) ?? .unknown
|
|
77
|
+
// verify inputFormat, only allow files with path extensions for speed?
|
|
78
|
+
guard FormatConverter.inputFormats.contains(inputFormat) else {
|
|
79
|
+
completionHandler?(Self.createError(message: "The input file format is in an incompatible format: \(inputFormat)"))
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if FileManager.default.fileExists(atPath: outputURL.path) {
|
|
84
|
+
if options?.eraseFile == true {
|
|
85
|
+
print("Warning: removing existing file at", outputURL.path)
|
|
86
|
+
try? FileManager.default.removeItem(at: outputURL)
|
|
87
|
+
} else {
|
|
88
|
+
let message = "The output file exists already. You need to choose a unique URL or delete the file."
|
|
89
|
+
completionHandler?(Self.createError(message: message))
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if options?.format == nil {
|
|
95
|
+
options?.format = AudioFileFormat(rawValue: outputURL.pathExtension.lowercased()) ?? .unknown
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Format checks are necessary as AVAssetReader has opinions about compressed
|
|
99
|
+
|
|
100
|
+
// PCM output, any supported input
|
|
101
|
+
if Self.isPCM(url: outputURL) == true {
|
|
102
|
+
// PCM output
|
|
103
|
+
convertToPCM(completionHandler: completionHandler)
|
|
104
|
+
|
|
105
|
+
// PCM input, compressed output
|
|
106
|
+
} else if Self.isPCM(url: inputURL) == true,
|
|
107
|
+
Self.isCompressed(url: outputURL) == true
|
|
108
|
+
{
|
|
109
|
+
convertPCMToCompressed(completionHandler: completionHandler)
|
|
110
|
+
|
|
111
|
+
// Compressed input and output, won't do sample rate
|
|
112
|
+
} else if Self.isCompressed(url: inputURL) == true,
|
|
113
|
+
Self.isCompressed(url: outputURL) == true
|
|
114
|
+
{
|
|
115
|
+
convertCompressed(completionHandler: completionHandler)
|
|
116
|
+
|
|
117
|
+
} else {
|
|
118
|
+
completionHandler?(Self.createError(message: "Unable to determine formats for conversion"))
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// MARK: - Definitions
|
|
124
|
+
|
|
125
|
+
public enum AudioFileFormat: String {
|
|
126
|
+
case aac
|
|
127
|
+
case aif
|
|
128
|
+
case aifc
|
|
129
|
+
case aiff
|
|
130
|
+
case au
|
|
131
|
+
case caf
|
|
132
|
+
case m4a
|
|
133
|
+
case m4v
|
|
134
|
+
case mov
|
|
135
|
+
case mp3
|
|
136
|
+
case mp4
|
|
137
|
+
case sd2
|
|
138
|
+
case snd
|
|
139
|
+
case ts
|
|
140
|
+
case unknown
|
|
141
|
+
case wav
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public extension FormatConverter {
|
|
145
|
+
|
|
146
|
+
/// FormatConverterCallback is the callback format for start()
|
|
147
|
+
/// - Parameter: error This will contain one parameter of type Error which is nil if the conversion was successful.
|
|
148
|
+
typealias FormatConverterCallback = (_ error: Error?) -> Void
|
|
149
|
+
|
|
150
|
+
/// Formats that this class can write
|
|
151
|
+
static let outputFormats: [AudioFileFormat] = [.wav, .aif, .caf, .m4a]
|
|
152
|
+
|
|
153
|
+
static let defaultOutputFormat: AudioFileFormat = .wav
|
|
154
|
+
|
|
155
|
+
/// Formats that this class can read
|
|
156
|
+
static let inputFormats: [AudioFileFormat] = FormatConverter.outputFormats + [
|
|
157
|
+
.mp3, .snd, .au, .sd2,
|
|
158
|
+
.aif, .aiff, .aifc, .aac,
|
|
159
|
+
.mp4, .m4v, .mov, .ts,
|
|
160
|
+
.unknown, // allow files with no extension. convertToPCM can still read the type
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
/// An option to block upsampling to a higher bit depth than the source.
|
|
164
|
+
/// For example, converting to 24bit from 16 doesn't have much benefit
|
|
165
|
+
enum BitDepthRule {
|
|
166
|
+
/// Don't allow upsampling to 24bit if the src is 16
|
|
167
|
+
case lessThanOrEqual
|
|
168
|
+
|
|
169
|
+
/// allow any conversaion
|
|
170
|
+
case any
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// The conversion options, leave any property nil to adopt the value of the input file
|
|
174
|
+
/// bitRate assumes a stereo bit rate and the converter will half it for mono
|
|
175
|
+
struct Options {
|
|
176
|
+
/// Audio Format
|
|
177
|
+
public var format: AudioFileFormat?
|
|
178
|
+
/// Sample Rate in Hertz
|
|
179
|
+
public var sampleRate: Double?
|
|
180
|
+
/// used only with PCM data
|
|
181
|
+
public var bitDepth: UInt32?
|
|
182
|
+
/// used only when outputting compressed audio
|
|
183
|
+
public var bitRate: UInt32 = 128000 {
|
|
184
|
+
didSet {
|
|
185
|
+
bitRate = bitRate.clamped(to: 64000 ... 320000)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// An option to block upsampling to a higher bit depth than the source.
|
|
190
|
+
/// default value is `.lessThanOrEqual`
|
|
191
|
+
public var bitDepthRule: BitDepthRule = .lessThanOrEqual
|
|
192
|
+
|
|
193
|
+
/// How many channels to convert to. Typically 1 or 2
|
|
194
|
+
public var channels: UInt32?
|
|
195
|
+
|
|
196
|
+
/// Maps to PCM Conversion format option `AVLinearPCMIsNonInterleaved`
|
|
197
|
+
public var isInterleaved: Bool?
|
|
198
|
+
|
|
199
|
+
/// Overwrite existing files, set false if you want to handle this before you call start()
|
|
200
|
+
public var eraseFile: Bool = true
|
|
201
|
+
|
|
202
|
+
public init() {}
|
|
203
|
+
|
|
204
|
+
/// Create options by parsing the contents of the url and using the audio settings
|
|
205
|
+
/// in the file
|
|
206
|
+
/// - Parameter url: The audio file to open and parse
|
|
207
|
+
public init?(url: URL) {
|
|
208
|
+
guard let avFile = try? AVAudioFile(forReading: url) else { return nil }
|
|
209
|
+
self.init(audioFile: avFile)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/// Create options by parsing the audioFile for its settings
|
|
213
|
+
/// - Parameter audioFile: an AVAudioFile to parse
|
|
214
|
+
public init?(audioFile: AVAudioFile) {
|
|
215
|
+
let streamDescription = audioFile.fileFormat.streamDescription.pointee
|
|
216
|
+
|
|
217
|
+
format = AudioFileFormat(rawValue: audioFile.url.pathExtension) ?? .unknown
|
|
218
|
+
// FormatConverter.formatIDToString(streamDescription.mFormatID)
|
|
219
|
+
sampleRate = streamDescription.mSampleRate
|
|
220
|
+
bitDepth = streamDescription.mBitsPerChannel
|
|
221
|
+
channels = streamDescription.mChannelsPerFrame
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/// Create PCM Options
|
|
225
|
+
/// - Parameters:
|
|
226
|
+
/// - pcmFormat: wav, aif, or caf
|
|
227
|
+
/// - sampleRate: Sample Rate
|
|
228
|
+
/// - bitDepth: Bit Depth, or bits per channel
|
|
229
|
+
/// - channels: How many channels
|
|
230
|
+
public init?(pcmFormat: AudioFileFormat,
|
|
231
|
+
sampleRate: Double? = nil,
|
|
232
|
+
bitDepth: UInt32? = nil,
|
|
233
|
+
channels: UInt32? = nil)
|
|
234
|
+
{
|
|
235
|
+
format = pcmFormat
|
|
236
|
+
self.sampleRate = sampleRate
|
|
237
|
+
self.bitDepth = bitDepth
|
|
238
|
+
self.channels = channels
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
internal func completionProxy(error: Error?,
|
|
243
|
+
deleteOutputOnError: Bool = true,
|
|
244
|
+
completionHandler: FormatConverterCallback? = nil)
|
|
245
|
+
{
|
|
246
|
+
guard error != nil,
|
|
247
|
+
deleteOutputOnError,
|
|
248
|
+
let outputURL = outputURL,
|
|
249
|
+
FileManager.default.fileExists(atPath: outputURL.path)
|
|
250
|
+
else {
|
|
251
|
+
completionHandler?(error)
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
do {
|
|
256
|
+
print("Deleting on error", outputURL.path)
|
|
257
|
+
try FileManager.default.removeItem(at: outputURL)
|
|
258
|
+
} catch let err as NSError {
|
|
259
|
+
print("Failed to remove file", outputURL, err)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
completionHandler?(error)
|
|
263
|
+
}
|
|
264
|
+
}
|
package/ios/Compressor.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>SchemeUserState</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>Compressor.xcscheme_^#shared#^_</key>
|
|
8
|
+
<dict>
|
|
9
|
+
<key>orderHint</key>
|
|
10
|
+
<integer>56</integer>
|
|
11
|
+
</dict>
|
|
12
|
+
</dict>
|
|
13
|
+
</dict>
|
|
14
|
+
</plist>
|