【问题标题】:i am trying to merge an audio and a video and save to photos library ios swift我正在尝试合并音频和视频并保存到照片库 ios swift
【发布时间】:2018-02-04 17:35:15
【问题描述】:

我的音频和视频将来自 Document 目录。当我将视频保存到照片中时,一切正常。但是后来发生了这个错误并且没有保存。

failed Optional(Error Domain=AVFoundationErrorDomain Code=-11800 "操作无法完成" UserInfo={NSUnderlyingError=0x17044a2f0 {Error Domain=NSOSStatusErrorDomain Code=-12842 "(null)"}, NSLocalizedFailureReason=发生未知错误(-12842), NSLocalizedDescription=操作无法完成})

这是我的功能

 func getData(){
        let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

        do {
            // Get the directory contents urls (including subfolders urls)
            let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: [])
            print(directoryContents)

            // if you want to filter the directory contents you can do like this:
            videoUrlforMarge = directoryContents.filter{ $0.pathExtension == "mov" } as [AnyObject]
            //videoUrlforMarge.append(directoryContents[1] as AnyObject)
            print("this video \(videoUrlforMarge[0])")

            audioUrl = directoryContents.filter{ $0.pathExtension == "caf" } as [AnyObject]

        } catch let error as NSError {
            print(error.localizedDescription)
        }

    }

这是我的合并函数

   func mergeFilesWithUrl(videoUrl:NSURL, audioUrl:NSURL)
    {
        let mixComposition : AVMutableComposition = AVMutableComposition()
        var mutableCompositionVideoTrack : [AVMutableCompositionTrack] = []
        var mutableCompositionAudioTrack : [AVMutableCompositionTrack] = []
        let totalVideoCompositionInstruction : AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction()


        //start merge



        let aVideoAsset : AVAsset = AVAsset(url: videoUrl as URL)
        let aAudioAsset : AVAsset = AVAsset(url: audioUrl as URL)

        mutableCompositionVideoTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid))
        mutableCompositionAudioTrack.append( mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid))

        guard aVideoAsset.tracks(withMediaType: AVMediaTypeVideo).count > 0 && aAudioAsset.tracks(withMediaType: AVMediaTypeAudio).count > 0 else{
            return
        }
        let aVideoAssetTrack : AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaTypeVideo)[0]
        let aAudioAssetTrack : AVAssetTrack = aAudioAsset.tracks(withMediaType: AVMediaTypeAudio)[0]



        do{
            try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), of: aVideoAssetTrack, at: kCMTimeZero)

            try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: kCMTimeZero)

        }catch{

        }

        totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,aVideoAssetTrack.timeRange.duration )

        let mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition()
        mutableVideoComposition.frameDuration = CMTimeMake(1, 30)

        mutableVideoComposition.renderSize = CGSize(width: 1280, height: 720)


        let VideoFilePath = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("mergeVideo\(arc4random()%1000)d")!.appendingPathExtension("mp4").absoluteString
        if FileManager.default.fileExists(atPath: VideoFilePath)

        {
            do

            {
                try FileManager.default.removeItem(atPath: VideoFilePath)
            }
            catch { }

        }
        let tempfilemainurl =  NSURL(string: VideoFilePath)!
        let sourceAsset = AVURLAsset(url: tempfilemainurl as URL, options: nil)
        let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetMediumQuality)!
        assetExport.outputFileType = AVFileTypeQuickTimeMovie
        assetExport.outputURL = tempfilemainurl as URL


        assetExport.exportAsynchronously { () -> Void in
            switch assetExport.status
            {
            case AVAssetExportSessionStatus.completed:
                DispatchQueue.main.async(execute: {
                    do
                    {

                        self.userreponsevideoData = try NSData(contentsOf: tempfilemainurl as URL, options: NSData.ReadingOptions())
                        print("MB - \(self.userreponsevideoData.length) byte")
                        let assetsLib = ALAssetsLibrary()
                        assetsLib.writeVideoAtPath(toSavedPhotosAlbum: tempfilemainurl as URL!, completionBlock: nil)




                    }
                    catch
                    {

                        print(error)
                    }
                })
            case  AVAssetExportSessionStatus.failed:
                print("failed \(String(describing: assetExport.error))")
            case AVAssetExportSessionStatus.cancelled:
                print("cancelled \(String(describing: assetExport.error))")
            default:
                print("complete")

            }

        }
}

和其他我称之为合并函数的函数

func Action(){
  guard videoUrlforMarge.count > 0 && audioUrl.count > 0 else{
                return
            }
            let videoUrl  = videoUrlforMarge[0]
            let url = NSURL(fileURLWithPath: videoUrl.absoluteString!!)
            let audio  = audioUrl[0]
            let urla = NSURL(fileURLWithPath: audio.absoluteString!!)

            self.mergeFilesWithUrl(videoUrl: url as NSURL  , audioUrl: 
  urla as NSURL

}

【问题讨论】:

  • 无重播。为什么为什么:(
  • 您是否将所需的警告添加到 .plist 中? (隐私 - 照片库使用说明)用户是否批准您访问照片库?
  • 是的..我添加了这个

标签: ios swift


【解决方案1】:
import Photos
import PhotosUI

我认为您在提供信息和代码方面做得很好。现在是星期天早上,所以也许专家们在睡觉?由于您的错误消息非常神秘,我认为这是一个权限问题,也许您还没有更新您的 Info.plist 以包含所需的“隐私 - 照片库使用说明”条目。此外,当第一次运行时,用户必须接受您的访问请求才能保存到库才能工作。 [您没有显示该代码,并且您的代码都没有从照片库请求(和接收)数据 - 这就是为什么我认为这是问题所在。] 需要这样的东西:

func configureGalleryAccess() {

    PHPhotoLibrary.requestAuthorization({(_ status: PHAuthorizationStatus) -> Void in switch status {
        case .authorized:
            print("PHAuthorizationStatusAuthorized")
            self.postAuthorizationLoadController() // replace with your code
        case .denied:
            print("PHAuthorizationStatusDenied")
        case .notDetermined:
            print("PHAuthorizationStatusNotDetermined")
        case .restricted:
            print("PHAuthorizationStatusRestricted")
        }
    })
}

错误消息抱怨您正在尝试保存它不允许的 nil 对象。因此,通过调试器运行程序,在保存对象/照片之前设置断点。如果您在未预料到的地方发现 nil,请备份直到找到问题所在。并在保存可选项时在保存前检查 nil。

【讨论】:

  • phphotoLibrary 是否需要任何模块导入??
  • 是的。我在上面添加了它:照片和(可能 - 取决于使用)PhotosUI
  • 还是一样的问题 :(
  • 这取决于照片
  • 实际上,当我创建一个示例项目并通过此代码时,它第一次和第二次工作,但在几次字母后它给出了这个错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-31
  • 1970-01-01
  • 2019-05-24
  • 2019-11-26
  • 1970-01-01
相关资源
最近更新 更多