Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/101.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift-将视频转换为数据和字符串并使用UTF8编码返回nil-通过HTTP POST将视频发送到AWS S3存储桶_Ios_Swift_Amazon Web Services_Amazon S3_Video - Fatal编程技术网

Ios Swift-将视频转换为数据和字符串并使用UTF8编码返回nil-通过HTTP POST将视频发送到AWS S3存储桶

Ios Swift-将视频转换为数据和字符串并使用UTF8编码返回nil-通过HTTP POST将视频发送到AWS S3存储桶,ios,swift,amazon-web-services,amazon-s3,video,Ios,Swift,Amazon Web Services,Amazon S3,Video,问题的高级解释(在Swift 5中) 我正在使用AVAssetWriter 我正在使用exportSession.exportAsynchronously在MP4中对视频进行编码(但是我可以跳过这一步,我仍然有相同的问题) 我通过HTTP POST将视频发送到AWS S3存储桶,其中包含: let fileData=尝试将NSData(contentsOfFile:videoPathMP4.path,选项:[])作为数据使用 让fileContent=String(数据:fileData,编

问题的高级解释(在Swift 5中)

  • 我正在使用
    AVAssetWriter

  • 我正在使用
    exportSession.exportAsynchronously
    在MP4中对视频进行编码(但是我可以跳过这一步,我仍然有相同的问题)

  • 我通过HTTP POST将视频发送到AWS S3存储桶,其中包含:

    let fileData=尝试将NSData(contentsOfFile:videoPathMP4.path,选项:[])作为数据使用

    让fileContent=String(数据:fileData,编码:.utf8)

  • fileContent
    现在为
    nil
    ,这意味着视频数据不能用UTF8解释。如果我使用UTF16,它可以工作(我得到一个字符串),但当我在服务器端收到消息时,它不是一个可读的MP4文件(它已损坏?)。我觉得这是因为它应该是UTF8中的字符串,但我无法将视频数据转换为UTF8字符串发送到服务器

    如何以UTF8格式发送此数据,或者如何仅以NSData格式发送视频数据?我是不是看错了

    以下是不同步骤中的代码片段:

    步骤1-在MOV中录制视频:

    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer).seconds
                switch _captureState {
                case .start:
                    print ("starting to record")
                    // Set up recorder
                    _filename = UUID().uuidString
                    let videoPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("\(_filename).mov")
                    let writer = try! AVAssetWriter(outputURL: videoPath, fileType: .mov)
                    let settings = _videoOutput!.recommendedVideoSettingsForAssetWriter(writingTo: .mov)
                    let input = AVAssetWriterInput(mediaType: .video, outputSettings: settings) 
                    input.mediaTimeScale = CMTimeScale(bitPattern: 600)
                    input.expectsMediaDataInRealTime = true
                    input.transform = CGAffineTransform(rotationAngle: .pi/2)
                    let adapter = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: input, sourcePixelBufferAttributes: nil)
                    if writer.canAdd(input) {
                        writer.add(input)
                    }
                    writer.startWriting()
                    writer.startSession(atSourceTime: .zero)
                    _assetWriter = writer
                    _assetWriterInput = input
                    _adpater = adapter
                    _captureState = .capturing
                    _time = timestamp
                case .capturing:
                    if _assetWriterInput?.isReadyForMoreMediaData == true {
                        let time = CMTime(seconds: timestamp - _time, preferredTimescale: CMTimeScale(600))
                        _adpater?.append(CMSampleBufferGetImageBuffer(sampleBuffer)!, withPresentationTime: time)
                    }
                    break
                case .end:
                    guard _assetWriterInput?.isReadyForMoreMediaData == true, _assetWriter!.status != .failed else { break }
                    _assetWriterInput?.markAsFinished()
                    _assetWriter?.finishWriting { [weak self] in
                        self?._captureState = .idle
                        self?._assetWriter = nil
                        self?._assetWriterInput = nil
                        print ("Finished writing video file: \(self!._filename)")
                    }
                default:
                    break
                }
    
    }
    
    步骤2-在MP4中编码视频(同步以避免发送数据时出现争用情况):

    步骤3-发送视频(获取到S3的临时URL并进行身份验证以发送实际的视频文件,然后发送视频文件-所有阻止调用的调用):

    private func sendVideo(文件名:String,记录ID:String){
    //获取临时URL和凭据
    让url=url(字符串:“https:/”)!
    //服务器的JSON负载
    让数据=[
    “记录ID”:记录ID,
    ]as[字符串:任意]
    let group=DispatchGroup()
    group.enter()
    sendVideoURLRequestToRestAPI(url:url,数据:数据)
    {响应,json,错误在
    //将在完成或出错时调用。
    guard let statusCode=响应?.statusCode其他{
    打印(“[sendVideo]未返回状态代码-请求失败”)
    返回
    }
    打印(“来自服务器的状态代码:\(状态代码)”)
    如果状态代码!=200{
    DispatchQueue.main.async{
    让alert2=UIAlertController(标题:“错误”,消息:“提交数据时出错-请重试!-\(json[“body”]as?String)”,首选样式:。警报)
    addAction(UIAlertAction(标题:“确定”,样式:。默认,处理程序:nil))
    self.present(警报2,动画:true)
    }
    }否则{//成功
    让videoURL=json[“url”]作为!字符串
    设参数=[
    [
    “密钥”:“密钥”,
    “值”:(json[“字段”]as![String:Any])[“键”!,
    “类型”:“文本”
    ],
    [
    “密钥”:“AWSAccessKeyId”,
    “值”:(json[“字段”]as![String:Any][“AWSAccessKeyId”]!,
    “类型”:“文本”
    ],
    [
    “密钥”:“签名”,
    “值”:(json[“字段”]as![String:Any])[“签名”!,
    “类型”:“文本”
    ],
    [
    “密钥”:“策略”,
    “值”:(json[“字段”]as![String:Any])[“策略”!,
    “类型”:“文本”
    ],
    [
    “密钥”:“x-amz-security-token”,
    “值”:(json[“字段”]as![String:Any][“x-amz-security-token”]!,
    “类型”:“文本”
    ],
    [
    “密钥”:“文件”,
    “src”:文件名,
    “类型”:“文件”,
    “内容类型”:“视频/mp4”
    ]
    ]as[[String:Any]]
    let boundary=“boundary-\(UUID().uuidString)”
    var body=“”
    变量错误:错误?=nil
    参数中的参数{
    如果参数[“禁用”]==nil{
    让paramName=param[“key”]!
    正文+=“--\(边界)\r\n”
    body+=“内容处置:表单数据;名称=\”\(paramName)\“”
    如果参数[“contentType”]!=nil{
    body+=“\r\n内容类型:\(参数[“contentType”]as!String)”
    }
    让paramType=param[“type”]作为!字符串
    如果paramType==“text”{
    让paramValue=param[“value”]作为!字符串
    正文+=“\r\n\r\n\(参数值)\r\n”
    }否则{
    让paramSrc=param[“src”]作为!字符串
    打印(“paramSrc:\(paramSrc)”)
    让videoPath=FileManager.default.url(用于:.documentDirectory,位于:.userDomainMask中)。首先!.appendingPathComponent(“\(paramSrc.mov”)
    encodeVideo(位于:videoPath,completionHandler:{url,错误在
    保护错误==nil else{
    打印(“错误视频mp4转换”)
    打印(字符串(描述:错误))
    返回
    }
    })
    
        func encodeVideo(at videoURL: URL, completionHandler: ((URL?, Error?) -> Void)?)  {
        let avAsset = AVURLAsset(url: videoURL, options: nil)
    
        let startDate = Date()
    
        //Create Export session
        guard let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough) else {
            completionHandler?(nil, nil)
            return
        }
    
        //Creating temp path to save the converted video
        let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
        let filePath = documentsDirectory.appendingPathComponent("rendered-Video.mp4")
    
        //Check if the file already exists then remove the previous file
        if FileManager.default.fileExists(atPath: filePath.path) {
            do {
                try FileManager.default.removeItem(at: filePath)
            } catch {
                completionHandler?(nil, error)
            }
        }
    
        exportSession.outputURL = filePath
        exportSession.outputFileType = AVFileType.mp4
        exportSession.shouldOptimizeForNetworkUse = true
          let start = CMTimeMakeWithSeconds(0.0, preferredTimescale: 0)
        let range = CMTimeRangeMake(start: start, duration: avAsset.duration)
        exportSession.timeRange = range
    
        let group = DispatchGroup()
        group.enter()
        
        exportSession.exportAsynchronously(completionHandler: {() -> Void in
            switch exportSession.status {
            case .failed:
                print(exportSession.error ?? "NO ERROR")
                completionHandler?(nil, exportSession.error)
            case .cancelled:
                print("Export canceled")
                completionHandler?(nil, nil)
            case .completed:
                //Video conversion finished
                let endDate = Date()
    
                let time = endDate.timeIntervalSince(startDate)
                print(time)
                print("Successful!")
                print(exportSession.outputURL ?? "NO OUTPUT URL")
                completionHandler?(exportSession.outputURL, nil)
    
                default: break
            }
            group.leave()
        })
        group.wait(timeout: .now() + 10.0) // blocks current queue
    }
    
        private func sendVideo(filename: String, recordID: String){
        
        //Obtain temporary URL and credentials
        let url = URL(string: "https://<OMITTED>")!
    
        //JSON Payload for server
        let data = [
                    "recordid" : recordID,
        ] as [String : Any]
        
        let group = DispatchGroup()
        group.enter()
        Helper.sendVideoURLRequestToRestAPI(url: url, data: data)
            { response, json, error in
                    // will be called at either completion or at an error.
            
                    guard let statusCode = response?.statusCode else{
                        print ("[sendVideo] no status code returned - request failed")
                        return
                    }
                    print ("Status Code from server: \(statusCode)")
            
                    if statusCode != 200 {
                        DispatchQueue.main.async {
                            let alert2 = UIAlertController(title: "Error", message: "Error submitting data - please try again! - \(json["body"] as? String)", preferredStyle: .alert)
                            alert2.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                            self.present(alert2, animated: true)
                        }
    
                    } else { //success
                        
                        let videoURL = json["url"] as! String
    
                        let parameters = [
                          [
                            "key": "key",
                            "value": (json["fields"] as! [String : Any])["key"]!,
                            "type": "text"
                          ],
                          [
                            "key": "AWSAccessKeyId",
                            "value": (json["fields"] as! [String : Any])["AWSAccessKeyId"]!,
                            "type": "text"
                          ],
                          [
                            "key": "signature",
                            "value": (json["fields"] as! [String : Any])["signature"]!,
                            "type": "text"
                          ],
                          [
                            "key": "policy",
                            "value": (json["fields"] as! [String : Any])["policy"]!,
                            "type": "text"
                          ],
                          [
                            "key": "x-amz-security-token",
                            "value": (json["fields"] as! [String : Any])["x-amz-security-token"]!,
                            "type": "text"
                          ],
                          [
                            "key": "file",
                            "src": filename, 
                            "type": "file",
                            "contentType": "video/mp4"
                          ]
                        ] as [[String : Any]]
    
                        let boundary = "Boundary-\(UUID().uuidString)"
                        var body = ""
                        var error: Error? = nil
                        for param in parameters {
                            if param["disabled"] == nil {
                                let paramName = param["key"]!
                                body += "--\(boundary)\r\n"
                                body += "Content-Disposition:form-data; name=\"\(paramName)\""
                                if param["contentType"] != nil {
                                  body += "\r\nContent-Type: \(param["contentType"] as! String)"
                                }
                                let paramType = param["type"] as! String
                                if paramType == "text" {
                                  let paramValue = param["value"] as! String
                                  body += "\r\n\r\n\(paramValue)\r\n"
                                } else {
                                    let paramSrc = param["src"] as! String
                                    print("paramSrc: \(paramSrc)")
                                    let videoPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("\(paramSrc).mov")
                                    
                                    self.encodeVideo(at: videoPath, completionHandler: { url, error in
                                        guard error == nil else {
                                            print ("error video mp4 conversion")
                                            print(String(describing: error))
                                            return
                                        }
                                    })
                                    let videoPathMP4 = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("rendered-Video.mp4")
    
                                    do {
                                        let fileData = try NSData(contentsOfFile:videoPathMP4.path, options:[]) as Data
                                        let fileContent = String(data: fileData, encoding: .utf8)! //Exception thrown here - IF I change this to UTF16 it doesn't throw an exception but the file arrives corrupted on server side.
    
                                        body += "; filename=\"\(paramName)\"\r\n"
                                        + "Content-Type: \"content-type header\"\r\n\r\n\(fileContent)\r\n" //paramName = paramSrc
                                    
                                      //  print ("Body: \(body)")
                                    } catch {
                                        print ("Could not open video file: \(videoPathMP4.path)")
                                        return
                                    }
                                }
                            }
                        }
                        body += "--\(boundary)--\r\n";
                        let postData = body.data(using: .utf8) //UTF8
    
                        var request = URLRequest(url: URL(string: videoURL)!,timeoutInterval: Double.infinity)
                        request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
                        request.httpMethod = "POST"
                        request.httpBody = postData
    
    
                        let session = URLSession.shared
                        let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
    
                            guard error == nil else {
                                print ("error")
                                print(String(describing: error))
                                return
                            }
    
                            guard let data = data else {
                                print ("Error unpacking data")
                                print(String(describing: error))
                                //semaphore.signal()
                                return
                            }
    
                            print ("data \(data) - \(response)")
                            print(String(data: data, encoding: .utf8)!)
                        })
                        task.resume()
    
                        group.leave()
                    }
            }
        group.wait() // blocks current queue
    }