@@ -252,6 +252,132 @@ class RNVideoTrimmer: NSObject {
252
252
}
253
253
}
254
254
}
255
+
256
+ @objc func boomerang( _ source: String , options: NSDictionary , callback: @escaping RCTResponseSenderBlock ) {
257
+
258
+ let quality = " "
259
+
260
+ let manager = FileManager . default
261
+ guard let documentDirectory = try ? manager. url ( for: . documentDirectory, in: . userDomainMask, appropriateFor: nil , create: true )
262
+ else {
263
+ callback ( [ " Error creating FileManager " , NSNull ( ) ] )
264
+ return
265
+ }
266
+
267
+ let sourceURL = getSourceURL ( source: source)
268
+ let firstAsset = AVAsset ( url: sourceURL as URL )
269
+
270
+ let mixComposition = AVMutableComposition ( )
271
+ let track = mixComposition. addMutableTrack ( withMediaType: AVMediaTypeVideo, preferredTrackID: Int32 ( kCMPersistentTrackID_Invalid) )
272
+
273
+
274
+ var outputURL = documentDirectory. appendingPathComponent ( " output " )
275
+ var finalURL = documentDirectory. appendingPathComponent ( " output " )
276
+ do {
277
+ try manager. createDirectory ( at: outputURL, withIntermediateDirectories: true , attributes: nil )
278
+ try manager. createDirectory ( at: finalURL, withIntermediateDirectories: true , attributes: nil )
279
+ let name = randomString ( )
280
+ outputURL = outputURL. appendingPathComponent ( " \( name) .mp4 " )
281
+ finalURL = finalURL. appendingPathComponent ( " \( name) merged.mp4 " )
282
+ } catch {
283
+ callback ( [ error. localizedDescription, NSNull ( ) ] )
284
+ print ( error)
285
+ }
286
+
287
+ //Remove existing file
288
+ _ = try ? manager. removeItem ( at: outputURL)
289
+ _ = try ? manager. removeItem ( at: finalURL)
290
+
291
+ let useQuality = getQualityForAsset ( quality: quality, asset: firstAsset)
292
+
293
+ // print("RNVideoTrimmer passed quality: \(quality). useQuality: \(useQuality)")
294
+
295
+ AVUtilities . reverse ( firstAsset, outputURL: outputURL, completion: { [ unowned self] ( reversedAsset: AVAsset ) in
296
+
297
+
298
+ let secondAsset = reversedAsset
299
+
300
+ // Credit: https://www.raywenderlich.com/94404/play-record-merge-videos-ios-swift
301
+ do {
302
+ try track. insertTimeRange ( CMTimeRangeMake ( kCMTimeZero, firstAsset. duration) , of: firstAsset. tracks ( withMediaType: AVMediaTypeVideo) [ 0 ] , at: kCMTimeZero)
303
+ } catch _ {
304
+ callback ( [ " Failed: Could not load 1st track " , NSNull ( ) ] )
305
+ return
306
+ }
307
+
308
+ do {
309
+ try track. insertTimeRange ( CMTimeRangeMake ( kCMTimeZero, secondAsset. duration) , of: secondAsset. tracks ( withMediaType: AVMediaTypeVideo) [ 0 ] , at: mixComposition. duration)
310
+ } catch _ {
311
+ callback ( [ " Failed: Could not load 2nd track " , NSNull ( ) ] )
312
+ return
313
+ }
314
+
315
+
316
+ guard let exportSession = AVAssetExportSession ( asset: mixComposition, presetName: useQuality) else {
317
+ callback ( [ " Error creating AVAssetExportSession " , NSNull ( ) ] )
318
+ return
319
+ }
320
+ exportSession. outputURL = NSURL . fileURL ( withPath: finalURL. path)
321
+ exportSession. outputFileType = AVFileTypeMPEG4
322
+ exportSession. shouldOptimizeForNetworkUse = true
323
+ let startTime = CMTime ( seconds: Double ( 0 ) , preferredTimescale: 1000 )
324
+ let endTime = CMTime ( seconds: mixComposition. duration. seconds, preferredTimescale: 1000 )
325
+ let timeRange = CMTimeRange ( start: startTime, end: endTime)
326
+
327
+ exportSession. timeRange = timeRange
328
+
329
+ exportSession. exportAsynchronously {
330
+ switch exportSession. status {
331
+ case . completed:
332
+ callback ( [ NSNull ( ) , finalURL. absoluteString] )
333
+
334
+ case . failed:
335
+ callback ( [ " Failed: \( exportSession. error) " , NSNull ( ) ] )
336
+
337
+ case . cancelled:
338
+ callback ( [ " Cancelled: \( exportSession. error) " , NSNull ( ) ] )
339
+
340
+ default : break
341
+ }
342
+ }
343
+ } )
344
+ }
345
+
346
+ @objc func reverse( _ source: String , options: NSDictionary , callback: @escaping RCTResponseSenderBlock ) {
347
+
348
+ let quality = " "
349
+
350
+ let manager = FileManager . default
351
+ guard let documentDirectory = try ? manager. url ( for: . documentDirectory, in: . userDomainMask, appropriateFor: nil , create: true )
352
+ else {
353
+ callback ( [ " Error creating FileManager " , NSNull ( ) ] )
354
+ return
355
+ }
356
+
357
+ let sourceURL = getSourceURL ( source: source)
358
+ let asset = AVAsset ( url: sourceURL as URL )
359
+
360
+ var outputURL = documentDirectory. appendingPathComponent ( " output " )
361
+ do {
362
+ try manager. createDirectory ( at: outputURL, withIntermediateDirectories: true , attributes: nil )
363
+ let name = randomString ( )
364
+ outputURL = outputURL. appendingPathComponent ( " \( name) .mp4 " )
365
+ } catch {
366
+ callback ( [ error. localizedDescription, NSNull ( ) ] )
367
+ print ( error)
368
+ }
369
+
370
+ //Remove existing file
371
+ _ = try ? manager. removeItem ( at: outputURL)
372
+
373
+ let useQuality = getQualityForAsset ( quality: quality, asset: asset)
374
+
375
+ print ( " RNVideoTrimmer passed quality: \( quality) . useQuality: \( useQuality) " )
376
+
377
+ AVUtilities . reverse ( asset, outputURL: outputURL, completion: { [ unowned self] ( asset: AVAsset ) in
378
+ callback ( [ NSNull ( ) , outputURL. absoluteString] )
379
+ } )
380
+ }
255
381
256
382
@objc func compress( _ source: String , options: NSDictionary , callback: @escaping RCTResponseSenderBlock ) {
257
383
0 commit comments