如何在SwiftUI中使用UIVideoEditorController?

问题描述 投票:0回答:1

我正在尝试在 SwiftUI 中使用 UIVideoEditorController,但遇到一个问题,点击“保存”后,它不会触发使用编辑的视频路径调用委托方法,并且还会消除UIVideoEditorController 直到返回到根视图控制器。我该如何解决这个问题?

这是我的 UIViewControllerRepresentable 版本的 UIVideoEditorController:

struct VideoEditor: UIViewControllerRepresentable {
  let source: URL
  let maxSeconds: TimeInterval
  let onSaved: (URL) -> Void

  @Environment(\.dismiss) private var dismiss

  func makeUIViewController(context: Context) -> UIVideoEditorController {
    let editor = UIVideoEditorController()
    editor.videoPath = source.absoluteString
    editor.videoMaximumDuration = maxSeconds
    editor.videoQuality = .typeHigh
    editor.delegate = context.coordinator
    return editor
  }

  func updateUIViewController(_ uiViewController: UIVideoEditorController, context: Context) {}

  func makeCoordinator() -> Coordinator { Coordinator(videoEditor: self) }

  class Coordinator: NSObject, UINavigationControllerDelegate, UIVideoEditorControllerDelegate {
    private let videoEditor: VideoEditor

    init(videoEditor: VideoEditor) {
      self.videoEditor = videoEditor
    }

    func videoEditorController(
      _ editor: UIVideoEditorController,
      didSaveEditedVideoToPath editedVideoPath: String
    ) {
      let url = URL(fileURLWithPath: editedVideoPath)
      videoEditor.onSaved(url)
      videoEditor.dismiss()
    }
  }
}

我的使用方法如下:

struct ContentView: View {
  let videoToEdit: URL

  @State private var presentingFirstCover = false
  @State private var presentingEditor = false

  var body: some View {
    VStack {
      Button("Present first cover") { presentingFirstCover = true }
    }
    .fullScreenCover(isPresented: $presentingFirstCover) {

      Button("Present editor") { presentingEditor = true }
        .fullScreenCover(isPresented: $presentingEditor) {

          VideoEditor(source: fullVideo, maxSeconds: 20) {
            print("saved edited video to: \($0)")
        }
    }
  }
}
swiftui uikit uiviewcontrollerrepresentable uivideoeditorcontroller
1个回答
0
投票

我想通了!事实证明问题是:

  1. 我没有正确传递视频路径(我需要使用
    source.path
    ,而不是
    source.absoluteString
    ),这导致了一个问题:它不会保存修剪后的视频,而是会取消。
  2. 它被解雇回到根的原因是因为我没有实现
    videoEditorControllerDidCancel
    UIVideoEditorControllerDelegate
    方法,我需要自己解雇视图控制器。如果没有定义这个方法,UIVideoEditorController 就没有办法解散自己,只能解散回根目录,所以这就是它所做的。

这是我最终的工作解决方案:

import SwiftUI

struct VideoEditor: UIViewControllerRepresentable {
  let source: URL
  let maxSeconds: TimeInterval
  let onSaved: (URL) -> Void

  @Environment(\.dismiss) private var dismiss

  func makeUIViewController(context: Context) -> UIVideoEditorController {
    let editor = UIVideoEditorController()
    editor.videoPath = source.path
    editor.videoMaximumDuration = maxSeconds
    editor.videoQuality = .typeHigh
    editor.delegate = context.coordinator
    return editor
  }

  func updateUIViewController(_ uiViewController: UIVideoEditorController, context: Context) {}

  func makeCoordinator() -> Coordinator { Coordinator(videoEditor: self) }

  class Coordinator: NSObject, UINavigationControllerDelegate, UIVideoEditorControllerDelegate {
    private let videoEditor: VideoEditor
    private var savedEditedVideo = false

    init(videoEditor: VideoEditor) {
      self.videoEditor = videoEditor
    }

    func videoEditorController(
      _ editor: UIVideoEditorController,
      didSaveEditedVideoToPath editedVideoPath: String
    ) {
      defer { videoEditor.dismiss() }

      // For some reason, this delegate method is always called twice.
      // So, we must make sure we only call onSaved the first time this delegate method is called.
      if savedEditedVideo { return }

      let urlSavedTo = URL(fileURLWithPath: editedVideoPath)
      videoEditor.onSaved(urlSavedTo)
      savedEditedVideo = true
    }

    func videoEditorControllerDidCancel(_ editor: UIVideoEditorController) {
      videoEditor.dismiss()
    }

    func videoEditorController(
      _ editor: UIVideoEditorController, didFailWithError error: any Error
    ) {
      print("Failed to edit video \(videoEditor.source), with error \(error)")
      videoEditor.dismiss()
    }
  }
}

尽管付出了所有这些努力,但遗憾的是我无法使用我的解决方案,因为导出的视频质量不够高,即使设置为

.typeHigh
(也只有 480p)。

相反,我必须使用

UIImagePickerController
直接从相机胶卷中选择视频并修剪它,因为使用该视图控制器,您可以将
videoExportPreset
设置为
AVAssetExportPresetPassthrough
以使其保持高清质量,如果所选视频是高清的。

© www.soinside.com 2019 - 2024. All rights reserved.