2017-12-20 6 views
0

コード提案の解決策に基づいて修正されましたが、まだ動作しません。動画は0バイトとしてアップロードされています。私は自分の携帯電話からビデオを録画できるはずのアプリを持っています。「ビデオを使う」が選択されている場合、ビデオをPHPサーバにアップロードします。ファイルは正常にアップロードされており、表示されているサイズに基づいて空ではありません。しかし、私は、アプリでビデオを再生するために行くか、直接ブラウザを介して再生されません。再生コードに問題はありません。他のサイトの他の動画へのリンクをハードコードしていて、正常に動作します。コードは以下の通りですが、どんな助けでも大歓迎です。ビデオPHPのサーバにアップロードした後、録画されたiPhone Xのビデオは再生されません

func encodeVideo(dataPath: URL){ 
    let avAsset = AVURLAsset(url: dataPath) 
    let startDate = Date() 
    let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough) 

    let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] 
    let myDocPath = NSURL(fileURLWithPath: docDir).appendingPathComponent("temp.mp4")?.absoluteString 

    let docDir2 = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL 

    let filePath = docDir2.appendingPathComponent("rendered-Video.mp4") 
    //uploadVideo(filePath) 
    //self.encodeVideo(dataPath: dataPath) 
    deleteFile(filePath!) 


    if FileManager.default.fileExists(atPath: myDocPath!){ 
     do{ 
      try FileManager.default.removeItem(atPath: myDocPath!) 

     }catch let error{ 
      print(error) 
     } 
    } 
    //self.uploadVideo((myDocPath as AnyObject) as! URL) 

    exportSession?.outputURL = filePath 
    exportSession?.outputFileType = AVFileType.mp4 
    exportSession?.shouldOptimizeForNetworkUse = true 

    let start = CMTimeMakeWithSeconds(0.0, 0) 
    let range = CMTimeRange(start: start, duration: avAsset.duration) 
    exportSession?.timeRange = range 

    exportSession!.exportAsynchronously{() -> Void in 
     switch exportSession!.status{ 
     case .failed: 
      print("\(exportSession!.error!)") 
     case .cancelled: 
      print("Export cancelled") 
     case .completed: 
      let endDate = Date() 
      let time = endDate.timeIntervalSince(startDate) 
      print(time) 
      print("Successful") 
      print(exportSession?.outputURL ?? "") 
     default: 
      break 
     } 

    } 
} 
func deleteFile(_ filePath:URL) { 
    guard FileManager.default.fileExists(atPath: filePath.path) else { 
     return 
    } 

    do { 
     try FileManager.default.removeItem(atPath: filePath.path) 
    }catch{ 
     fatalError("Unable to delete file: \(error) : \(#function).") 
    } 
} 

//の

// Finished recording a video 
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 
    print("Got a video") 

    if let pickedVideo:URL = (info[UIImagePickerControllerMediaURL] as? URL) { 
     // Save video to the main photo album 
     let selectorToCall = #selector(CameraVideoViewController.videoWasSavedSuccessfully(_:didFinishSavingWithError:context:)) 
     UISaveVideoAtPathToSavedPhotosAlbum(pickedVideo.relativePath, self, selectorToCall, nil) 
     imageSelected = true 
     uuid = UUID().uuidString 

     if imageSelected == true { 
      saveFileName = "video-\(uuid).mp4" 
     } 
     // Save the video to the app directory so we can play it later 
     let videoData = try? Data(contentsOf: pickedVideo) 
     let paths = NSSearchPathForDirectoriesInDomains(
      FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) 
     let documentsDirectory: URL = URL(fileURLWithPath: paths[0]) 
     let dataPath = documentsDirectory.appendingPathComponent(saveFileName) 
     try! videoData?.write(to: dataPath, options: []) 
     print("Saved to " + dataPath.absoluteString) 

     imagePicker.dismiss(animated: true, completion: { 
      // Anything you want to happen when the user saves an video 
      self.encodeVideo(dataPath: dataPath) 
      self.uploadVideo(videoData!) 



     }) 
    } } 

