2016-02-05 10 views
5

Kürzlich habe ich meinen eigenen Parse-Server erstellt, der auf Heroku gehostet wird, indem ich mongoLab verwende, um meine Daten zu speichern.iOS - Video kann nicht von Parse Backend gestreamt werden

Mein Problem ist, ich speichere ein Video als Parse PFFile, aber ich kann nicht scheinen, um es nach dem Speichern zu streamen.

Hier sind meine genauen Schritte.

Zuerst speichere ich das Video wieder von 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) 
      }) 

Das alles gut funktioniert. Das Problem liegt, wenn ich die PFFile abrufen und versuchen, das Video zu streamen. Hier ist mein Code dafür:

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

Was am Ende passiert, wenn ich die playerController präsentieren, ist dies:

enter image description here

, warum dies geschieht, wenn ich versuche, mein Video streamen?

Jede Hilfe wird sehr geschätzt!

UPDATE

Ich habe vor kurzem versucht haben, ein Video von einer anderen Datenbank mit dieser Codezeile gespeichert spielen: let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")

Dies bestätigt, dass es das Format ich Speichern bin mein PFFile, dass verursacht der Fehler.

Es muss diese Linie den Fehler verursacht als "video/mp4" wahrscheinlich nicht das richtige Format ist: videoFile = PFFile(data: data!, contentType: "video/mp4")

UPDATE 2

ich den direkten Link meiner .mp4-Datei auf mongoLab befindet sich genommen haben und gefunden Ich kann es in Google Chrome spielen, aber nicht auf Safari oder meinem iPhone.

UPDATE 3

ich gefunden habe, dass dies ein Problem mit dem Parse-api war selbst, und hatte nichts mit dem Code zu tun, wie mein Code funktioniert perfekt, wenn der Original-Parse-Backend (das, das ist Schließen) anstelle meines benutzerdefinierten Parse-Servers. Ich habe derzeit keine Lösung, aber es sollte im Laufe der Zeit behoben werden.

+1

Ich habe eine ähnliche (gleiche?) Frage. Kannst du etwas über dein drittes Update erfahren? Wurde dies den Betreuern von GH gemeldet? – sbauch

+1

@Josh Dies wurde oft in der GH aber vergeblich gemeldet. Sie würden es einfach als Serverproblem schließen. Einige Leute haben Erfolg gemeldet, indem sie von mLab auf S3 gewechselt haben, aber es gibt andere, die dasselbe Problem von S3 gemeldet haben. Von jetzt an parse Server -heroku- mlaab streamt kein Audio, Videodateien sind das, was wir schließen konnten. Wenn irgendjemand das lösen könnte, sollten wir uns selbst helfen, indem wir die Lösung hier veröffentlichen. Ich denke nicht, dass es von Parse-Mitarbeitern gelöst wird. – Tobio

Antwort

-1

Ich habe eine lokale mongodb mit Parse-Server und dies benötigt, damit es funktioniert: obwohl

Parse-server stream video to IOS from PFFile.url

Sie wissen nicht, ob es das gleiche mit nicht-lokalen Datenbanken ist.

+0

Wenn Sie eine NEUE Frage haben, klicken Sie bitte auf die Schaltfläche [Frage stellen] (// stackoverflow.com/questions/ask). Wenn Sie eine ausreichende Reputation haben, können Sie die Frage (// stackoverflow.com/privileges/vote-up) stellen. Alternativ "Stern" als Favorit und Sie werden über neue Antworten benachrichtigt. –

1

dieser Code funktioniert für mich

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

Parse-Server scheint nicht in Safari/iOS-Streaming unterstützt zu werden, und die Lösung ist die ermöglicht es ausdrücklich & Gridstor wie folgt verwendet wird,

parsen-server-Beispiel \ 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-Beispiel \ 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); 
} 
}, ... 

Parse-Server-Beispiel \ 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); 
     }); 
     }); 
     }) 
     } 
     }, ... 

Bottom of Gridstore Adapter

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

P. S Die ursprüngliche Antwort wird von @Braggs hier gegeben - https://github.com/ParsePlatform/parse-server/issues/1440#issuecomment-212815625. User @ Stav1 hat es auch in diesem Thread erwähnt, aber leider wurde er downvooted?

0

Für jeden, der hier noch landet, erkennt Parse-Server beim Betrachten des neuen Parse-Server-Beispiel-Updates nun Streaming; Sie sollten jedoch die Methode Parse iOS sdk verwenden, um das Video abzurufen. Der Server-Code ist unten, wenn Sie einen benutzerdefinierten Parse-Server einrichten. Ich folge mit einer Liste einiger Streaming-Methoden.

Server-Codeänderung gefunden:

Parse-Server-Beispiel \ node_modules \ Parsing-server \ lib \ Router \ 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.'); 
    }); 
    } 
}}, 

Methode Beispiel für das Streaming mit iOS Parse-sdk (swift):

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