簡體   English   中英

AVAssetExportSession導出需要很多時間

[英]AVAssetExportSession export takes a lot of time

我的目標是讓用戶從照片中選擇視頻,然后讓他在其上添加標簽。

這是我所擁有的:

let audioAsset = AVURLAsset(url: selectedVideoURL)
let videoAsset = AVURLAsset(url: selectedVideoURL)
let mixComposition = AVMutableComposition()
let compositionVideoTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
let compositionAudioTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
let clipVideoTrack = videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0]
let clipAudioTrack = audioAsset.tracks(withMediaType: AVMediaTypeAudio)[0]
do {
    try compositionVideoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), of: clipVideoTrack, at: kCMTimeZero)
    try compositionAudioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, audioAsset.duration), of: clipAudioTrack, at: kCMTimeZero)
    compositionVideoTrack.preferredTransform = clipVideoTrack.preferredTransform
} catch {
    print(error)
}
var videoSize = clipVideoTrack.naturalSize
if isVideoPortrait(asset: videoAsset) {
    videoSize = CGSize(width: videoSize.height, height: videoSize.width)
}
let parentLayer = CALayer()
let videoLayer = CALayer()
parentLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height)
videoLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height)
parentLayer.addSublayer(videoLayer)

// adding label
let helloLabelLayer = CATextLayer()
helloLabelLayer.string = "Hello"
helloLabelLayer.font = "Signika-Semibold" as CFTypeRef?
helloLabelLayer.fontSize = 30.0
helloLabelLayer.contentsScale = mainScreen.scale
helloLabelLayer.alignmentMode = kCAAlignmentNatural
helloLabelLayer.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 50.0)
parentLayer.addSublayer(helloLabelLayer)

// creating composition
let videoComp = AVMutableVideoComposition()
videoComp.renderSize = videoSize
videoComp.frameDuration = CMTimeMake(1, 30)
videoComp.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)

let instruction = AVMutableVideoCompositionInstruction()
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, mixComposition.duration)
let layerInstruction = videoCompositionInstructionForTrack(track: compositionVideoTrack, asset: videoAsset)
instruction.layerInstructions = [layerInstruction]
videoComp.instructions = [instruction]
if let assetExport = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPreset640x480) {
    let filename = NSTemporaryDirectory().appending("video.mov")

    if FileManager.default.fileExists(atPath: filename) {
    do {
        try FileManager.default.removeItem(atPath: filename)
    } catch {
        print(error)
    }
}

let url = URL(fileURLWithPath: filename)
assetExport.outputURL = url
assetExport.outputFileType = AVFileTypeMPEG4
assetExport.videoComposition = videoComp
print(NSDate().timeIntervalSince1970)
assetExport.exportAsynchronously {
    print(NSDate().timeIntervalSince1970)
    let library = ALAssetsLibrary()
    library.writeVideoAtPath(toSavedPhotosAlbum: url, completionBlock: {
        (url, error) in
        switch assetExport.status {
            case AVAssetExportSessionStatus.failed:
                p("failed \(assetExport.error)")
            case AVAssetExportSessionStatus.cancelled:
                p("cancelled \(assetExport.error)")
            default:
                p("complete")
                p(NSDate().timeIntervalSince1970)
                if FileManager.default.fileExists(atPath: filename) {
                    do {
                        try FileManager.default.removeItem(atPath: filename)
                    } catch {
                        p(error)
                    }
                }
                print("Exported")                                    
        }
    })
}

isVideoPortrait函數的實現:

func isVideoPortrait(asset: AVAsset) -> Bool {
    var isPortrait = false
    let tracks = asset.tracks(withMediaType: AVMediaTypeVideo)
    if tracks.count > 0 {
        let videoTrack = tracks[0]
        let t = videoTrack.preferredTransform
        if t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0 {
            isPortrait = true
        }
        if t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0 {
            isPortrait = true
        }
        if t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0 {
            isPortrait = false
        }
        if t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0 {
            isPortrait = false
        }
    }
    return isPortrait
}

video composition layer instruction的最后一個功能是:

func videoCompositionInstructionForTrack(track: AVCompositionTrack, asset: AVAsset) -> AVMutableVideoCompositionLayerInstruction {
    let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
    let assetTrack = asset.tracks(withMediaType: AVMediaTypeVideo)[0]
    let transform = assetTrack.preferredTransform
    instruction.setTransform(transform, at: kCMTimeZero)
    return instruction
}

代碼運行良好,輸出視頻帶有標簽,但是如果我選擇1分鍾的視頻,則導出需要28秒。

我已經搜索了它,並試圖刪除layerInsctuction轉換,但是沒有效果。

試圖添加: assetExport.shouldOptimizeForNetworkUse = false也無效。

另外,嘗試為AVAssetExportSession設置AVAssetExportPresetPassthrough ,在這種情況下,視頻導出時間為1秒,但標簽消失了。

任何幫助將不勝感激,因為我陷入困境。 謝謝你的時間。

這與您的問題沒有直接關系,但是您的代碼在這里是向后的:

assetExport.exportAsynchronously {
    let library = ALAssetsLibrary()
    library.writeVideoAtPath(toSavedPhotosAlbum: url, completionBlock: {
        switch assetExport.status {

不不不。 首先,您完成資產導出。 然后,如果您要這樣做,則可以再次復制到其他地方。 所以這需要像這樣:

assetExport.exportAsynchronously {
    switch assetExport.status {
    case .completed:
        let library = ALAssetsLibrary()
        library.writeVideoAtPath...

其他的建議:

  • ALAssetsLibrary已死。 這不是復制到用戶照片庫中的方法。 使用照片框架。

  • 您的原始代碼很奇怪,因為您還沒有測試很多其他情況。 您只是假設 default表示.completed 太危險了

我能想到的唯一方法是通過比特率和分辨率降低質量。

這是通過應用到AssetExporter的videoSettings的字典來完成的,為此,我不得不使用一個名為SDAVAssetExportSession的框架

然后,通過更改videoSettings,我可以播放質量以獲得最佳質量/速度。

    let compression = [AVVideoAverageBitRateKey : 2097152(DESIRED_BITRATE),AVVideoProfileLevelKey : AVVideoProfileLevelH264BaselineAutoLevel]

    let videoSettings = [AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : maxWidth, AVVideoHeightKey : maxHeight, AVVideoCompressionPropertiesKey:compression]

這是我加快速度的唯一方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM