Skip to content

Commit

Permalink
Merge pull request #221 from Yummypets/RecordingSquareVideos
Browse files Browse the repository at this point in the history
Recording square videos
  • Loading branch information
NikKovIos authored Sep 17, 2018
2 parents 75b3606 + 880c024 commit 5473c01
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 14 deletions.
1 change: 1 addition & 0 deletions Source/Helpers/YPLoaders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ struct YPLoaders {
spinner.startAnimating()
return UIBarButtonItem(customView: spinner)
}

}
104 changes: 104 additions & 0 deletions Source/Helpers/YPVideoProcessor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// YPVideoProcessor.swift
// YPImagePicker
//
// Created by Nik Kov on 13.09.2018.
// Copyright © 2018 Yummypets. All rights reserved.
//

import UIKit
import AVFoundation

/*
This class contains all support and helper methods to process the videos
*/
class YPVideoProcessor {

/// Creates an output path and removes the file in temp folder if existing
///
/// - Parameters:
/// - temporaryFolder: Save to the temporary folder or somewhere else like documents folder
/// - suffix: the file name wothout extension
static func makeVideoPathURL(temporaryFolder: Bool, fileName: String) -> URL {
var outputURL: URL

if temporaryFolder {
let outputPath = "\(NSTemporaryDirectory())\(fileName).\(YPConfig.video.fileType.fileExtension)"
outputURL = URL(fileURLWithPath: outputPath)
} else {
guard let documentsURL = FileManager
.default
.urls(for: .documentDirectory,
in: .userDomainMask).first else {
print("YPVideoProcessor -> Can't get the documents directory URL")
return URL(fileURLWithPath: "Error")
}
outputURL = documentsURL.appendingPathComponent("\(fileName).\(YPConfig.video.fileType.fileExtension)")
}

let fileManager = FileManager.default
if fileManager.fileExists(atPath: outputURL.path) {
do {
try fileManager.removeItem(atPath: outputURL.path)
} catch {
print("YPVideoProcessor -> Can't remove the file for some reason.")
}
}

return outputURL
}

/*
Crops the video to square by video height from the top of the video.
*/
static func cropToSquare(filePath: URL, completion: @escaping (_ outputURL : URL?) -> ()) {

// output file
let outputPath = makeVideoPathURL(temporaryFolder: true, fileName: "squaredVideoFromCamera")

// input file
let asset = AVAsset.init(url: filePath)
let composition = AVMutableComposition.init()
composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)

// input clip
let clipVideoTrack = asset.tracks(withMediaType: .video)[0]

// make it square
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = CGSize(width: CGFloat(clipVideoTrack.naturalSize.height), height: CGFloat(clipVideoTrack.naturalSize.height))
videoComposition.frameDuration = CMTimeMake(1, 30)
let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30))

// rotate to potrait
let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: clipVideoTrack)
let t1 = CGAffineTransform(translationX: clipVideoTrack.naturalSize.height, y: -(clipVideoTrack.naturalSize.width - clipVideoTrack.naturalSize.height) / 2)
let t2: CGAffineTransform = t1.rotated(by: .pi/2)
let finalTransform: CGAffineTransform = t2
transformer.setTransform(finalTransform, at: kCMTimeZero)
instruction.layerInstructions = [transformer]
videoComposition.instructions = [instruction]

// exporter
let exporter = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetMediumQuality)
exporter?.videoComposition = videoComposition
exporter?.outputURL = outputPath
exporter?.shouldOptimizeForNetworkUse = true
exporter?.outputFileType = YPConfig.video.fileType

