fix(camera): modernize mp4 export

This commit is contained in:
Peter Steinberger
2025-12-14 02:34:22 +00:00
parent 259e9cfccf
commit f86b1cf6a1
2 changed files with 50 additions and 30 deletions

View File

@@ -199,25 +199,35 @@ actor CameraController {
} }
private nonisolated static func exportToMP4(inputURL: URL, outputURL: URL) async throws { private nonisolated static func exportToMP4(inputURL: URL, outputURL: URL) async throws {
let asset = AVAsset(url: inputURL) let asset = AVURLAsset(url: inputURL)
guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else { guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else {
throw CameraError.exportFailed("Failed to create export session") throw CameraError.exportFailed("Failed to create export session")
} }
exporter.outputURL = outputURL
exporter.outputFileType = .mp4
exporter.shouldOptimizeForNetworkUse = true exporter.shouldOptimizeForNetworkUse = true
try await withCheckedThrowingContinuation(isolation: nil) { cont in if #available(iOS 18.0, tvOS 18.0, visionOS 2.0, *) {
exporter.exportAsynchronously { do {
switch exporter.status { try await exporter.export(to: outputURL, as: .mp4)
case .completed: return
cont.resume(returning: ()) } catch {
case .failed: throw CameraError.exportFailed(error.localizedDescription)
cont.resume(throwing: exporter.error ?? CameraError.exportFailed("Export failed")) }
case .cancelled: } else {
cont.resume(throwing: CameraError.exportFailed("Export cancelled")) exporter.outputURL = outputURL
default: exporter.outputFileType = .mp4
cont.resume(throwing: CameraError.exportFailed("Export did not complete"))
try await withCheckedThrowingContinuation(isolation: nil) { cont in
exporter.exportAsynchronously {
switch exporter.status {
case .completed:
cont.resume(returning: ())
case .failed:
cont.resume(throwing: exporter.error ?? CameraError.exportFailed("Export failed"))
case .cancelled:
cont.resume(throwing: CameraError.exportFailed("Export cancelled"))
default:
cont.resume(throwing: CameraError.exportFailed("Export did not complete"))
}
} }
} }
} }

View File

@@ -200,29 +200,39 @@ actor CameraCaptureService {
} }
private nonisolated static func exportToMP4(inputURL: URL, outputURL: URL) async throws { private nonisolated static func exportToMP4(inputURL: URL, outputURL: URL) async throws {
let asset = AVAsset(url: inputURL) let asset = AVURLAsset(url: inputURL)
guard let export = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality) else { guard let export = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality) else {
throw CameraError.exportFailed("Failed to create export session") throw CameraError.exportFailed("Failed to create export session")
} }
export.outputURL = outputURL
export.outputFileType = .mp4
export.shouldOptimizeForNetworkUse = true export.shouldOptimizeForNetworkUse = true
await withCheckedContinuation { cont in if #available(macOS 15.0, *) {
export.exportAsynchronously { do {
cont.resume() try await export.export(to: outputURL, as: .mp4)
return
} catch {
throw CameraError.exportFailed(error.localizedDescription)
} }
} } else {
export.outputURL = outputURL
export.outputFileType = .mp4
switch export.status { await withCheckedContinuation { cont in
case .completed: export.exportAsynchronously {
return cont.resume()
case .failed: }
throw CameraError.exportFailed(export.error?.localizedDescription ?? "export failed") }
case .cancelled:
throw CameraError.exportFailed("export cancelled") switch export.status {
default: case .completed:
throw CameraError.exportFailed("export did not complete (\(export.status.rawValue))") return
case .failed:
throw CameraError.exportFailed(export.error?.localizedDescription ?? "export failed")
case .cancelled:
throw CameraError.exportFailed("export cancelled")
default:
throw CameraError.exportFailed("export did not complete (\(export.status.rawValue))")
}
} }
} }
} }