【问题标题】:UIImagePickerController allowsEditing = YES, getting untrimmed video after trimmingUIImagePickerController allowedEditing = YES,修剪后得到未修剪的视频
【发布时间】:2012-09-03 14:35:15
【问题描述】:

问题:

当我在我的 UIImagePickerController 中录制视频时,将 allowEditing 设置为 YES,然后使用视频捕获后的修剪界面修剪视频,我会返回原始视频,而不是修剪后的视频。

设置:

我使用UIImagePickerController 进行视频捕获,allowsEditing 属性设置为 YES。在委托方法didFinishPickingMediaWithInfo 中,我使用UIImagePickerControllerMediaURL 来自信息NSDictionary 来获取路径URL。 The official Apple docs 遗憾的是,不要提及任何已编辑的视频 URL。

代码:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];

    if (CFStringCompare ((__bridge CFStringRef) mediaType, kUTTypeMovie, 0)
        == kCFCompareEqualTo) {

        self.tempVideoPath = [[info objectForKey:
                                UIImagePickerControllerMediaURL] path];
    }
}

我意识到这个问题类似于otherones 在 SO 上发布的问题,但没有明确的答案为什么它不起作用或为什么选项甚至在那里。如果是这样,我不明白为什么选择器有一个“allowsEditing”属性。

编辑:在我返回的信息字典中,有以下键:

info: {
    UIImagePickerControllerMediaType = "public.movie";
    UIImagePickerControllerMediaURL = "file://localhost/private/var/mobile/Applications/F12E4608-FE5A-4EE3-B4E2-8F7D2508C4C8/tmp/capture-T0x21d810.tmp.wabFCC/capturedvideo.MOV";
    "_UIImagePickerControllerVideoEditingEnd" = "5.498333333333333";
    "_UIImagePickerControllerVideoEditingStart" = "4.273402690887451";
}

这是否意味着我们必须用这些数据自己修剪它?然后Apple文档对此不是很清楚。如果是这样,你知道一个好的做法吗?

【问题讨论】:

    标签: iphone ios ipad video uiimagepickercontroller


    【解决方案1】:

    看看这篇文章中突出显示的答案:

    How to trim the video using AVFoundation

    我认为这正是您想要的。答案也使用 UIImagePickerController

    希望对你有帮助, 马里奥

    【讨论】:

      【解决方案2】:

      这是一个快速而肮脏的 Swift 5 示例,说明如何从 UIImagePickerController 修剪视频

      extension ViewController: UIImagePickerControllerDelegate {
          func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
              let mediaType = info[.mediaType] as! String
      
              dismiss(animated: true) { [weak self] in
                  // Handle a movie capture
                  if mediaType == kUTTypeMovie as String {
                      guard let videoURL = info[.mediaURL] as? URL else {
                          SwiftyBeaver.error("Could not get URL for movie")
                          return
                      }
      
                      let editingEnd = UIImagePickerController.InfoKey(rawValue: "_UIImagePickerControllerVideoEditingEnd")
                      let editingStart = UIImagePickerController.InfoKey(rawValue: "_UIImagePickerControllerVideoEditingStart")
      
                      let startMilliseconds: Double?
                      let endMilliseconds: Double?
      
                      if let start = info[editingStart] as? Double, let end = info[editingEnd] as? Double {
                          startMilliseconds = start
                          endMilliseconds = end
                      } else {
                          startMilliseconds = nil
                          endMilliseconds = nil
                      }
      
                      let alert = UIAlertController(title: "Creating", message: "File is being processed", preferredStyle: .alert)
                      self?.present(alert, animated: true)
                      self?.process(srcVideoURL: videoURL, startSeconds: startMilliseconds, endSeconds: endMilliseconds) { (error) in
                          DispatchQueue.main.async {
                              if let error = error {
                                  alert.title = "Whoops"
                                  alert.message = "\(error)"
                                  alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
                                      self?.dismiss(animated: true, completion: nil)
                                  }))
                                  return
                              }
                              self?.dismiss(animated: true, completion: nil)
                          }
                      }
                  }
              }
          }
      }
      
      enum VideoError: Error {
          case error(message: String)
      }
      
      extension ViewController {
          func process(srcVideoURL: URL, startSeconds: Double?, endSeconds: Double?, completed: @escaping (_ error: Error?) -> ()) {
              DispatchQueue.global(qos: .userInitiated).async {
                  let dstVideoURL: URL // some URL for the destination
                  do {
                      try self.handleNewVideo(srcVideoURL: srcVideoURL, dstVideoURL: dstVideoURL, startSeconds: startSeconds, endSeconds: endSeconds)
                      completed(nil)
                  } catch {
                      completed(error)
                  }
              }
          }
      
          func handleNewVideo(srcVideoURL: URL, dstVideoURL: URL, startSeconds: Double?, endSeconds: Double?) throws {
              guard let start = startSeconds, let end = endSeconds else {
                  print("No video editing information. Copying file.")
                  try FileManager.default.moveItem(at: srcVideoURL, to: dstVideoURL)
                  return
              }
      
              print("Video editing information. Processing start \(start) end \(end).")
              let videoAsset = AVURLAsset(url: srcVideoURL)
              let exportSession = AVAssetExportSession(asset: videoAsset, presetName: AVAssetExportPresetHighestQuality)!
              exportSession.outputURL = dstVideoURL
              exportSession.outputFileType = AVFileType.mov
              let timeRange = CMTimeRange(start: CMTime(seconds: start, preferredTimescale: 1000), duration: CMTime(seconds: end - start, preferredTimescale: 1000))
              exportSession.timeRange = timeRange
      
              var error: Error? = nil
              let dispatchGroup = DispatchGroup()
              dispatchGroup.enter()
              exportSession.exportAsynchronously(completionHandler: {
                  switch exportSession.status {
                  case .completed:
                      break
                  case .failed:
                      error = exportSession.error ?? VideoError.error(message: "Unknown failed error")
                  case .cancelled:
                      error = exportSession.error ?? VideoError.error(message: "Video Cancelled")
                  case .exporting:
                      error = exportSession.error ?? VideoError.error(message: "Video still exporting")
                  case .unknown:
                      error = exportSession.error ?? VideoError.error(message: "Unknown unknown error")
                  case .waiting:
                      error = exportSession.error ?? VideoError.error(message: "Waiting error")
                  @unknown default:
                      error = exportSession.error ?? VideoError.error(message: "Future error")
                  }
                  dispatchGroup.leave()
              })
              dispatchGroup.wait()
      
              if let error = error {
                  throw error
              }
          }
      }
      

      【讨论】:

      • 任何方式 startMilliseconds 和 endMilliseconds 总是给出 nil 值。
      【解决方案3】:

      您需要为此使用UIVideoEditorController。它是Delegate Protocol 指定了一个方法videoEditorController:didSaveEditedVideoToPath:,这似乎是您想要的。 here 提供了示例代码,在 this SO question 中引用。

      【讨论】:

      • 那么这将如何与UIImagePickerController 结合使用?如果您应该使用其他类,为什么首先会出现 allowsEditing 的选项?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      • 1970-01-01
      相关资源
      最近更新 更多