www novedades ipadizate descargar apple acethinker ios video streaming pffile parse-server

novedades - ios 12 iphone 6



iOS-No se puede transmitir video desde Parse Backend (4)

Recientemente, he creado mi propio servidor de análisis alojado en heroku usando mongoLab para almacenar mis datos.

Mi problema es que estoy guardando un video como un análisis PFFile , sin embargo, parece que no puedo transmitirlo luego de guardarlo.

Aquí están mis pasos exactos.

Primero, UIImagePicker el video devuelto por UIImagePicker

//Get the video URL let videoURL = info[UIImagePickerControllerMediaURL] as? NSURL //Create PFFile with NSData from URL let data = NSData(contentsOfURL: videoURL!) videoFile = PFFile(data: data!, contentType: "video/mp4") //Save PFFile first, then save the PFUser PFUser.currentUser()?.setObject(videoFile!, forKey: "profileVideo") videoFile?.saveInBackgroundWithBlock({ (succeeded, error) -> Void in print("saved video") PFUser.currentUser()?.saveInBackgroundWithBlock({ (succeeded, error) -> Void in if succeeded && error == nil { print("user saved") //Hide progress bar UIView.animateWithDuration(0.5, animations: { () -> Void in self.progressBar.alpha = 0 }, completion: { (bool) -> Void in self.progressBar.removeFromSuperview() }) }else{ //Show error if the save failed let message = error!.localizedDescription let alert = UIAlertController(title: "Uploading profile picture error!", message: message, preferredStyle: UIAlertControllerStyle.Alert) let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil) alert.addAction(dismiss) self.presentViewController(alert, animated: true, completion: nil) } }) }, progressBlock: { (progress) -> Void in self.progressBar.setProgress(Float(progress)/100, animated: true) })

Todo esto funciona bien El problema radica cuando recupero el PFFile y trato de transmitir el video. Aquí está mi código para eso:

//Get URL from my current user self.videoFile = PFUser.currentUser()?.objectForKey("profileVideo") as? PFFile self.profileVideoURL = NSURL(string: (self.videoFile?.url)!) //Create AVPlayerController let playerController = AVPlayerViewController() //Set AVPlayer URL to where the file is stored on the sever let avPlayer = AVPlayer(URL: self.profileVideoURL) playerController.player = avPlayer //Present the playerController self.presentViewController(playerController, animated: true, completion: { () -> Void in playerController.player?.play() })

Lo que termina sucediendo cuando presento el playerController es este:

¿Por qué sucede esto cuando intento transmitir mi video?

¡Cualquier ayuda es muy apreciada!

ACTUALIZAR

Recientemente intenté reproducir un video guardado desde una base de datos diferente usando esta línea de código: let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")

Esto confirma que es el formato en el que estoy guardando mi PFFile que está causando el error.

Debe ser esta línea la que causa el error ya que "video/mp4" probablemente no sea el formato correcto: videoFile = PFFile(data: data!, contentType: "video/mp4")

ACTUALIZACIÓN 2

Tomé el enlace directo de mi archivo .mp4 ubicado en mongoLab y encontré que puedo reproducirlo en google chrome, pero no en safari o en mi iPhone.

ACTUALIZACIÓN 3

Descubrí que esto era un problema con la API de análisis en sí, y no tenía nada que ver con el código, ya que mi código funciona perfectamente cuando se usa el motor de análisis original (el que se está cerrando) en lugar de mi servidor de análisis personalizado. Actualmente no tengo solución, sin embargo, debería arreglarse con el tiempo.


este código funciona para mí

let playerController = AVPlayerViewController() self.addChildViewController(playerController) self.view.addSubview(playerController.view) playerController.view.frame = self.view.frame file!.getDataInBackgroundWithBlock({ (movieData: NSData?, error: NSError?) -> Void in if (error == nil) { let filemanager = NSFileManager.defaultManager() let documentsPath : AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0] let destinationPath:NSString = documentsPath.stringByAppendingString("/file.mov") movieData!.writeToFile ( destinationPath as String, atomically:true) let playerItem = AVPlayerItem(asset: AVAsset(URL: NSURL(fileURLWithPath: destinationPath as String))) let player = AVPlayer(playerItem: playerItem) playerController.player = player player.play() } else { print ("error on getting movie data /(error?.localizedDescription)") } })


parse-server no parece ser compatible con la transmisión en Safari / iOS y la solución es habilitarlo usando express & GridStore de la siguiente manera:

parse-server-example / node_modules / parse-server / lib / Routers / FilesRouter

{ key: ''getHandler'', value: function getHandler(req, res, content) { var config = new _Config2.default(req.params.appId); var filesController = config.filesController; var filename = req.params.filename; var video = ''.mp4'' var lastFourCharacters = video.substr(video.length - 4); if (lastFourCharacters == ''.mp4'') { filesController.handleVideoStream(req, res, filename).then(function (data) { }).catch(function (err) { console.log(''404FilesRouter''); res.status(404); res.set(''Content-Type'', ''text/plain''); res.end(''File not found.''); }); }else{ filesController.getFileData(config, filename).then(function (data) { res.status(200); res.end(data); }).catch(function (err) { res.status(404); res.set(''Content-Type'', ''text/plain''); res.end(''File not found.''); }); } } } , ...