// MP4変換はPARAMS

func createBodyWithParams(_ parameters: [String: String]?, filePathKey: String?, videoData: Data, boundary: String) -> Data { 

    var body = "" 

    if let params = parameters { 
     for (key, value) in params { 
      body += "--\(boundary)\r\n" 
      body += "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n" 
      body += "\(value)\r\n" 
     } 
    } 
    var filename = "" 

    if imageSelected { 
     filename = "video-\(uuid).mp4" 
    } 

    let mimetype = "video/mp4" 
    body += "--\(boundary)\r\n" 
    body += "Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n" 
    body += "Content-Type: \(mimetype)\r\n\r\n" 
    body += String(data: videoData, encoding: .utf8)! 
    body += "\r\n" 

    body += "--\(boundary)--\r\n" 

    return Data(body.utf8) 

} 

//関数はFUNC uploadVideoファイル をアップロードするPHPにリクエストを送信作成します(_ビデオデータ:データ){

let id = user!["id"] as! String 
    uuid = UUID().uuidString 


    let url = URL(string: "http://www.foo.com/videoposts.php")! 
    var request = URLRequest(url: url) 
    request.httpMethod = "POST" 

    let param = [ 
     "id" : id, 
     "uuid" : uuid 
    ] 

    // body 
    let boundary = "Boundary-\(UUID().uuidString)" 
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") 

    // if picture is selected, compress it by half 
    let imageData = Data() 


    // ... body 
    request.httpBody = createBodyWithParams(param, filePathKey: "file", videoData: imageData, boundary: boundary) 

    // launch session 
    URLSession.shared.dataTask(with: request) { data, response, error in 

     // get main queu to communicate back to user 
     DispatchQueue.main.async(execute: { 


      if error == nil { 

       do { 

        // json containes $returnArray from php 
        let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary 

        // declare new var to store json inf 
        guard let parseJSON = json else { 
         print("Error while parsing") 
         return 
        } 

        // get message from $returnArray["message"] 
        let message = parseJSON["message"] 

        // if there is some message - post is made 
        if message != nil { 

         // reset UI 

         self.postBtn.alpha = 0.4 
         self.imageSelected = false 

         // switch to another scene 
         self.tabBarController?.selectedIndex = 4 

        } 

       } catch { 

        // get main queue to communicate back to user 
        DispatchQueue.main.async(execute: { 
         let message = "\(error)" 
         appDelegate.infoView(message: message, color: colorSmoothRed) 
        }) 
        return 

       } 

      } else { 

       // get main queue to communicate back to user 
       DispatchQueue.main.async(execute: { 
        let message = error!.localizedDescription 
        appDelegate.infoView(message: message, color: colorSmoothRed) 
       }) 
       return 

      } 


     }) 

     }.resume() 

} 
+0

iOS 11では、新しい既定のビデオ形式としてhttps://en.wikipedia.org/wiki/High_Efficiency_Video_Codingが追加されています。 – ceejayoz

+0

おかげでceejayoz、私は記事を読んで始めましたが、実際のファイル拡張子が何であるかは不明です。あなたは知ってもらえますか? – techgirl

+0

私はそれが新しいファイル拡張子だとは思わない、ちょうど新しいコーデック。おそらく '.mov'か' .mp4'でしょう。 – ceejayoz

答えて

1

さて、実際にビデオをエンコードしてアップロードするコードを作成しました。 残念ながら、URLSessionmultipart/form-dataを行うのは実際にはかなり難しいので、私は実際にビデオをアップロードするのにAlamofireを使用しました。

この

は、部品のコードです:

UIImagePickerControllerDelegate

