首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >压缩AVAsset (主要是AVMutableComposition)

压缩AVAsset (主要是AVMutableComposition)
EN

Stack Overflow用户
提问于 2017-02-23 10:32:50
回答 1查看 1.3K关注 0票数 1

我有一段带有这些规格的视频

  • 格式: H.264,1280x544
  • FPS : 25
  • 数据大小:26
  • 持续时间: 3:00
  • 数据速率: 1.17 Mbit/s

在实验中,我在每一个其他帧上执行了一个removeTimeRange(range : CMTimeRange) (总帧= 4225)。这将导致视频速度提高2倍,因此持续时间为1:30

然而,当我导出视频时,视频变得大12倍,即325 it .This是有意义的,因为这种技术是将视频分解成大约2112片段并将其重新拼接在一起。显然,这样做的话,单个帧之间的压缩就会丢失,从而导致巨大的尺寸。

当播放AVPlayer时,这会导致视频中的口吃,因此性能很差。

问题:我如何在拼接帧的同时应用某种压缩,这样视频就可以播放得很流畅,而且体积也更小?

我只想找个正确的方向。谢谢!

1)从资产创建AVMutableComposition &配置它

代码语言:javascript
复制
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)删除所有其他帧。

代码语言:javascript
复制
   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)保存文件

代码语言:javascript
复制
  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播放新的作文!

代码语言:javascript
复制
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()

  }
EN

回答 1

Stack Overflow用户

发布于 2017-03-13 08:07:22

如果您正在使用AVMutableComposition,您将注意到每个组合可能包含一个或多个AVCompositionTrack(or AVMutableCompositionTrack),编辑作文的最佳方法是操作每个轨道,而不是整个组合。

但是,如果您的目的是加快您的视频的速度,编辑轨道将是不必要的。

所以我会尽我所能告诉你我对你问题的了解

关于播放视频口吃

口吃的可能原因

请注意,您使用的是removeTimeRange(range: CMTimeRange)方法,此方法将删除组合是的timeRange,但不会自动填充每个时间范围的空值。

代码语言:javascript
复制
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)

代码语言:javascript
复制
Example
AVMutableComposition * project;//if this video is 200s

//Scale
project.scaleTimeRange:CMTimeRangeMake(kCMTimeZero, project.duration) toDuration:CMTimeMakeWithSeconds(100,kCMTimeMaxTimescale)

这种方法是使视频更快/更慢。

关于文件大小

视频文件的大小可能会受到比特率和格式类型的影响,如果使用H.264,导致大小放大的最可能的原因将是比特率。

在您的代码中,您正在使用AVAssetExportSession

代码语言:javascript
复制
AVAssetExportSession(asset: asset, presetName:     AVAssetExportPresetHighestQuality

你在我自己的应用项目中给出了AVAssetExportPresetHighestQuality预置,在我使用这个预置后,视频的比特率将是20~30 30Mbps,不管你的源视频的比特率如何。而且,使用苹果的预置将不允许你手动设定比特率,所以。

可能解决办法

还有一个名为SDAVAssetExportSession的第三部分工具,这个会话将允许您完全配置导出会话,您可能希望尝试学习有关自定义导出会话预置的代码。

我现在可以告诉你的是。希望能帮助:>

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42413171

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档