Last active
January 22, 2019 11:49
-
-
Save mspvirajpatel/5c22da870e37f3d339e78dbd42336c62 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Media is a video | |
let videoUrl = "Your URL FILE" as! NSURL | |
let asset = AVAsset(url: videoUrl as URL) | |
let first: CMTimeRange = CMTimeRange.init(start: kCMTimeZero, duration: CMTime.init(seconds: 2, preferredTimescale: asset.duration.timescale)) | |
let firstScael: CMTime = CMTimeMakeWithSeconds((Float64(2) * Float64(5)), asset.duration.timescale) | |
let second: CMTimeRange = CMTimeRange.init(start: CMTime.init(seconds: 5, preferredTimescale: asset.duration.timescale), duration: CMTime.init(seconds: 5, preferredTimescale: asset.duration.timescale)) | |
let secondScael: CMTime = CMTimeMakeWithSeconds((Float64(5) / Float64(5.0)), asset.duration.timescale) | |
let thir: CMTimeRange = CMTimeRange.init(start: CMTime.init(seconds: 11, preferredTimescale: asset.duration.timescale), duration: CMTime.init(seconds: 2, preferredTimescale: asset.duration.timescale)) | |
let thirScael: CMTime = CMTimeMakeWithSeconds((Float64(2) * Float64(2.0)), asset.duration.timescale) | |
let url = videoUrl | |
VSVideoSpeeder.shared.scaleAsset(fromURL: url as URL, by: 2, withMode: .Faster, withCMTime: [firstScael, secondScael, thirScael], withRange: [first, second, thir]) { (exporter) in | |
if let exporter = exporter { | |
switch exporter.status { | |
case .failed: do { | |
print(exporter.error?.localizedDescription ?? "Error in exporting..") | |
} | |
case .completed: do { | |
self.playAVPlayer(url: exporter.outputURL! as NSURL) | |
print("Scaled video has been generated successfully!") | |
} | |
case .unknown: break | |
case .waiting: break | |
case .exporting: break | |
case .cancelled: break | |
} | |
} | |
else { | |
print("Exporter is not initialized.") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SlowFast.swift | |
// | |
// Created by Viraj Patel on 11/12/18. | |
// | |
import Foundation | |
import UIKit | |
import AVFoundation | |
enum SpeedoMode { | |
case Slower | |
case Faster | |
} | |
class VSVideoSpeeder: NSObject { | |
static var shared: VSVideoSpeeder = { | |
return VSVideoSpeeder() | |
}() | |
func margeVideos(compositionTrack: AVMutableCompositionTrack, withCMTime timeScale: [CMTime], withRange range: [CMTimeRange]) { | |
var temptimeRange2StartTime = range[0].end | |
var lastTimeRangeForStart = kCMTimeRangeZero | |
for (index, newRange) in range.enumerated() { | |
if index == 0 { | |
compositionTrack.scaleTimeRange(newRange, toDuration: timeScale[index]) | |
} | |
else { | |
var timeRange2 = newRange | |
let timeRange = range[index - 1] | |
var indexItem = index | |
if index == 1 { | |
indexItem = 0 | |
} else if index == 2 { | |
indexItem = 2 | |
} | |
temptimeRange2StartTime = timeRange.end | |
let timeRangerrr = (lastTimeRangeForStart.start.seconds + (Double(compositionTrack.segments[indexItem].timeMapping.target.duration.value) / Double(compositionTrack.segments[indexItem].timeMapping.target.duration.timescale))) + Double(timeRange2.start.seconds - temptimeRange2StartTime.seconds) | |
print(timeRangerrr) | |
let duration = timeRange2.duration | |
timeRange2.start = CMTime.init(seconds: timeRangerrr, preferredTimescale: timeRange2.start.timescale) | |
timeRange2.duration = duration | |
compositionTrack.scaleTimeRange(timeRange2, toDuration: timeScale[index]) | |
lastTimeRangeForStart = timeRange2 | |
} | |
} | |
} | |
/// Range is b/w 1x, 2x and 3x. Will not happen anything if scale is out of range. Exporter will be nil in case url is invalid or unable to make asset instance. | |
func scaleAsset(fromURL url: URL, by scale: Float, withMode mode: SpeedoMode, withCMTime timeScale: [CMTime], withRange range: [CMTimeRange], completion: @escaping (_ exporter: AVAssetExportSession?) -> Void) { | |
/// Asset | |
let asset = AVAsset(url: url) | |
/// Video Tracks | |
let videoTracks = asset.tracks(withMediaType: AVMediaTypeVideo) | |
if videoTracks.count == 0 { | |
/// Can not find any video track | |
completion(nil) | |
return | |
} | |
let fullTimeRange = CMTimeRangeMake(kCMTimeZero, CMTime.init(seconds: Double(asset.duration.seconds), preferredTimescale: asset.duration.timescale)) | |
/// Video track | |
let videoTrack = videoTracks.first! | |
let mixComposition = AVMutableComposition() | |
let compositionVideoTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid) | |
/// Audio Tracks | |
let audioTracks = asset.tracks(withMediaType: AVMediaTypeAudio) | |
if audioTracks.count > 0 { | |
/// Use audio if video contains the audio track | |
let compositionAudioTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid) | |
/// Audio track | |
let audioTrack = audioTracks.first! | |
do { | |
try compositionAudioTrack.insertTimeRange(fullTimeRange, of: audioTrack, at: kCMTimeZero) | |
margeVideos(compositionTrack: compositionAudioTrack, withCMTime: timeScale, withRange: range) | |
} catch _ { | |
/// Ignore audio error | |
} | |
} | |
do { | |
// videoTracks | |
try compositionVideoTrack.insertTimeRange(fullTimeRange, of: videoTrack, at: kCMTimeZero) | |
margeVideos(compositionTrack: compositionVideoTrack, withCMTime: timeScale, withRange: range) | |
print(compositionVideoTrack.segments) | |
print(mixComposition.duration) | |
/// Keep original transformation | |
compositionVideoTrack.preferredTransform = videoTrack.preferredTransform | |
/// Initialize Exporter now | |
// let outputFileURL = URL(fileURLWithPath: "/Users/viraj.patel/Desktop/scaledVideo222.mp4") | |
/// Note:- Please use directory path if you are testing with device. | |
let df = DateFormatter() | |
df.locale = NSLocale(localeIdentifier: "en_US") as Locale | |
df.dateFormat = "yyyyMMddHHmmssSSS" | |
var formate = df.string(from: Date()) | |
formate = formate + ".mp4" | |
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) | |
let documentsDirectory = paths[0] | |
let outputFileURL = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("\(formate)") | |
print(outputFileURL) | |
if FileManager.default.fileExists(atPath: outputFileURL.absoluteString) { | |
try FileManager.default.removeItem(at: outputFileURL) | |
} | |
let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) | |
exporter?.outputURL = outputFileURL | |
exporter?.outputFileType = AVFileTypeMPEG4 | |
exporter?.shouldOptimizeForNetworkUse = true | |
exporter?.exportAsynchronously(completionHandler: { | |
completion(exporter) | |
}) | |
} catch let error { | |
print(error.localizedDescription) | |
completion(nil) | |
return | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment