AVFoundation系列一: AVAsset的使用方法

xiaoxiao2022-06-12  37

AVAsset 是AVFoundation的操作模型,其中包含音频,视频,字幕,元数据。

GPUImage系列专栏 参考:AVFoundation Programming Guide

AVFoundation系列五:关于音视频的导出 AVFoundation系列四:如何配置一个合格的Camera AVFoundation系列三:音视频编辑 AVFoundation系列二:用AVPlayer播放视频

本文将从以下几个方面介绍AVAsset

Demo 地址

1. AVAsset的加载方式 2. 播放一个AVAsset 3. 获取一个asset的相关属性 4. 从相册加载AVAsset 5. loadValuesAsynchronously的使用 6. 从视频中获取视频帧 图像 7. 通过一个AVAsset导出音频,设置时间裁剪 8. 通过一个AVAsset导出视频,设置时间裁剪

一、AVAsset的加载方式 第一种加载方式

let path = Bundle.main.path(forResource: "3", ofType: "mp4") let asset = AVAsset.init(url: URL.init(fileURLWithPath: path!, isDirectory: true))

第二种加载方式

let options = [AVURLAssetPreferPreciseDurationAndTimingKey:true] let asset = AVURLAsset.init(url: URL.init(fileURLWithPath: path!, isDirectory: true), options: options)

其中:AVURLAssetPreferPreciseDurationAndTimingKey 获取精确时间 通常不会再播放时使用 URL.init(fileURLWithPath: path!, isDirectory: true)如果URL是一个文件路径,苹果建议加上isDirectory

二、播放一个AVAsset 由于生命周期的原因,我们添加两个成员变量:

var player:AVPlayer? var playerItem:AVPlayerItem?

播放:

func plackTrack(track:AVAssetTrack?){ guard let asset = track?.asset else{ return } playerItem = AVPlayerItem.init(asset: asset) player = AVPlayer.init(playerItem: playerItem!) let playerlayer = AVPlayerLayer.init(player: player!) playerlayer.frame = view.bounds self.view.layer.addSublayer(playerlayer) player?.play() }

AVAssetTrack 如: let audioTrack = asset.tracks(withMediaType: .audio) let videoTrack = asset.tracks(withMediaType: .video)

三、获取一个asset的相关属性