// MARK: UIImagePickerControllerDelegate 
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { 
    print("Cancelled video operation.") 
    dismiss(animated: true, completion: nil) 
} 

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 
    guard let mediaType = info[UIImagePickerControllerMediaType] as? String else { 
     print("Error with media type. Cancelling.") 
     dismiss(animated: true, completion: nil) 
     return; 
    } 

    print("Media type: \(mediaType)") 

    if (mediaType == "public.movie") { // Video selected 
     let videoURL: URL 
     if info[UIImagePickerControllerMediaURL] != nil { 
      videoURL = info[UIImagePickerControllerMediaURL] as! URL 
     } 
     else { 
      videoURL = info[UIImagePickerControllerReferenceURL] as! URL 
     } 


     if (picker.sourceType == .camera) { 
      // The original video came from the camera, so it's considered new 
      // Save it to the photo library 
      saveVideo(url: videoURL, albumName: "MyApp") 
     } 

     // Dismiss the media picker and then re-encode the video 
     dismiss(animated: true) { 
      self.exportVideoToMP4(url: videoURL) { (exportedVideoURL) in 

       guard let tempURL = exportedVideoURL else { 
        print("ERROR: Unknown error. The exported video URL is nil.") 
        return 
       } 

       print("Temporary video successfully exported to: \(tempURL.absoluteString)") 





       // TODO: Add your own POST parameters 
       let uuid = UUID().uuidString 
       let params = [ 
        "uuid" : uuid, 
        "user" : "myUserNameOrWhatever" 
       ] 


       // TODO: Change the parameters for uploading 
       self.upload( to: "http://yourweb.com/uploadVideo.php", // The URL to send the upload to 
           videoURL: tempURL, // The file URL of the temporary video file 
           parameters: params, // The POST parameters you want to send along with the upload 
           fileName: "vid-\(uuid).mp4", // The filename you want the server to receive. 
           fieldName: "video_file" // This is "name" from <input type="file" name="video_file" ... /> in HTML 
       ) { (response) in 

        guard let resp = response else { 
         print("ERROR: Empty or unrecognizable response from server.") 
         return 
        } 

        print("Video uploaded. RESPONSE: \(resp)") 

        //: TODO Parse the server response after uploading 
       } 

      } 
     } 
    } 
} 

フォトライブラリヘルパーメソッド

(これはあなたが // TODOにのコメントをチェックし、修正しなければならないものです)
// MARK: Photo Library 

func saveVideo(url: URL, albumName: String) { 

    // Check authorization status before trying to save the video 
    switch PHPhotoLibrary.authorizationStatus() { 

    case .notDetermined: 
     PHPhotoLibrary.requestAuthorization() { (status) in 
      switch status { 
      case .authorized: 
       self.saveVideo(url: url, albumName: albumName) // Re-try to save the video after authorization 
       return 

      default: 
       return 
      } 
     } 



    case .authorized: 
     // Save the video to the Photo Library here 

     if let assetCollection = assetCollection(albumName: albumName) { 

      // Asset collection exists, insert directly 
      insertVideo(url: url, assetCollection: assetCollection) 

     } 
     else { 

      // Asset collection doesn't exist, create it and then insert 
      PHPhotoLibrary.shared().performChanges({ 

       PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: albumName) 

      }, completionHandler: { (success, error) in 
       guard success else { 
        print("ERROR: \(error!.localizedDescription)") 
        return 
       } 

       let createdAssetCollection = self.assetCollection(albumName: albumName)! 
       self.insertVideo(url: url, assetCollection: createdAssetCollection) 
      }) 

     } 

     return 



    default: 
     // Not authorized 
     print("Not authorized to save a video to the Photo Library.") 
     return 
    } 


} 


func assetCollection(albumName: String) -> PHAssetCollection? { 
    let fetchOptions = PHFetchOptions() 
    fetchOptions.predicate = NSPredicate(format:"title == '\(albumName)'") 

    let fetchResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: fetchOptions) 

    return fetchResult.firstObject 
} 


func insertVideo(url: URL?, assetCollection: PHAssetCollection) { 
    guard let videoURL = url else { 
     print("ERROR: The URL to insert into the Photo Library is empty.") 
     return 
    } 

    PHPhotoLibrary.shared().performChanges({ 

     let createAssetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL) 
     let assetPlaceholder = createAssetRequest?.placeholderForCreatedAsset 
     let changeRequest = PHAssetCollectionChangeRequest(for: assetCollection) 

     let enumeration: NSArray = [assetPlaceholder!] 

     changeRequest?.addAssets(enumeration) 

    }, completionHandler: { (success, error) in 
     guard success else { 
      print("ERROR: \(error!.localizedDescription)") 
      return 
     } 

     print("Video saved successfully to the Photo Library album.") 
    }) 
} 

