使用AVAssetExportSession压缩iOS Swift导出的视频文件大小

3
我目前正在以下方式导出视频:

   let exporter = AVAssetExportSession.init(asset: mixComposition, presetName: AVAssetExportPreset1280x720)
   exporter?.outputURL = outputPath
   exporter?.outputFileType = AVFileType.mp4
   exporter?.shouldOptimizeForNetworkUse = true
   exporter?.videoComposition = mainCompositionInst

一个15秒的视频消耗约20MB的数据。与Snapchat的2MB视频相比,这个数字似乎完全不可接受。
我已经降低了导出和捕获会话的质量(1280x720)。
该视频是使用自定义相机拍摄的。未使用UIImagePickerController。
AVAssetExportSession使用默认设置。
有没有办法减小我的视频尺寸呢? 非常感谢!
编辑1: 我尝试使用了这个库:https://cocoapods.org/pods/NextLevelSessionExporter 不幸的是,这会导致大小问题并移除我的音频:
// Creating exporter
    let exporter = NextLevelSessionExporter(withAsset: mixComposition)
    exporter.outputURL = outputPath
    exporter.outputFileType = AVFileType.mp4
    exporter.videoComposition = mainCompositionInst

    let compressionDict: [String: Any] = [
        AVVideoAverageBitRateKey: NSNumber(integerLiteral: 2500000),
        AVVideoProfileLevelKey: AVVideoProfileLevelH264BaselineAutoLevel as String,
        ]

        exporter.videoOutputConfiguration = [
            AVVideoCodecKey: AVVideoCodecType.h264,
            AVVideoWidthKey: NSNumber(integerLiteral: 1280),
            AVVideoHeightKey: NSNumber(integerLiteral: 720),
            AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill,
            AVVideoCompressionPropertiesKey: compressionDict
        ]

        exporter.audioOutputConfiguration = [
            AVFormatIDKey: kAudioFormatMPEG4AAC,
            AVEncoderBitRateKey: NSNumber(integerLiteral: 128000),
            AVNumberOfChannelsKey: NSNumber(integerLiteral: 2),
            AVSampleRateKey: NSNumber(value: Float(44100))
        ]

enter image description here


不是重复内容,上下文有所不同。我在这里使用AVAssetExportSession。 - thelearner
1
@holex "AVAssetExportSession使用默认设置。" - 感谢您的有毒评论。 - thelearner
@dfi,这个评论一点也不恶意,朋友。默认设置给你20MB的大视频,你期望什么随机奇迹?改变规格,你可以得到不同大小的输出。小菜一碟...但是你可能需要定义你愿意接受多少视频质量的损失来获得更小的输出,否则你的帖子就毫无意义了,我很抱歉。 - holex
@dfi,根据您的需求,您仍需要定义可以接受的视频质量损失程度,以获得仍然不错的输出效果,之后就可以轻松找到创建这种输出所需的高效设置。在您无法定义“损失”之前,您也无法为自己或其他人找到高效的设置。希望您能理解这里的因果关系...例如:您是否可以接受视频每秒1帧?不行吗?那么您寻求的最低帧速率是多少?60?还是需要240用于慢动作?那么您就没有办法了。您能接受每秒12帧吗?那么可能会有一些解决方案等待您。如果您看到这里的流程,就明白了。 - holex
1
@dfi 这个问题与此问题相关:https://dev59.com/VFUL5IYBdhLWcg3wM1ry - thelearner
显示剩余4条评论
4个回答

8

为了减小文件大小,尝试使用下列参数设置HEVC编解码器(使用CocoaPod NextLevelSessionExporter):

let compressionDict: [String: Any] = [
AVVideoAverageBitRateKey: NSNumber(integerLiteral: 2500000), //lower it if you wish
AVVideoProfileLevelKey: AVVideoProfileLevelH264BaselineAutoLevel as String,
]
exporter.videoOutputConfiguration = [
    AVVideoCodecKey : AVVideoCodecType.hevc,
    AVVideoWidthKey : NSNumber(integerLiteral: 1280),
    AVVideoHeightKey: NSNumber(integerLiteral: 720),
    AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill,
    AVVideoCompressionPropertiesKey: compressionDict
]

为了使用HEVC视频编解码器,您需要升级到macOS High SierraiOS 11。但是,如果由于某种原因您无法使用HEVC,则请使用较低比特率的常规H.264

AVVideoCodecKey : AVVideoCodecType.h264:

此处有图片,请查看链接

另外,查看这篇关于iOS视频比特率的SO文章


2
首先,非常感谢你的帮助!你的答案将文件大小从20MB减小到了惊人的4MB。我爱你,伙计!你不知道我为了达到这个效果研究了多久。- 你是我的英雄。我无法使用HEVC,所以我按照你的建议使用了h264。非常感谢你! - thelearner
1
你好,Andy! 经过几天的奋斗,我终于成功解决了问题。iOS 11存在一个活动缺陷,会导致镜像视频的尺寸问题。我手动镜像了视频,现在它已经完美地运行了。感谢你的帮助! - thelearner
我不知道为什么。我在Xcode 9中尝试过,一切都正常运行。 - Andy Jazz
对于HEVC,应该从VideoToolbox框架将配置文件设置为kVTProfileLevel_HEVC_Main_AutoLevel。在AVVideoSettings.h中找到了这个注释:/* HEVC profiles/levels are defined in VideoToolbox/VTCompressionProperties.h, e.g. kVTProfileLevel_HEVC_Main_AutoLevel. The constants defined there can be used as the value for the key AVVideoProfileLevelKey. */ - Moshe Gottlieb
非常感谢@MosheGottlieb,我会解决的。 - Andy Jazz
显示剩余4条评论

7

终于解决了这个问题。

使用exportSession.fileLengthLimit = 1048576 * 10 //10 MB

10MB是硬编码数字。 根据所需的比特率进行设置。

fileLengthLimit /* 表示会话输出不应超过的文件长度。 根据源资产的内容,输出可能略微超出文件长度限制。 如果您需要在使用输出之前严格遵守限制,则应测试输出文件的长度。 另请参见maxDuration和timeRange。 */


2
Lalit Kumar的回答完美地解决了问题。在他的解决方案之上,我编写了一个AVAsset扩展,以便可以轻松设置比特率,而不是文件大小。在preferredBitrate方法中的方程式是我原创的。您也可以使用硬编码表。
extension AVAsset {
    private var preferredBitRate: Float {
        //          720p   1080p
        //  30fps:   5.0    11.3
        //  60fps:   7.5    16.9
        // 120fps:  11.3    25.3
        // 240fps:  16.9    38.0 (Mbps)
        guard let videoTrack = self.tracks(withMediaType: .video).first else {
            return .zero
        }
        let size = Float(min(videoTrack.naturalSize.width, videoTrack.naturalSize.height))
        let frameRate = videoTrack.nominalFrameRate
        return pow(1.5, log2(frameRate / 30)) * pow(size / 720, 2) * 5
    }

    private var preferredFileLength: Int64 {
        // 1 Mbit := 125000 bytes
        return Int64(self.duration.seconds * Double(self.preferredBitRate)) * 125000
    }
}

1

如果您设置了fileLengthLimit值,则导出会话生成的视频比特率值将发生变化。 这正是我想要的。 如果您想设置AVExportSession的视频比特率值,请计算并设置AVExportSessionfileLengthLimit值。

像这样:

exportSession.fileLengthLimit = Int64(Double(preferredBitrate / 8) * video duration)

谢谢Lalit Kumar。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接