gpt4 book ai didi

ios - 如何拆分视频的前 15 秒并将其快速保存到相机胶卷

转载 作者:行者123 更新时间:2023-11-28 07:46:14 29 4
gpt4 key购买 nike

我正在尝试抓取从 UIImagePicker 中选择的任何视频的前 15 秒,然后将其保存到照片库中。我正在使用 AVFoundation 抓取前 15 秒,然后另存为新文件。我认为问题是我没有正确保存它,但我不确定。此时代码似乎可以正常运行。

import UIKit
import MobileCoreServices
import AVFoundation
import Photos

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var spliceSeconds = 15.0
var preferredPreset = AVAssetExportPresetPassthrough

@IBOutlet weak var bnLibrary: UIButton!
@IBOutlet weak var bnCamera: UIButton!

override func viewDidLoad() {
super.viewDidLoad()
authVideoAccess()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func authVideoAccess() {

let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized:
print("authorized")
break
case .denied:
//alert
print("denied")
break
case .notDetermined:
PHPhotoLibrary.requestAuthorization { (newStatus) in
print("status is \(newStatus)")
if newStatus == PHAuthorizationStatus.authorized {
/* do stuff here */
print("success")
}
}
print("It is not determined until now")
break
case .restricted:
print("permission restricted")
break
default:
// show something eles
print("default")
break
}


}

@IBAction func getVideo(_ sender: UIButton) {
if sender == bnCamera {
self.openCamera()
} else {
self.openVideoLibrary()
}
}

func openCamera() {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let myPickerController = UIImagePickerController()
myPickerController.delegate = self
myPickerController.sourceType = .camera
myPickerController.mediaTypes = [kUTTypeMovie as String]
self.present(myPickerController, animated: true, completion: nil)
}
}

func openVideoLibrary() {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let myPickerController = UIImagePickerController()
myPickerController.delegate = self
myPickerController.sourceType = .photoLibrary
myPickerController.mediaTypes = [kUTTypeMovie as String, kUTTypeVideo as String]
self.present(myPickerController, animated: true, completion: nil)
}

}

//pragmark - delegate methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

let vidUrl:URL = info[UIImagePickerControllerMediaURL]! as! URL
let options = [ AVURLAssetPreferPreciseDurationAndTimingKey: true ]
let asset = AVURLAsset(url: vidUrl, options: options)


if verifyPresetForAsset(preset: self.preferredPreset, asset: asset) {
let assetVideoTrack: AVAssetTrack = asset.tracks(withMediaType: AVMediaType.video).first!
let assetAudioTrack: AVAssetTrack = asset.tracks(withMediaType: AVMediaType.audio).first!
let startTime = assetAudioTrack.timeRange.start
let endTime = CMTimeMakeWithSeconds(spliceSeconds, startTime.timescale)

if assetVideoTrack.timeRange.duration.seconds > spliceSeconds {
trimVideo(assetVideoTrack: assetVideoTrack, assetAudioTrack: assetAudioTrack, startTime: startTime, endTime: endTime )
} else {
//show a message
}
}


//print(info[UIImagePickerControllerMediaURL]!)
}



func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 1
}

//pragmamark - trim stuff
func verifyPresetForAsset(preset: String, asset: AVAsset) -> Bool {
let compatiblePresets = AVAssetExportSession.exportPresets(compatibleWith: asset)
let filteredPresets = compatiblePresets.filter { $0 == preset }
return filteredPresets.count > 0 || preset == AVAssetExportPresetPassthrough
}


func getNewFilePath() -> String {
let paths = FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask)
return paths[0].absoluteString + "StorySplitter-" + UUID().uuidString + ".mp4"
}

func trimVideo(assetVideoTrack: AVAssetTrack, assetAudioTrack: AVAssetTrack, startTime: CMTime, endTime: CMTime) -> Void {

var accumulatedTime = kCMTimeZero

let durationOfCurrentSlice = CMTimeSubtract(endTime, startTime)
let timeRangeForCurrentSlice = CMTimeRangeMake(startTime, endTime)

let composition = AVMutableComposition()
let videoCompTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: CMPersistentTrackID())
let audioCompTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: CMPersistentTrackID())



do {
try videoCompTrack?.insertTimeRange(timeRangeForCurrentSlice, of: assetVideoTrack, at: accumulatedTime)
try audioCompTrack?.insertTimeRange(timeRangeForCurrentSlice, of: assetAudioTrack, at: accumulatedTime)
accumulatedTime = CMTimeAdd(accumulatedTime, durationOfCurrentSlice)
}
catch let compError {
print("TrimVideo: error during composition: \(compError)")
}

accumulatedTime = CMTimeAdd(accumulatedTime, durationOfCurrentSlice)

let exportSession = AVAssetExportSession(asset: composition, presetName: self.preferredPreset)
exportSession?.outputURL = URL(fileURLWithPath: getNewFilePath())
exportSession?.outputFileType = AVFileType.mp4
exportSession?.shouldOptimizeForNetworkUse = true

exportSession?.exportAsynchronously {
print("finished saving")
}


}

}

最佳答案

exportSession?.exportAsynchronously 

不会保存到照片库,而只是保存到您指定的 outputURL,它位于您应用的沙箱内。如果你把 URL 打印出来,它会是这样的

file:///var/mobile/Containers/Data/Application/520D8354-B1D2-465F-93C2-54F2528D1AA9/Pictures/StorySplitter-528229F9-4D4F-4E28-82C9-3B1F2FDB215B.mp4

将上述 URL 中的 mp4 保存到图片库的额外工作。

exportSession?.exportAsynchronously {
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: newURL)
}) { saved, error in
// handle here
}
}

另外,您的 func getNewFilePath() -> String,而不是使用 FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask),您需要更改为 NSTemporaryDirectory().appendingFormat("yourVideoName.mov")

看起来 PHPPhotoLibrary 无法从 FileManager 访问 URL,但可以通过 NSTemporaryDirectory() 访问

仅供引用:以上两个网址文件管理器路径:

file:///var/mobile/Containers/Data/Application/520D8354-B1D2-465F-93C2-54F2528D1AA9/Pictures/StorySplitter-528229F9-4D4F-4E28-82C9-3B1F2FDB215B.mp4

临时路径:

/private/var/mobile/Containers/Data/Application/520D8354-B1D2-465F-93C2-54F2528D1AA9/tmp/video.mov

主要区别是files:///privatefiles:///会使URL成为绝对URL,所以在您的 trimVideo 函数中,您必须使用 URL(string: getNewFilePath()) 作为导出 URL。

由于同一个 URL 必须使用两次并且 getNewFilePath()) 每次都获得唯一的 URL,您需要将它保存在一个变量中,以便在 exportSession?.exportAsynchronously,您仍然可以为 PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: newURL)

引用相同的 URL

关于ios - 如何拆分视频的前 15 秒并将其快速保存到相机胶卷,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50958629/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com