parse-server-example / node_modules / parse-server / lib / Controllers / FilesController

_createClass(FilesController, [{ key: ''getFileData'', value: function getFileData(config, filename) { return this.adapter.getFileData(filename); } },{ key: ''handleVideoStream'', value: function handleVideoStream(req, res, filename) { return this.adapter.handleVideoStream(req, res, filename); } }, ...

parse-server-example / node_modules / parse-server / lib / Adapters / Files / GridStoreAdapter

... , { key: ''handleVideoStream'', value: function handleVideoStream(req, res, filename) { return this._connect().then(function (database) { return _mongodb.GridStore.exist(database, filename).then(function () { var gridStore = new _mongodb.GridStore(database, filename, ''r''); gridStore.open(function(err, GridFile) { if(!GridFile) { res.send(404,''Not Found''); return; } console.log(''filename''); StreamGridFile(GridFile, req, res); }); }); }) } }, ...

Parte inferior del adaptador GridStore

function StreamGridFile(GridFile, req, res) { var buffer_size = 1024 * 1024;//1024Kb if (req.get(''Range'') != null) { //was: if(req.headers[''range'']) // Range request, partialle stream the file console.log(''Range Request''); var parts = req.get(''Range'').replace(/bytes=/, "").split("-"); var partialstart = parts[0]; var partialend = parts[1]; var start = partialstart ? parseInt(partialstart, 10) : 0; var end = partialend ? parseInt(partialend, 10) : GridFile.length - 1; var chunksize = (end - start) + 1; if(chunksize == 1){ start = 0; partialend = false; } if(!partialend){ if(((GridFile.length-1) - start) < (buffer_size) ){ end = GridFile.length - 1; }else{ end = start + (buffer_size); } chunksize = (end - start) + 1; } if(start == 0 && end == 2){ chunksize = 1; } res.writeHead(206, { ''Cache-Control'': ''no-cache'', ''Content-Range'': ''bytes '' + start + ''-'' + end + ''/'' + GridFile.length, ''Accept-Ranges'': ''bytes'', ''Content-Length'': chunksize, ''Content-Type'': ''video/mp4'', }); GridFile.seek(start, function () { // get GridFile stream var stream = GridFile.stream(true); var ended = false; var bufferIdx = 0; var bufferAvail = 0; var range = (end - start) + 1; var totalbyteswanted = (end - start) + 1; var totalbyteswritten = 0; // write to response stream.on(''data'', function (buff) { bufferAvail += buff.length; //Ok check if we have enough to cover our range if(bufferAvail < range) { //Not enough bytes to satisfy our full range if(bufferAvail > 0) { //Write full buffer res.write(buff); totalbyteswritten += buff.length; range -= buff.length; bufferIdx += buff.length; bufferAvail -= buff.length; } } else{ //Enough bytes to satisfy our full range! if(bufferAvail > 0) { var buffer = buff.slice(0,range); res.write(buffer); totalbyteswritten += buffer.length; bufferIdx += range; bufferAvail -= range; } } if(totalbyteswritten >= totalbyteswanted) { // totalbytes = 0; GridFile.close(); res.end(); this.destroy(); } }); }); }else{ // res.end(GridFile); // stream back whole file res.header(''Cache-Control'', ''no-cache''); res.header(''Connection'', ''keep-alive''); res.header("Accept-Ranges", "bytes"); res.header(''Content-Type'', ''video/mp4''); res.header(''Content-Length'', GridFile.length); var stream = GridFile.stream(true).pipe(res); } };

PD La respuesta original está dada por @Bragegs aquí - https://github.com/ParsePlatform/parse-server/issues/1440#issuecomment-212815625 . User @ Stav1 también lo mencionó en este hilo, pero desafortunadamente él fue votado negativamente.



Para cualquiera que aterrice aquí todavía, al mirar la nueva actualización del ejemplo de Parse-Server, Parse-server ahora reconoce la transmisión; sin embargo, debes utilizar el método de SDK de Parse iOS para recuperar el video. El código del servidor está debajo en caso de que esté desplegando un servidor parse personalizado. Sigo con una lista de algunos de los métodos de transmisión.

Cambio de código de servidor encontrado en:

parse-server-example / node_modules / parse-server / lib / Routers / FilesRouter

{ key: ''getHandler'', value: function getHandler(req, res) { var config = new _Config2.default(req.params.appId); var filesController = config.filesController; var filename = req.params.filename; var contentType = _mime2.default.lookup(filename); if (isFileStreamable(req, filesController)) { filesController.getFileStream(config, filename).then(function (stream) { handleFileStream(stream, req, res, contentType); }).catch(function () { res.status(404); res.set(''Content-Type'', ''text/plain''); res.end(''File not found.''); }); } else { filesController.getFileData(config, filename).then(function (data) { res.status(200); res.set(''Content-Type'', contentType); res.set(''Content-Length'', data.length); res.end(data); }).catch(function () { res.status(404); res.set(''Content-Type'', ''text/plain''); res.end(''File not found.''); }); } }},

Ejemplo de método para la transmisión con iOS parse sdk (swift):

vidObject.video.getDataStreamInBackground(block: <#T##PFDataStreamResultBlock?##PFDataStreamResultBlock?##(InputStream?, Error?) -> Void#>)