func getAssetAttribute(){ let path = Bundle.main.path(forResource: "3", ofType: "mp4") let asset = AVAsset.init(url: URL.init(fileURLWithPath: path!, isDirectory: true)) //时长 let duration = asset.duration.seconds //歌词 let lyrics = asset.lyrics //创建时间 通常从相册加载时会有数据 let creatDate = asset.creationDate?.dataValue //相关信息 如 iso let metadata = asset.metadata(forFormat: .isoUserData) print(duration,lyrics ?? "",creatDate ?? "",metadata) }

四、从相册加载AVAsset 这里没有写相关代码,请参考PhotoKit

五、loadValuesAsynchronously的使用

func asyncLoadInfo(){ let path = Bundle.main.path(forResource: "3", ofType: "mp4") let asset = AVAsset.init(url: URL.init(fileURLWithPath: path!, isDirectory: true)) ///当一个asset加载时,它的部分属性是未知的,因此需要 asset来完成指定的加载 asset.loadValuesAsynchronously(forKeys: ["playable"]) { var error: NSError? let keyStatus = asset.statusOfValue(forKey: "playable", error: &error) } }

六、从视频中获取视频帧 图像

func getImageByAsset(){ let path = Bundle.main.path(forResource: "3", ofType: "mp4") let asset = AVAsset.init(url: URL.init(fileURLWithPath: path!, isDirectory: true)) if asset.tracks(withMediaType: .video).count > 0 { let imgGen = AVAssetImageGenerator.init(asset: asset) //最大尺寸 imgGen.maximumSize = CGSize.init(width: 100, height: 100) //光圈 imgGen.apertureMode = AVAssetImageGenerator.ApertureMode.cleanAperture //异步加载多个 imgGen.generateCGImagesAsynchronously(forTimes: [CMTime.zero as NSValue]) { (time1, cgimg, time2, result, error) in if let _cgimg = cgimg { let img = UIImage.init(cgImage: _cgimg) print("async get a img by asset") } } var actrueTime:CMTime = CMTime.zero //同步加载一个 if let cgimg = try? imgGen.copyCGImage(at: CMTime.zero, actualTime: &actrueTime){ let img = UIImage.init(cgImage: cgimg) print("sync get a img by asset") } } }

generateCGImagesAsynchronously可以一次性异步加载多个 videoComposition 与 appliesPreferredTrackTransform冲突,会导致彼此失效

七、通过一个AVAsset导出音频、视频,设置时间裁剪

func exportAsset(){ guard let path = Bundle.main.path(forResource: "3", ofType: "mp4") else{ return } let url = URL.init(fileURLWithPath: path) let asset = AVAsset.init(url: url) let videoTracks = asset.tracks(withMediaType: .video) let audioTracks = asset.tracks(withMediaType: .audio) let firstVideoTrack = videoTracks.first let firstAudioTrack = audioTracks.first //视频 let videocomposition = AVMutableComposition.init() if let compositionVideoTrack = videocomposition.addMutableTrack(withMediaType: .video, preferredTrackID: 0){ if firstVideoTrack != nil{ try? compositionVideoTrack.insertTimeRange(firstVideoTrack!.timeRange, of: firstVideoTrack!, at: .zero) videoExportSession(asset: videocomposition) } } //音频 let audiocomposition = AVMutableComposition.init() if let compositionAudioTrack = audiocomposition.addMutableTrack(withMediaType: .audio, preferredTrackID: 0){ if firstAudioTrack != nil{ try? compositionAudioTrack.insertTimeRange(firstAudioTrack!.timeRange, of: firstAudioTrack!, at: .zero) audioExportSession(asset: audiocomposition) } } }

可以调用 cancelExport 来取消 导出 audioExport?.cancelExport() AVMutableComposition 用于控制组件成分,本身是AVAsset的子类,意味着它可以像,AVAsset一样被用于播放。

//导出 func audioExportSession(asset:AVAsset){ let presetNames = AVAssetExportSession.exportPresets(compatibleWith: asset) if presetNames.contains(AVAssetExportPresetAppleM4A) { audioExport = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetAppleM4A) }else{ audioExport = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetPassthrough) } audioExport?.outputURL = getAudioExportURL() audioExport?.outputFileType = AVFileType.m4a audioExport?.shouldOptimizeForNetworkUse = true audioExport?.exportAsynchronously(completionHandler: {[weak self]in print(self?.audioExport?.error) }) } //获取url func getAudioExportURL()->URL{ let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let fileName = "Quinn_export" + ".m4a" let url = path.appendingPathComponent(fileName) if FileManager.default.fileExists(atPath: url.path){ try? FileManager.default.removeItem(at: url) } print("quinn",url) return url }

其中:videoExport、audioExport 为 AVAssetExportSession,在接下来的文章会介绍到。 presetNames 本视频支持导出的格式 AVAssetExportPresetPassthrough 为模拟器支持格式. 如果想要裁剪 设置相关参数 audioExport?.timeRange = getTimeRange(asset:asset) 时间裁剪方法:

//公共函数 //设置裁剪参数 func getTimeRange(asset:AVAsset)->CMTimeRange{ print(asset.duration.timescale) let start = CMTimeMake(value: Int64(asset.duration.timescale * 10), timescale: asset.duration.timescale) let end = CMTimeMake(value: Int64(asset.duration.timescale * 30), timescale: asset.duration.timescale) let range = CMTimeRange.init(start: start, end: end) return range }

同理 ,视频导出代码如下:

/// 视频相关 extension ViewController{ //导出 func videoExportSession(asset:AVAsset){ // presetNames 本视频支持导出的格式 AVAssetExportPresetPassthrough 为模拟器支持格式 let presetNames = AVAssetExportSession.exportPresets(compatibleWith: asset) //设置 AVAssetExportPreset640x480等可选参数,会导致视频压缩,但还需研究VideoTool,进一步做压缩处理 videoExport = AVAssetExportSession.init(asset: asset, presetName: presetNames.first ?? AVAssetExportPresetPassthrough) videoExport?.outputURL = getVideoExportURL() videoExport?.outputFileType = AVFileType.mp4 ///如果想要裁剪 设置相关参数 // videoExport?.timeRange = getTimeRange(asset:asset) videoExport?.exportAsynchronously(completionHandler: {[weak self]in print(self?.audioExport?.error) }) } //获取url func getVideoExportURL()->URL{ let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let fileName = "Quinn_export" + ".mp4" let url = path.appendingPathComponent(fileName) if FileManager.default.fileExists(atPath: url.path){ try? FileManager.default.removeItem(at: url) } print("quinn",url) return url } }
转载请注明原文地址: https://www.6miu.com/read-4932316.html

最新回复(0)