exporter?.exportAsynchronously {
if exporter?.status == .completed {
DispatchQueue.main.async(execute: {
completion(outputPath)
})
return
} else if exporter?.status == .failed {
print("YPVideoProcessor -> Export of the video failed. Reason: \(String(describing: exporter?.error))")
}
completion(nil)
return
}
}

}
2 changes: 1 addition & 1 deletion Source/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.4.0</string>
<string>3.4.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
17 changes: 6 additions & 11 deletions Source/Pages/Video/YPVideoCaptureHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,8 @@ class YPVideoCaptureHelper: NSObject {
// MARK: - Recording

public func startRecording() {
let outputPath = "\(NSTemporaryDirectory())output.\(YPConfig.video.fileType.fileExtension)"
let outputURL = URL(fileURLWithPath: outputPath)
let fileManager = FileManager.default
if fileManager.fileExists(atPath: outputPath) {
do {
try fileManager.removeItem(atPath: outputPath)
} catch {
return
}
}

let outputURL = YPVideoProcessor.makeVideoPathURL(temporaryFolder: true, fileName: "recordedVideoRAW")

checkOrientation { [weak self] orientation in
guard let strongSelf = self else {
Expand Down Expand Up @@ -273,7 +265,10 @@ extension YPVideoCaptureHelper: AVCaptureFileOutputRecordingDelegate {
didFinishRecordingTo outputFileURL: URL,
from connections: [AVCaptureConnection],
error: Error?) {
didCaptureVideo?(outputFileURL)
YPVideoProcessor.cropToSquare(filePath: outputFileURL) { [weak self] url in
guard let _self = self, let u = url else { return }
_self.didCaptureVideo?(u)
}
timer.invalidate()
}
}
2 changes: 1 addition & 1 deletion YPImagePicker.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'YPImagePicker'
s.version = "3.4.0"
s.version = "3.4.1"
s.summary = "Instagram-like image picker & filters for iOS"
s.homepage = "https://github.com/Yummypets/YPImagePicker"
s.license = { :type => "MIT", :file => "LICENSE" }
Expand Down
6 changes: 5 additions & 1 deletion YPImagePicker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
99CF6D29201B900400487F77 /* LibraryMediaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99CF6D28201B900400487F77 /* LibraryMediaManager.swift */; };
99CF6D2B201CB96700487F77 /* YPVideoCaptureHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99CF6D2A201CB96700487F77 /* YPVideoCaptureHelper.swift */; };
99D1DC2B1F9788930047F0E0 /* YPImagePickerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D1DC2A1F9788930047F0E0 /* YPImagePickerConfiguration.swift */; };
EB05F6E7214A7191002040AA /* YPVideoProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB05F6E6214A7191002040AA /* YPVideoProcessor.swift */; };
EB19A8F420AC41AE007F88D8 /* AVAssetTrack+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB19A8F320AC41AE007F88D8 /* AVAssetTrack+Extensions.swift */; };
EB1AB2EA20AC1DED00BFA79F /* CGFloat+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB1AB2E920AC1DED00BFA79F /* CGFloat+Extensions.swift */; };
EB473E17208E192800D16105 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB473E16208E192800D16105 /* URL+Extensions.swift */; };
Expand Down Expand Up @@ -166,6 +167,7 @@
99D1DC2A1F9788930047F0E0 /* YPImagePickerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YPImagePickerConfiguration.swift; sourceTree = "<group>"; };
A7FD716620755C2D0044A8E8 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
E5287F5820B908720052153D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
EB05F6E6214A7191002040AA /* YPVideoProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YPVideoProcessor.swift; sourceTree = "<group>"; };
EB11EE9820572F3700A19365 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
EB19A8F320AC41AE007F88D8 /* AVAssetTrack+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVAssetTrack+Extensions.swift"; sourceTree = "<group>"; };
EB1AB2E920AC1DED00BFA79F /* CGFloat+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extensions.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -259,6 +261,7 @@
99CF6D26201B739600487F77 /* YPAlerts.swift */,
990FD28E201A49D3002A39A1 /* YPPermissionCheckable.swift */,
EB94F28D208E3A140049F523 /* YPLoaders.swift */,
EB05F6E6214A7191002040AA /* YPVideoProcessor.swift */,
);
path = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -302,7 +305,6 @@
EB65C4B3209281A10037858B /* Pages */,
99C6D6A91F1FB5C100711DB2 /* Filters */,
EBD2B639207B7B1100E711C2 /* SelectionsGallery */,
99019E4A2018CCB8007325C2 /* BottomPager */,
99019E542018CECC007325C2 /* Helpers */,
EBD2B63D207B7D4E00E711C2 /* Models */,
99C6D6B31F1FB5C100711DB2 /* Info.plist */,
Expand All @@ -327,6 +329,7 @@
99C6D6A31F1FB5C100711DB2 /* YPGridView.swift */,
99CF6D28201B900400487F77 /* LibraryMediaManager.swift */,
99A0529B1F20B44B005600B3 /* Albums */,
99019E4A2018CCB8007325C2 /* BottomPager */,
);
path = Gallery;
sourceTree = "<group>";
Expand Down Expand Up @@ -566,6 +569,7 @@
buildActionMask = 2147483647;
files = (
99C6D6C81F1FB5C100711DB2 /* YPFiltersView.swift in Sources */,
EB05F6E7214A7191002040AA /* YPVideoProcessor.swift in Sources */,
990FD293201B3D69002A39A1 /* YPLibraryViewDelegate.swift in Sources */,
990FD28F201A49D3002A39A1 /* YPPermissionCheckable.swift in Sources */,
EB473E23208E1DB000D16105 /* AVPlayer+Extensions.swift in Sources */,
Expand Down

0 comments on commit 5473c01

Please sign in to comment.