ビデオのアップロード

// MARK: Video upload 
func upload(to uploadAddress: String, videoURL: URL, parameters: [String:Any]?, fileName: String, fieldName: String, _ completion: ((String?) -> Void)?) { 

    Alamofire.upload(multipartFormData: { (multipartFormData) in 

     // Add the video file (if data is correct) 
     if let videoData = FileManager.default.contents(atPath: videoURL.path) { 
      multipartFormData.append(videoData, withName: fileName) 
     } 

     // Add the post params (if available) 
     if let params = parameters { 
      for (key, value) in params { 
       multipartFormData.append((value as! String).data(using: .utf8)! , withName: key) 
      } 
     } 

    }, to: uploadAddress) 
    { (result) in 

     switch result { 
     case .success(let upload, _, _): 
      upload.responseString { (response) in 
       if let completionHandler = completion { 
        completionHandler(response.result.value) 
       } 
      } 

     case .failure(let encodingError): 
      print("ERROR: \(encodingError.localizedDescription)") 
      if let completionHandler = completion { 
       completionHandler(nil) 
      } 
     } 

    } 

} 

AVFoundation

// MARK: AVFoundation 
func exportVideoToMP4(url: URL, _ completion: @escaping ((URL?) -> Void)) { 

    // Show some sort of indicator here, as this could take a while 


    // Generate a temporary URL path to export the video 
    let relativePath = "myAppTempVideoExport.mp4"; 
    let outputFilePath = NSTemporaryDirectory() + relativePath; 

    print("Temp file path: \(outputFilePath)") 


    // If there's any temp file from before at that path, delete it 
    if FileManager.default.fileExists(atPath: outputFilePath) { 
     do { 
      try FileManager.default.removeItem(atPath: outputFilePath) 
     } 
     catch { 
      print("ERROR: Can't remove temporary file from before. Cancelling export.") 
      completion(nil) 
      return 
     } 
    } 


    // Export session setup 
    let outputFileURL = URL(fileURLWithPath: outputFilePath) 

    let asset = AVAsset(url: url) // Original (source) video 

    // The original video codec is probably HEVC, so we'll force the system to re-encode it at the highest quality in MP4 
    // You probably want to use medium quality if this video is intended to be uploaded (as this example is doing) 
    if let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) { 

     exportSession.outputURL = outputFileURL 
     exportSession.outputFileType = .mp4 

     exportSession.exportAsynchronously { 

      // Hide the indicator for the export session 

      switch exportSession.status { 
      case .completed: 
       print("Video export completed.") 
       completion(outputFileURL) 
       return 

      case .failed: 
       print("ERROR: Video export failed. \(exportSession.error!.localizedDescription)") 
       completion(nil) 
       return 

      case .cancelled: 
       print("Video export cancelled.") 
       completion(nil) 
       return 

      default: 
       break 
      } 

     } 

    } 
    else { 
     print("ERROR: Cannot create an AVAssetExportSession.") 
     return 
    } 

} 

今(符号化方式)、これが機能するために、あなたは明らかに動画を記録するために持っている、インポート(CocoaPodsからインストールAlamofireを、使用して)ビューコントローラがプロトコルに準拠していることを指定します:

import AVFoundation 
import Photos 
import Alamofire 



class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { 
    let imagePicker = UIImagePickerController() 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 
     imagePicker.sourceType = .camera 
     imagePicker.delegate = self 
     imagePicker.showsCameraControls = true 
     imagePicker.allowsEditing = true 
     imagePicker.mediaTypes = ["public.movie"] 

     DispatchQueue.main.async { 
      self.present(self.imagePicker, animated: true, completion: nil) 
     } 
    } 
} 

私はこれがあなたにとって有用であることを願っています。お気軽にお問い合わせください。

関連する問題