我有一个包含这些规格的视频
- 格式:H.264,1280x544
- FPS:25
- 数据大小:26MB
- 时长:3:00
- 数据速率:1.17 Mbit / s
在试验期间,我在每个其他帧上执行了removeTimeRange(range : CMTimeRange)
(总帧数= 4225 )。这导致视频速度提高2倍,因此持续时间变为 1:30 。
然而,当我导出视频时,视频的大小增加了12倍,即 325MB 。这是有道理的,因为这项技术将视频分解为约 2112 块并拼接它回到了一起。显然,在这样做时,各个帧之间的压缩会丢失,从而导致巨大的尺寸。
当使用AVPlayer
进行播放时,会导致视频中出现口吃,因此效果不佳。
问题:如何在拼接框架时应用某种压缩方式,以便视频可以流畅播放并且尺寸更小?
我只想要一个正确的方向。谢谢!
CODE
1)从Asset&创建AVMutableComposition配置
func configureAssets(){
let options = [AVURLAssetPreferPreciseDurationAndTimingKey : "true"]
let videoAsset = AVURLAsset(url: Bundle.main.url(forResource: "Push", withExtension: "mp4")! , options : options)
let videoAssetSourceTrack = videoAsset.tracks(withMediaType: AVMediaTypeVideo).first! as AVAssetTrack
let comp = AVMutableComposition()
let videoCompositionTrack = comp.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)
do {
try videoCompositionTrack.insertTimeRange(
CMTimeRangeMake(kCMTimeZero, videoAsset.duration),
of: videoAssetSourceTrack,
at: kCMTimeZero)
deleteSomeFrames(from: comp)
videoCompositionTrack.preferredTransform = videoAssetSourceTrack.preferredTransform
}catch { print(error) }
asset = comp }
2)删除每隔一帧。
func deleteSomeFrames(from asset : AVMutableComposition){
let fps = Int32(asset.tracks(withMediaType: AVMediaTypeVideo).first!.nominalFrameRate)
let sumTime = Int32(asset.duration.value) / asset.duration.timescale;
let totalFrames = sumTime * fps
let totalTime = Float(CMTimeGetSeconds(asset.duration))
let frameDuration = Double(totalTime / Float(totalFrames))
let frameTime = CMTime(seconds: frameDuration, preferredTimescale: 1000)
for frame in Swift.stride(from: 0, to: totalFrames, by: 2){
let timing = CMTimeMultiplyByFloat64(frameTime, Float64(frame))
print("Asset Duration = \(CMTimeGetSeconds(asset.duration))")
print("")
let timeRange = CMTimeRange(start: timing, duration : frameTime)
asset.removeTimeRange(timeRange)
}
print("duration after time removed = \(CMTimeGetSeconds(asset.duration))")
}
3)保存文件
func createFileFromAsset(_ asset: AVAsset){
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
let filePath = documentsDirectory.appendingPathComponent("rendered-vid.mp4")
if let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality){
exportSession.outputURL = filePath
exportSession.shouldOptimizeForNetworkUse = true
exportSession.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration)
exportSession.outputFileType = AVFileTypeQuickTimeMovie
exportSession.exportAsynchronously {
print("finished: \(filePath) : \(exportSession.status.rawValue) ")
if exportSession.status.rawValue == 4{
print("Export failed -> Reason: \(exportSession.error!.localizedDescription))")
print(exportSession.error!)
}
}}}
4)最后更新ViewController以播放新的Composition!
override func viewDidLoad() {
super.viewDidLoad()
// Create the AVPlayer and play the composition
assetConfig.configureAssets()
let snapshot : AVComposition = assetConfig.asset as! AVComposition
let playerItem = AVPlayerItem(asset : snapshot)
player = AVPlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = CGRect(x : 0, y : 0, width : self.view.frame.width , height : self.view.frame.height)
self.view.layer.addSublayer(playerLayer)
player?.play()
}
答案 0 :(得分:0)
如果您使用AVMutableComposition
,您会注意到每个合成可能包含一个或多个AVCompositionTrack(or AVMutableCompositionTrack)
,编辑合成的最佳方法是操作每个曲目,但不是整个曲目。
但如果您的目的是加快视频的速度,则无需编辑曲目。
所以我会尽力告诉你我对你的问题的了解
请注意您使用的是方法removeTimeRange(range: CMTimeRange)
,此方法会删除构成时的timeRange,但 NOT 会自动填充每个时间范围的空白
Visualize Example
[F stand for Frame,E stand for Empty]
org_video --> F-F-F-F-F-F-F-F...
after remove time range, the composition will be like this
after_video --> F-E-F-E-F-E-F-E...
and you might think that the video will be like this
target_video --> F-F-F-F...
这是播放过程中出现口吃的最可能原因。
因此,如果您想缩短视频,让速度更快/更慢,则可能需要使用方法scaleTimeRange:(CMTimeRange) toDuration:(CMTime)
Example
AVMutableComposition * project;//if this video is 200s
//Scale
project.scaleTimeRange:CMTimeRangeMake(kCMTimeZero, project.duration) toDuration:CMTimeMakeWithSeconds(100,kCMTimeMaxTimescale)
这种方法是让视频更快/更慢。
视频文件的大小可能会受到比特率和格式类型的影响,如果您使用H.264,导致尺寸放大的最可能原因将是比特率。
在您的代码中,您正在使用AVAssetExportSession
AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality
你给出的预设是AVAssetExportPresetHighestQuality
在我自己的应用程序项目中,使用此预设后,无论您的源视频比特率如何,视频的比特率都将为20~30Mbps。并且,使用apple的预设将不允许您手动设置比特率,所以。
还有一个名为SDAVAssetExportSession的第三方工具,此会话将允许您完全配置导出会话,您可能希望尝试研究有关自定义导出会话预设的此代码。
这是我现在可以告诉你的。希望可以提供帮助:>