AVFoundation - 비디오의 인코딩(압축) 및 업로드(1) - Export Session 이용

2023. 3. 18. 12:38iOS/이슈

비디오의 압축

비디오 업로드 시, AWS 서버 비용 때문에 용량을 줄여달라는 요구 사항이 있었다. 그래서 ExportSession를 거쳐 Asset Reader/Writer를 적용한 경험을 포스팅해보려고 한다.

애플 도큐먼트에는 가능하면 버전이 업데이트 될 수록 최신 기술들(HDR 등)이 적용될 테니 프리셋을 사용하라고 나와있었다. custom하면 대응해줘야하기 때문이다. 하지만 프리셋 만으로 원하는 크기만큼 인코딩(압축)되지 않았고, Asset reader/writer를 사용하기로 했다.

간단한 이론

[참조3] 비디오의 용량을 결정 짓는 것이 Bitrate이다.

비디오는 무엇인가? FFmpeg는 무엇인가?에 대한 설명들이 참조 링크에 잘 설명되어 있다.

아래 [참조 2]를 보고 [참조 1]을 보는 것을 추천한다.

자세한 내용은 따로 글 써봐야지

ExportSession

// compress completion
......

do {
      let composition = try createMutableComposition(asset, range: range)
      let session = try createExportSession(composition, preferedPreset: preferredPreset, range: range, outputURL: outputURL)
 
 // session의 프로그래스값을 프로그래스바로 전달하기 위해 sleep()을 줌
 //  https://stackoverflow.com/questions/45198189/swift-3-how-to-export-video-with-text-using-avvideocomposition
      DispatchQueue.main.async {
        let progress = session.progress
        progressBlock(progress)
        sleep(1)
      }
      
      session.exportAsynchronously {
        switch session.status {
        case .failed:
          Log.error("Failed: \(session.error?.localizedDescription ?? "unknown")")
          completion(.failure(.InProgressError))
        case .completed:
          completion(.success(outputURL))
        default: break
        }
      }
    } catch {
      guard let error = error as? VideoError else { return completion(.failure(.unknown)) }
      completion(.failure(error))
    }
 // [참조3]포스팅의 깃헙 소스 참조함
 // https://github.com/testfairy-blog/VideoCompressionTutorial/blob/master/VideoCompressionTutorial/VideoCompression.swift
 private func createMutableComposition(_ asset: AVAsset, range: CMTimeRange) throws -> AVMutableComposition {
    // 트랙 체크 및 트랙 추출
    guard asset.isExportable,
          let sourceVideoTrack = asset.tracks(withMediaType: .video).first,
          let sourceAudioTrack = asset.tracks(withMediaType: .audio).first
    else {
      Log.error("Track is not exportable")
      throw VideoError.trackError
    }
    // mutable한 트랙 생성 및 트랙 생성
    let composition = AVMutableComposition()
    let compositionVideoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
    let compositionAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid)
    )
    
    // 트랙에 추출한 트랙 삽입 및 범위 지정
    do {
      try compositionVideoTrack?.insertTimeRange(range, of: sourceVideoTrack, at: .zero)
      try compositionAudioTrack?.insertTimeRange(range, of: sourceAudioTrack, at: .zero)
      compositionVideoTrack?.preferredTransform = sourceVideoTrack.preferredTransform
    } catch {
      Log.error("Track insert error")
      throw VideoError.trackError
    }
    
    return composition
  }
private func createExportSession(_ composition: AVMutableComposition, preferedPreset: String, range: CMTimeRange, outputURL: URL) throws -> AVAssetExportSession {
    // 적용 가능 프리셋
    let compatiblePresets = AVAssetExportSession.exportPresets(compatibleWith: composition)
    // 프리셋 무시
    var preset = AVAssetExportPresetPassthrough
    
    // 프리셋이 적용 가능하면 변수에 대입
    if compatiblePresets.contains(preferedPreset) {
      preset = preferedPreset
    }
    let fileType: AVFileType = .mp4
    
    // 세션 생성
    guard
      let exportSession = AVAssetExportSession(asset: composition, presetName: preset),
      exportSession.supportedFileTypes.contains(fileType)
    else {
      throw VideoError.exportSessionError
    }
    
    // Set Session
    exportSession.timeRange = range
    exportSession.outputURL = outputURL
    exportSession.outputFileType = fileType
    exportSession.shouldOptimizeForNetworkUse = true
    
    return exportSession
  }

 

 

 

[참조1] https://img.ly/blog/ultimate-guide-to-ffmpeg/

 

FFmpeg - Ultimate Guide | IMG.LY Blog

This guide covers the ins and outs of FFmpeg starting with fundamental concepts and moving to media transcoding and video and audio processing providing practical examples along the way.

img.ly

[참조2] https://present.do/documents/636474014e11750badbcb4cc?page=0 

 

FFmpeg

Brief introduction of FFmpeg and its tool(ffmpeg) and how I managed to changed the video exporting logic

present.do

[참조3] https://testfairy.com/blog/fine-tuned-video-compression-in-ios-swift-4-no-dependencies/

 

Fine Tuned Video Compression in iOS (Swift 4, no dependencies)

Working compression code, configurable a/v bitrate, video resolution, audio sample rate and many other fine tuning operations

testfairy.com

[참조4] https://github.com/testfairy-blog/VideoCompressionTutorial/blob/master/VideoCompressionTutorial/VideoCompression.swift

 

GitHub - testfairy-blog/VideoCompressionTutorial: iOS - Fine tuned video compression in Swift 4

iOS - Fine tuned video compression in Swift 4. Contribute to testfairy-blog/VideoCompressionTutorial development by creating an account on GitHub.

github.com