录制的iPhone X视频赢得';上传到PHP服务器后不能播放

录制的iPhone X视频赢得';上传到PHP服务器后不能播放,php,ios,swift,video,Php,Ios,Swift,Video,根据建议解决方案修改代码,但仍不起作用。视频以0字节的形式上传。我有一个应用程序,用户应该能够从手机录制视频,当选择“使用视频”时,它会将视频上传到我们的PHP服务器。文件正在成功上载,根据显示的大小,它不是空的。但是,当我在应用程序中播放视频,甚至直接通过浏览器播放视频时,它不会播放。播放代码没有问题,因为我已经硬编码了其他网站上其他视频的链接,效果很好。代码如下,非常感谢您的帮助 // Finished recording a video func imagePickerController

根据建议解决方案修改代码,但仍不起作用。视频以0字节的形式上传。我有一个应用程序,用户应该能够从手机录制视频,当选择“使用视频”时,它会将视频上传到我们的PHP服务器。文件正在成功上载,根据显示的大小,它不是空的。但是,当我在应用程序中播放视频,甚至直接通过浏览器播放视频时,它不会播放。播放代码没有问题,因为我已经硬编码了其他网站上其他视频的链接,效果很好。代码如下,非常感谢您的帮助

// 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视频转换

  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).")
    }
}
//创建参数

   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)

}
//函数用于向PHP发送上传文件的请求 func上传视频(视频数据:数据){


好的,我做了一些编码来实际编码和上传视频。 不幸的是,在
URLSession
中执行
multipart/form data
实际上相当困难,因此我使用
Alamofire
实际上传视频

以下是部分代码:

UIImagePickerControllerDelegate(这是您应该修改的,请检查//TODO注释)

视频上传(使用
Alamofire
,从CocoaPods安装)

AVFoundation(编码方法)

现在,要使其工作,您显然必须录制视频、导入框架并指定视图控制器符合协议,因此:

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)
        }
    }
}

我希望这对你有用,请随意提问。

iOS 11添加为新的默认视频格式。感谢ceejayoz,我开始阅读这篇文章,但不清楚实际的文件扩展名是什么。你知道吗?我不认为这是一个新的文件扩展名,只是一个新的编解码器。
.mov
.mp4
可能。你为什么不知道呢-将您的视频编码为MP4?您收到的视频可能是HEC。您可能想使用
AVAssetExportSession
来完成此操作。@techgirl08能否请您上传更新的代码,以便我测试可能的错误?
// 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
                }

            }
        }
    }
}
// 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)
            }
        }

    }

}
// 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
    }

}
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)
        }
    }
}