ios 在AVPlayer中播放慢速AVAsset时出现问题

j2datikz  于 2023-08-08  发布在  iOS
关注(0)|答案(5)|浏览(133)

我正在尝试在AVPlayer中播放慢动作视频(由用户的iPhone拍摄)。
我正在检索AVAsset,并从picker中请求PHAsset

[manager requestAVAssetForVideo:PHAsset
                           options:videoRequestOptions
                     resultHandler:^(AVAsset * avasset, AVAudioMix * audioMix, NSDictionary * info) {}];

字符串
问题是一旦它播放,我得到这个错误:

-[AVComposition URL]: unrecognized selector sent to instance 0x138d17f40


但是,如果我在管理器请求中设置此选项,它将以120/240 fps的正常速度播放视频,并且不会崩溃:

videoRequestOptions.version = PHVideoRequestOptionsVersionOriginal;


怎么回事?默认的version属性是PHVideoRequestOptionsVersionCurrent,它包含慢动作、用户编辑和修剪等。
我想播放那个视频版本。谢啦,谢啦

b5buobof

b5buobof1#

因此,慢动作视频被传递为AVComposition
您可以将其导出到视频文件/ URL中,然后像处理任何其他视频一样处理它。
解决方案: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];
         }
    });
}];

字符串

vm0i2vca

vm0i2vca2#

对于那些来这里寻找快速答案的人,这是我在我的项目中使用的swift翻译,我需要慢动作视频的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()
                    }
                }
            }
        })
    }
}

字符串

ufj5ltwl

ufj5ltwl3#

使用自定义视图在Swift 4n以上版本中播放慢动作和库视频

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*/)

字符串

  • :)享受 *
nlejzf6q

nlejzf6q4#

在Swift中寻找答案?我是这样做
在iOS swift中创建“慢动作”视频并不容易,我遇到了许多“慢动作”,后来知道不工作或其中的一些代码被贬值。所以我终于找到了一种在斯威夫特中制作慢动作的方法。此代码可用于120fps以上的情况。.
下面是“我为实现慢动作而创建的代码片段”
如果这段代码有效,请给予我一个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
        }
    })
}

字符串

n1bvdmb6

n1bvdmb65#

Swift版本的投票答案:

// Output URL
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    guard let documentsDirectory = paths.first else {
        return
    }
    let fileName = String(format: "mergeSlowMoVideo-%d.mov", Int(arc4random_uniform(1000)))
    let url = documentsDirectory.appendingPathComponent(fileName)
    
    // Begin slow mo video export
    guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else {
        return
    }
    exporter.outputURL = url
    exporter.outputFileType = .mov
    exporter.shouldOptimizeForNetworkUse = true
    
    exporter.exportAsynchronously {
        DispatchQueue.main.async {
            if exporter.status == .completed {
                guard let url = exporter.outputURL, let videoData = try? Data(contentsOf: url) else {
                    return
                }
                // Upload
                self.uploadSelectedVideo(video: url, data: videoData)
            }
        }
    }

字符串

相关问题