【问题标题】:Compressing an AVAsset (mainly AVMutableComposition)压缩一个 AVAsset(主要是 AVMutableComposition)
【发布时间】:2017-02-23 10:32:50
【问题描述】:

我有一个包含这些规格的视频

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

在实验过程中,我在每个其他帧上执行了removeTimeRange(range : CMTimeRange)总帧数 = 4225)。这会导致视频变快 2 倍,因此时长变为 1:30

但是,当我导出视频时,视频的大小会变大 12 倍,即 325MB。这是有道理的,因为这种技术将视频分解为大约 2112 块并拼接它重新组合在一起。显然,这样做会丢失单个帧之间的压缩,从而导致巨大的尺寸。

这会导致使用AVPlayer 播放视频时卡顿,因此性能不佳。

问题:如何在拼接帧时应用某种压缩,以便视频可以流畅播放并且尺寸更小?

我只想要一个正确方向的点。谢谢!

代码

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()

  }

【问题讨论】:

  • 你能分享你创建编辑视频的代码吗?你在用AVMutableComposition吗?
  • 我正在使用 AVMutableComposition 。我已经用一些代码更新了这个问题。非常感谢!

标签: ios video compression avfoundation avasset


【解决方案1】:

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

但如果您的目的是加快视频播放速度,则无需编辑音轨。

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

关于视频播放时卡顿

口吃的可能原因

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

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,导致尺寸放大的最可能原因将是bit率

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

AVAssetExportSession(asset: asset, presetName:     AVAssetExportPresetHighestQuality

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

可能的解决方案

有一个名为SDAVAssetExportSession的第三方工具,此会话将允许您完全配置您的导出会话,您可能想尝试研究有关自定义导出会话预设的代码。

这就是我现在可以告诉你的。希望能帮上忙:>

【讨论】:

  • 感谢您抽出宝贵时间回答我的问题。我故意使用removeTimeRange(..),因为我想减少视频中的整体帧数。正如您所注意到的,在for loop 中计算frameTime 也可以让我以每帧 为基础操作视频。我注意到scaleTimeRange(..) 实际上并没有修改视频iteslf,而只是修改了元数据。当 timeRange 缩短时,可以在视频的 比特率 中看到这一点。可悲的是,视频只能缩短到 1/9 ~ 240fps,因为这对硬件来说太多了。
  • 还有一点,即使使用AVCompositionTrack 而不是AVMutableComposition,问题仍然存在。也许我遗漏了一些东西,因为在for 循环中,任何类型的timeRange 修改都会导致视频中出现微小的卡顿/空白帧或其他不一致。
  • Ehh.. 您是否尝试过在删除时间范围内使用 kCMTimeMaxTimeScale?口吃是由不同的时间尺度引起的吗?我的应用程序是一种视频编辑器,我将所有时间刻度设置为 kCMTimeMaxTimeScale,当我播放和导出我的作品时,没有发现卡顿。你觉得这有意义吗?
  • 是的,你会尝试在这一行使用 CMTimeMaxScale 吗? let frameTime = CMTime(seconds: frameDuration, preferredTimescale: CMTimeMaxTimeScale 在你的 for loop
  • 不幸的是,CMTimeMaxTimeScale 无济于事。但我注意到,当我 导出 AVAsset 并在我的 Mac 上使用 QuickTime 播放它时,它运行顺畅。同一导出的视频无法在模拟器的照片应用中流畅运行。我不明白出了什么问题。
猜你喜欢
  • 2019-10-18
  • 2019-07-21
  • 1970-01-01
  • 2014-12-25
  • 2016-09-16
  • 1970-01-01
  • 1970-01-01
  • 2019-04-12
  • 1970-01-01
相关资源
最近更新 更多