在 AVPlayer 中播放慢动作 AVAsset 的问题
Posted
技术标签:
【中文标题】在 AVPlayer 中播放慢动作 AVAsset 的问题【英文标题】:Issue playing slow-mo AVAsset in AVPlayer 【发布时间】:2016-05-01 00:58:45 【问题描述】:我正在尝试在AVPlayer
中播放慢动作视频(由用户的 iPhone 拍摄)。
我正在检索 AVAsset
,并从一个选择器请求 PHAsset
:
[manager requestAVAssetForVideo:PHAsset
options:videoRequestOptions
resultHandler:^(AVAsset * avasset, AVAudioMix * audioMix, NSDictionary * info) ];
问题是一旦播放,我得到这个错误:
-[AVComposition URL]: unrecognized selector sent to instance 0x138d17f40
但是,如果我在经理请求中设置此选项,它将以 120/240fps 的正常速度视频播放并且不会崩溃:
videoRequestOptions.version = PHVideoRequestOptionsVersionOriginal;
怎么了?默认的version
属性是PHVideoRequestOptionsVersionCurrent
,它包含慢动作、用户编辑和修剪等。
我想播放那个视频版本。谢谢
【问题讨论】:
你能解决这个问题吗?我正在录制慢动作视频,而不是从库中获取它。如果我将它保存在图书馆中,它可以正常工作,而且速度很慢。如果我在我的应用程序中的 AVPLayer 中查看它,慢动作将不起作用。 【参考方案1】:原来慢动作视频是作为AVComposition
传递的。
您可以将其导出到视频文件/网址中,然后像处理任何其他视频一样处理它。
这里的解决方案:https://overflow.buffer.com/2016/02/29/slow-motion-video-ios/
//Output URL
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = paths.firstObject;
NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"mergeSlowMoVideo-%d.mov",arc4random() % 1000]];
NSURL *url = [NSURL fileURLWithPath:myPathDocs];
//Begin slow mo video export
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL = url;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^
dispatch_async(dispatch_get_main_queue(), ^
if (exporter.status == AVAssetExportSessionStatusCompleted)
NSURL *URL = exporter.outputURL;
NSData *videoData = [NSData dataWithContentsOfURL:URL];
// Upload
[self uploadSelectedVideo:video data:videoData];
);
];
【讨论】:
感谢您提供此解决方案,但是我还有一些额外的问题。我使用上面的代码在 AVPlayerViewController 中播放视频。但是,当我调用“player.currentItem.currentTime.value”时,它的行为很奇怪。我已经花了足够的时间知道,如果我从照片应用程序进入视频,并制作整个视频慢动作或正常动作,我就能获得稳定的行为。这只是标准的 iPhone 默认设置(在视频不以慢动作显示的开头和结尾制作一小段),奇怪的行为开始了。知道如何将其保存为仅慢动作吗? 这是从照片库中挑选的情况。如果我录制慢动作视频然后想上传它怎么办? ***.com/questions/47514282/…【参考方案2】:对于那些来这里寻找快速答案的人,这是我在项目中使用的快速翻译,我需要慢动作视频的 url 来使用AVPlayerViewController
播放它:
else if asset is AVComposition
//Slow-Motion Assets are passed as AVComposition
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory: NSString? = paths.first as NSString?
if documentsDirectory != nil
let random = Int(arc4random() % 1000)
let pathToAppend = String(format: "mergeSlowMoVideo-%d.mov", random)
let myPathDocs = documentsDirectory!.strings(byAppendingPaths: [pathToAppend])
let myPath = myPathDocs.first
if myPath != nil
let url = URL(fileURLWithPath: myPath!)
let exporter = AVAssetExportSession(asset: asset!, presetName: AVAssetExportPresetHighestQuality)
if exporter != nil
exporter!.outputURL = url
exporter!.outputFileType = AVFileTypeQuickTimeMovie
exporter!.shouldOptimizeForNetworkUse = true
exporter!.exportAsynchronously(completionHandler:
AsyncUtil.asyncMain
let url = exporter!.outputURL
if url != nil
let player = AVPlayer(url: url!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
playerViewController.modalTransitionStyle = .crossDissolve
view.present(playerViewController, animated: true)
playerViewController.player!.play()
)
【讨论】:
【参考方案3】:使用自定义视图在 Swift 4 n 以上播放慢动作和库视频
var vcPlayer = AVPlayerViewController()
var player = AVPlayer()
func playallVideo(_ customView: UIView, asset: PHAsset)
guard asset.mediaType == .video
else
print("Not a valid video media type")
return
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true
PHCachingImageManager().requestPlayerItem(forVideo: asset, options: options) (playerItem, info) in
DispatchQueue.main.async
self.player = AVPlayer(playerItem: playerItem)
self.vcPlayer.player = self.player
self.vcPlayer.view.frame = customView.bounds
self.vcPlayer.videoGravity = .resizeAspectFill
self.vcPlayer.showsPlaybackControls = true
//self.vcPlayer.allowsPictureInPicturePlayback = true
self.playerView.addSubview(self.vcPlayer.view)
self.player.play()
/**********Function Call ********/
self.playallVideo(self.playerView/*YourCustomView*/, asset: currentAssetArr[currentIndex]/*Current PHAsset Fetched from Library*/)
:) 享受
【讨论】:
【参考方案4】:在 Swift 中寻找答案? 我是这样做的
在 iOS swift 中创建“慢动作”视频并不容易,我遇到了许多“慢动作”,知道它们不起作用或者其中的一些代码已被贬值。所以我终于找到了一种在 Swift 中制作慢动作的方法。 此代码可用于 120fps 也大于此。
这是“我为实现慢动作而创建的代码 sn-p”
如果此代码有效,请给我一个 UPVOTE。
func slowMotion(pathUrl: URL)
let videoAsset = AVURLAsset.init(url: pathUrl, options: nil)
let currentAsset = AVAsset.init(url: pathUrl)
let vdoTrack = currentAsset.tracks(withMediaType: .video)[0]
let mixComposition = AVMutableComposition()
let compositionVideoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
let videoInsertError: Error? = nil
var videoInsertResult = false
do
try compositionVideoTrack?.insertTimeRange(
CMTimeRangeMake(start: .zero, duration: videoAsset.duration),
of: videoAsset.tracks(withMediaType: .video)[0],
at: .zero)
videoInsertResult = true
catch let videoInsertError
if !videoInsertResult || videoInsertError != nil
//handle error
return
var duration: CMTime = .zero
duration = CMTimeAdd(duration, currentAsset.duration)
//MARK: You see this constant (videoScaleFactor) this helps in achieving the slow motion that you wanted. This increases the time scale of the video that makes slow motion
// just increase the videoScaleFactor value in order to play video in higher frames rates(more slowly)
let videoScaleFactor = 2.0
let videoDuration = videoAsset.duration
compositionVideoTrack?.scaleTimeRange(
CMTimeRangeMake(start: .zero, duration: videoDuration),
toDuration: CMTimeMake(value: videoDuration.value * Int64(videoScaleFactor), timescale: videoDuration.timescale))
compositionVideoTrack?.preferredTransform = vdoTrack.preferredTransform
let dirPaths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).map(\.path)
let docsDir = dirPaths[0]
let outputFilePath = URL(fileURLWithPath: docsDir).appendingPathComponent("slowMotion\(UUID().uuidString).mp4").path
if FileManager.default.fileExists(atPath: outputFilePath)
do
try FileManager.default.removeItem(atPath: outputFilePath)
catch
let filePath = URL(fileURLWithPath: outputFilePath)
let assetExport = AVAssetExportSession(
asset: mixComposition,
presetName: AVAssetExportPresetHighestQuality)
assetExport?.outputURL = filePath
assetExport?.outputFileType = .mp4
assetExport?.exportAsynchronously(completionHandler:
switch assetExport?.status
case .failed:
print("asset output media url = \(String(describing: assetExport?.outputURL))")
print("Export session faiied with error: \(String(describing: assetExport?.error))")
DispatchQueue.main.async(execute:
// completion(nil);
)
case .completed:
print("Successful")
let outputURL = assetExport!.outputURL
print("url path = \(String(describing: outputURL))")
phphotoLibrary.shared().performChanges(
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputURL!)
) saved, error in
if saved
print("video successfully saved in photos gallery view video in photos gallery")
if (error != nil)
print("error in saing video \(String(describing: error?.localizedDescription))")
DispatchQueue.main.async(execute:
// completion(_filePath);
)
case .none:
break
case .unknown:
break
case .waiting:
break
case .exporting:
break
case .cancelled:
break
case .some(_):
break
)
【讨论】:
以上是关于在 AVPlayer 中播放慢动作 AVAsset 的问题的主要内容,如果未能解决你的问题,请参考以下文章