|
9 | 9 | import UIKit |
10 | 10 | import AVKit |
11 | 11 |
|
12 | | -public final class DPVideoMerger: NSObject { |
13 | | - //videoQuality : AVAssetExportPresetMediumQuality(default) , AVAssetExportPresetLowQuality , AVAssetExportPresetHighestQuality |
14 | | - public func mergeVideos(withFileURLs |
| 12 | + |
| 13 | + |
| 14 | +@objc protocol VideoMerger { |
| 15 | + func mergeVideos(withFileURLs videoFileURLs: [URL], videoResolution:CGSize, videoQuality:String, completion: @escaping (_ mergedVideoURL: URL?, _ error: Error?) -> Void) |
| 16 | + func gridMergeVideos(withFileURLs videoFileURLs: [URL], videoResolution: CGSize, isRepeatVideo: Bool, videoDuration: Int, videoQuality: String, completion: @escaping (_ mergedVideoURL: URL?, _ error: Error?) -> Void) |
| 17 | +} |
| 18 | + |
| 19 | +@objc open class DPVideoMerger : NSObject { |
| 20 | +} |
| 21 | + |
| 22 | +extension DPVideoMerger : VideoMerger { |
| 23 | + /// Multiple videos merge in one video with manage scale & aspect ratio |
| 24 | + /// - Parameters: |
| 25 | + /// - videoFileURLs: Video file path URLs, Array of videos that going to merge |
| 26 | + /// - videoResolution: Output video resolution, (defult: CGSize(width: -1, height: -1), find max width and height from provided videos) |
| 27 | + /// - videoQuality: AVAssetExportPresetMediumQuality(default) , AVAssetExportPresetLowQuality , AVAssetExportPresetHighestQuality |
| 28 | + /// - completion: Completion give 2 optional values, 1)mergedVideoURL: URL path of successfully merged video 2)error: Gives Error object if some error occur in videos merging process |
| 29 | + /// - mergedVideoURL: URL path of successfully merged video |
| 30 | + /// - error: Gives Error object if some error occur in videos merging process |
| 31 | + open func mergeVideos(withFileURLs |
15 | 32 | videoFileURLs: [URL], |
16 | 33 | videoResolution:CGSize = CGSize(width: -1, height: -1), |
17 | 34 | videoQuality:String = AVAssetExportPresetMediumQuality, |
@@ -154,7 +171,7 @@ public final class DPVideoMerger: NSObject { |
154 | 171 | switch videoAssetOrientation_ { |
155 | 172 | case UIImage.Orientation.right: |
156 | 173 | Move = CGAffineTransform(translationX: (videoAssetWidth * factor) + CGFloat(tx) , y: CGFloat(ty)) |
157 | | - transform = CGAffineTransform(rotationAngle:degreeToRadian(90)) |
| 174 | + transform = CGAffineTransform(rotationAngle: degreeToRadian(90)) |
158 | 175 | layerInstruction.setTransform(transform.concatenating(Scale.concatenating(Move)), at: .zero) |
159 | 176 | case UIImage.Orientation.left: |
160 | 177 | Move = CGAffineTransform(translationX: CGFloat(tx), y: videoSize.height - CGFloat(ty)) |
@@ -225,26 +242,36 @@ public final class DPVideoMerger: NSObject { |
225 | 242 | } |
226 | 243 | } |
227 | 244 | } |
228 | | - func videoTarckError() -> Error { |
| 245 | + fileprivate func videoTarckError() -> Error { |
229 | 246 | let userInfo: [AnyHashable : Any] = |
230 | 247 | [ NSLocalizedDescriptionKey : NSLocalizedString("error", value: "Provide correct video file", comment: "") , |
231 | 248 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("error", value: "No video track available", comment: "")] |
232 | 249 | return NSError(domain: "DPVideoMerger", code: 404, userInfo: (userInfo as! [String : Any])) |
233 | 250 | } |
234 | | - func audioTarckError() -> Error { |
| 251 | + fileprivate func audioTarckError() -> Error { |
235 | 252 | let userInfo: [AnyHashable : Any] = |
236 | 253 | [ NSLocalizedDescriptionKey : NSLocalizedString("error", value: "Video file had no Audio track", comment: "") , |
237 | 254 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("error", value: "No Audio track available", comment: "")] |
238 | 255 | return NSError(domain: "DPVideoMerger", code: 404, userInfo: (userInfo as! [String : Any])) |
239 | 256 | } |
240 | | - func videoSizeError() -> Error { |
| 257 | + fileprivate func videoSizeError() -> Error { |
241 | 258 | let userInfo: [AnyHashable : Any] = |
242 | 259 | [ NSLocalizedDescriptionKey : NSLocalizedString("error", value: "videoSize height/width should grater than equal to 100", comment: "") , |
243 | 260 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("error", value: "videoSize too small", comment: "")] |
244 | 261 | return NSError(domain: "DPVideoMerger", code: 404, userInfo: (userInfo as! [String : Any])) |
245 | 262 | } |
246 | 263 |
|
247 | | - public func gridMergeVideos(withFileURLs |
| 264 | + /// Merge 4 videos to grid layout |
| 265 | + /// - Parameters: |
| 266 | + /// - videoFileURLs: Video file path URLs, Array of 4 videos that going to grid merge |
| 267 | + /// - videoResolution: Output video resolution |
| 268 | + /// - isRepeatVideo: Repeat Video on grid if one or more video have shorter duartion time then output video duration |
| 269 | + /// - videoDuration: Output video duration (defult: -1, find max duration from provided 4 videos) |
| 270 | + /// - videoQuality: AVAssetExportPresetMediumQuality(default) , AVAssetExportPresetLowQuality , AVAssetExportPresetHighestQuality |
| 271 | + /// - completion: completion give 2 optional values, 1)mergedVideoURL: URL path of successfully grid merged video 2)error: gives Error object if some error occur in videos merging process |
| 272 | + /// - mergedVideoURL: URL path of successfully grid merged video |
| 273 | + /// - error: gives Error object if some error occur in videos merging process |
| 274 | + open func gridMergeVideos(withFileURLs |
248 | 275 | videoFileURLs: [URL], |
249 | 276 | videoResolution: CGSize, |
250 | 277 | isRepeatVideo: Bool = false, |
@@ -421,24 +448,24 @@ public final class DPVideoMerger: NSObject { |
421 | 448 |
|
422 | 449 | } |
423 | 450 |
|
424 | | - func videoCountError() -> Error { |
| 451 | + fileprivate func videoCountError() -> Error { |
425 | 452 | let userInfo: [AnyHashable : Any] = |
426 | 453 | [ NSLocalizedDescriptionKey : NSLocalizedString("error", value: "Provide 4 Videos", comment: "") , |
427 | 454 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("error", value: "gridMerge required 4 videos to merge", comment: "")] |
428 | 455 | return NSError(domain: "DPVideoMerger", code: 404, userInfo: (userInfo as! [String : Any])) |
429 | 456 | } |
430 | 457 |
|
431 | | - func videoDurationError() -> Error { |
| 458 | + fileprivate func videoDurationError() -> Error { |
432 | 459 | let userInfo: [AnyHashable : Any] = |
433 | 460 | [ NSLocalizedDescriptionKey : NSLocalizedString("error", value: "videoDuration should grater than equal to logest video duration from all videoes.", comment: "") , |
434 | 461 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("error", value: "videoDuration is small to complete videoes", comment: "")] |
435 | 462 | return NSError(domain: "DPVideoMerger", code: 404, userInfo: (userInfo as! [String : Any])) |
436 | 463 | } |
437 | 464 |
|
438 | | - func generateMergedVideoFilePath() -> String { |
| 465 | + fileprivate func generateMergedVideoFilePath() -> String { |
439 | 466 | return URL(fileURLWithPath: ((FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last)?.path)!).appendingPathComponent("\(UUID().uuidString)-mergedVideo.mp4").path |
440 | 467 | } |
441 | | - func degreeToRadian(_ degree: CGFloat) -> CGFloat { |
| 468 | + fileprivate func degreeToRadian(_ degree: CGFloat) -> CGFloat { |
442 | 469 | return (.pi * degree / 180.0) |
443 | 470 | } |
444 | 471 | } |
|
0 commit comments