Skip to content

Commit

Permalink
Merge pull request #44 from rewardStyle/CC-998-enforce-1080-p-max-res…
Browse files Browse the repository at this point in the history
…olution-across-all-video-uploads

Make Video Processing Configurable
  • Loading branch information
zeph-cohen10 committed Mar 22, 2024
2 parents b0f7bdc + 20a291a commit 74ca8d2
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 13 deletions.
6 changes: 5 additions & 1 deletion Source/Configuration/YPImagePickerConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,11 @@ public struct YPConfigVideo {
- "AVAssetExportPresetPassthrough" // without any compression
*/
public var compression: String = AVAssetExportPresetHighestQuality


/// When `true` the video will always be processed using whatever whatever export preset is defined for `YPConfigVideo.compression.
/// The default value is `false`.`
public var shouldAlwaysProcessVideo: Bool = false

/// Choose the result video extension if you trim or compress a video. Defaults to mov.
public var fileType: AVFileType = .mov

Expand Down
39 changes: 29 additions & 10 deletions Source/Pages/Gallery/LibraryMediaManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ open class LibraryMediaManager {
}
}

open func fetchVideoUrlAndCrop(for videoAsset: PHAsset, cropRect: CGRect, timeRange: CMTimeRange = CMTimeRange(start: CMTime.zero, end: CMTime.zero), shouldMute: Bool = false, compressionTypeOverride: String? = nil, callback: @escaping (_ videoURL: URL?) -> Void) {
open func fetchVideoUrlAndCrop(for videoAsset: PHAsset, cropRect: CGRect, timeRange: CMTimeRange = CMTimeRange(start: CMTime.zero, end: CMTime.zero), shouldMute: Bool = false, compressionTypeOverride: String? = nil, processingFailedRetryCount: Int = 0, callback: @escaping (_ videoURL: URL?) -> Void) {
if currentExportSessions.contains(where: { $0.localIdentifier == videoAsset.localIdentifier }) {
cancelExport(for: videoAsset.localIdentifier)
}
Expand All @@ -167,7 +167,7 @@ open class LibraryMediaManager {
videosOptions.isNetworkAccessAllowed = true
videosOptions.deliveryMode = .highQualityFormat

let videoNeedsProcessing = videoAsset.mediaSubtypes.contains(.videoHighFrameRate)
let isSlowMoVideo = videoAsset.mediaSubtypes.contains(.videoHighFrameRate)

imageManager?.requestAVAsset(forVideo: videoAsset, options: videosOptions) { asset, _, _ in
do {
Expand Down Expand Up @@ -210,7 +210,15 @@ open class LibraryMediaManager {
// 5. Configuring export session
let videoIsCropped = cropRect.size.width < abs(videoSize.width) || cropRect.size.height < abs(videoSize.height)

let presetName = compressionTypeOverride ?? (videoIsCropped || videoIsTrimmed || videoIsRotated || (shouldMute && videoNeedsProcessing) ? YPConfig.video.compression : AVAssetExportPresetPassthrough)
let presetName: String

if YPConfig.video.shouldAlwaysProcessVideo {
presetName = compressionTypeOverride ?? YPConfig.video.compression
} else {
presetName = compressionTypeOverride ?? (videoIsCropped || videoIsTrimmed || videoIsRotated || (shouldMute && isSlowMoVideo) ? YPConfig.video.compression : AVAssetExportPresetPassthrough)
}


var videoComposition:AVMutableVideoComposition?

if videoIsCropped {
Expand Down Expand Up @@ -250,6 +258,13 @@ open class LibraryMediaManager {
videoComposition?.renderSize = CGSize(width: roundedWidth, height: roundedHeight)
}

// If we can detect the video is a Slow mo video or we've had a previous processing failure, apply the frame duration / sourceTrackIDForFrameTiming
// which allows Slow Mo video types to be processed with a selected preset without video composition failures.
if isSlowMoVideo || processingFailedRetryCount == 1 {
videoComposition?.frameDuration = CMTimeMake(value: 1, timescale: 30)
videoComposition?.sourceTrackIDForFrameTiming = kCMPersistentTrackID_Invalid
}

let fileURL = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingUniquePathComponent(pathExtension: YPConfig.video.fileType.fileExtension)
let exportSession = assetComposition
Expand All @@ -271,15 +286,19 @@ open class LibraryMediaManager {
callback(nil)
}
case .failed:
if compressionTypeOverride == nil, let self = self {
let compressionOverride = presetName == AVAssetExportPresetPassthrough ? YPConfig.video.compression : AVAssetExportPresetPassthrough
if let self = self {
var retryCount = processingFailedRetryCount
retryCount += 1
// Try one more time to process with the export settings on the YPConfig.
let compressionOverride = YPConfig.video.compression
ypLog("LibraryMediaManager -> Export of the video failed. Reason: \(String(describing: session.error))\n--- Retrying with compression type \(compressionOverride)")
self.stopExportTimer(for: session)
self.fetchVideoUrlAndCrop(for: videoAsset, cropRect: cropRect, timeRange: timeRange, shouldMute: shouldMute, compressionTypeOverride: compressionOverride, callback: callback)
}
else {
ypLog("LibraryMediaManager -> Export of the video failed. Reason: \(String(describing: session.error))")
self?.stopExportTimer(for: session)
if retryCount > 1 {
callback(nil)
} else {
self.fetchVideoUrlAndCrop(for: videoAsset, cropRect: cropRect, timeRange: timeRange, shouldMute: shouldMute, compressionTypeOverride: compressionOverride, processingFailedRetryCount: retryCount , callback: callback)
}
} else {
callback(nil)
}
default:
Expand Down
4 changes: 2 additions & 2 deletions Source/Pages/Gallery/YPLibraryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ internal final class YPLibraryView: UIView {
let cropView = assetZoomableView
let normalizedX = min(1, cropView.contentOffset.x &/ cropView.contentSize.width)
let normalizedY = min(1, cropView.contentOffset.y &/ cropView.contentSize.height)
let normalizedWidth = min(1, cropView.frame.width / cropView.contentSize.width)
let normalizedHeight = min(1, cropView.frame.height / cropView.contentSize.height)
let normalizedWidth = min(1, cropView.frame.width / cropView.contentSize.width.rounded())
let normalizedHeight = min(1, cropView.frame.height / cropView.contentSize.height.rounded())
return CGRect(x: normalizedX, y: normalizedY, width: normalizedWidth, height: normalizedHeight)
}

Expand Down

0 comments on commit 74ca8d2

Please sign in to comment.