Created
June 21, 2024 15:15
-
-
Save samsonjs/2f006c5f62f53c9aef820bc050e37809 to your computer and use it in GitHub Desktop.
AVAssetExportSession safety when using structured concurrency in Swift 5 and 6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AVFoundation | |
/** | |
* AVAssetExportSession is initialized with an AVComposition, and that composition and all of its constituent | |
* components are not sendable. Because `composition` is isolated to the main actor here, the call to the | |
* non-isolated method `export(to:as:)` sends it across an isolation region and that is unsafe. | |
*/ | |
@MainActor | |
class UnsafeMovieExporter { | |
let composition = AVMutableComposition() | |
func export() async throws { | |
// the compiler is noticing here that `exportSession` depends on `composition` | |
// but composition is isolated to MainActor... | |
let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough) | |
let url = URL(filePath: "/tmp/whatever.mp4") | |
// ... and this makes the non-isolated async call here unsafe | |
try await exportSession?.export(to: url, as: .mp4) | |
} | |
} | |
/** | |
* AVAssetExportSession is initialized with an AVComposition, and that composition and all of its constituent | |
* components are not sendable. Because `composition` is *not* isolated to the main actor here, the call to the | |
* non-isolated method `export(to:as:)` doesn't send it across an isolation region. | |
*/ | |
class SafeMovieExporter { | |
let composition = AVMutableComposition() | |
func export() async throws { | |
// the compiler is noticing here that `exportSession` depends on `composition` | |
// and composition is no longer isolated to any actor... | |
let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough) | |
let url = URL(filePath: "/tmp/whatever.mp4") | |
// ... and this makes the non-isolated async call here kosher | |
try await exportSession?.export(to: url, as: .mp4) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@DePasqualeOrg Haven’t tried it but if the caller holds onto the export session and then the exportAsynchronously callback calls into the caller’s context to finish up and read out the status that might work. Observing progress and reading the status is a pain. I’d probably just deal with warnings since it is safe to use the export session in the callback.