IOS - Impossibly streaming video from Parse Backend

I recently created my own parser server hosted on heroku using mongoLab to store my data.

My problem is that I am saving the video as PFFile , however I cannot play it after saving.

Here are my exact steps.

First, I save the video returned by 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) }) 

It all works well. The problem is that I am extracting the PFFile and trying to transfer the video. Here is my code for this:

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

What happens when I introduce playerController is:

enter image description here

Why does this happen when I try to transfer my video?

Any help is much appreciated!

UPDATE

I recently tried to play a video saved from another database using this line of code: let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")

This confirms that it is a format that I save in a PFFile , resulting in an error.

There should be this line causing the error, since "video/mp4" is probably not the correct format: videoFile = PFFile(data: data!, contentType: "video/mp4")

UPDATE 2

I took a direct link to my .mp4 file located on mongoLab and found that I can play it in Google Chrome, but not on safari or my iPhone.

UPDATE 3

I found that it was a problem with the parse api itself and had nothing to do with the code, as my code works fine when using the original parsing source file (the one that closes) instead of my custom parsing server. I have no solution, but it needs to be fixed over time.

+5
source share
4 answers

this code works for me

 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)") } }) 
+1
source

parse-server doesn't seem to support streaming in Safari / iOS, and the solution is to enable it using express and GridStore as follows:

syntax-server-example \ node_modules \ parsing-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.'); }); } } } , ... 

syntax-server-example \ node_modules \ parsing-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); } }, ... 

syntax-server example \ node_modules \ parsing 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); }); }); }) } }, ... 

GridStore adapter bottom

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

PS The original answer is given here @Bragegs - https://github.com/ParsePlatform/parse-server/issues/1440#issuecomment-212815625 . @ Stav1 also mentioned this in this thread, but unfortunately was it blocked?

0
source

For those who land here still looking at the new Parse-Server example, Parse-server now recognizes streaming; however, you must use the parse iOS sdk method to retrieve the video. The following is the server code if you are deploying your own parser. I am following a list of some streaming methods.

Server code change found in:

syntax-server-example \ node_modules \ parsing-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.'); }); } }}, 

Example method for streaming using iOS parse sdk (swift):

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

I have a local mongodb with a parse server and you need to do this:

Video stream analysis flow in IOS from PFFile.url

I don’t know if this coincides with non-local databases.

-1
source

Source: https://habr.com/ru/post/1242411/


All Articles