2016-02-05 2 views
5

Недавно я создал свой собственный сервер синтаксического анализа, размещенный на heroku, используя mongoLab для хранения моих данных.iOS - Не удается передать видео из Parse Backend

Моя проблема заключается в том, что я сохраняю видео в виде разбора PFFile, однако я не могу его воспроизвести после сохранения.

Вот мои точные шаги.

Во-первых, я сохранить видео возвращенное 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) 
      }) 

Это все работает хорошо. Проблема заключается в том, что я извлекаю PFFile и пытаюсь передать видео. Вот мой код, который:

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

Что в конечном итоге происходит, когда я представляю playerController это:

enter image description here

Почему это происходит, когда я пытаюсь поток видео?

Любая помощь с благодарностью!

UPDATE

Недавно я пытался играть видео сохраненную из другой базы данных, используя следующую строку кода: let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")

Это подтверждает, что это формат Я спасаю мой PFFile в том, что вызывает Ошибка.

Она должна быть эта строка вызывает ошибку в "video/mp4", вероятно, не правильный формат: videoFile = PFFile(data: data!, contentType: "video/mp4")

UPDATE 2

Я взял прямую ссылку на свой файл, расположенный на .mp4 mongoLab и нашел Я могу воспроизвести его в Google Chrome, но не на сафари или моем iPhone.

UPDATE 3

Я обнаружил, что это была проблема с самого разбора апи, и не имеет ничего общего с кодом, как мой код работает отлично при использовании оригинального синтаксического анализа бэкенд (тот, который закрытие) вместо моего настраиваемого сервера синтаксического анализа. В настоящее время у меня нет решения, но со временем оно должно быть исправлено.

+1

У меня проблема с аналогичной (такой же?). Можете ли вы пролить свет на свое третье обновление? Сообщалось об этом сотрудникам GH? – sbauch

+1

@Josh Это было сообщено много раз в GH, но напрасно. Они просто закрыли бы его как проблему с сервером. Некоторые люди сообщили об успехе, переключившись с mLab на S3, но есть и другие, которые сообщили о той же проблеме с S3. На данный момент синтаксический анализатор -heroku- mLab не передает потоковое аудио, видео-файлы - это то, что мы можем сделать. Если кто-то может это решить, мы должны помочь себе, разместив здесь решение. Я не думаю, что это будет решено персоналом Парса. – Tobio

ответ

-1

У меня есть локальный MongoDB с синтаксическим-сервером и это было нужно, чтобы заставить его работать:

Parse-server stream video to IOS from PFFile.url

Не знает, если это то же самое с не локальными базами данных, хотя.

+0

Если у вас есть НОВЫЙ вопрос, обратитесь к нему, нажав кнопку [Ask Question] (// stackoverflow.com/questions/ask). Если у вас есть достаточная репутация, [вы можете перенести] (// stackoverflow.com/privileges/vote-up) вопрос. Альтернативно, «звезда» это как фаворит, и вас будут уведомлять о любых новых ответах. –

1

этот код работает для меня, кажется, не

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

разбора сервер будет поддерживать потоковое в Safari/прошивкой и решение это включить его с помощью экспресс & GridStore следующим образом,

синтаксический-сервер пример \ node_modules \ разбор сервер \ 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.'); 
    }); 
} 
} 
} , ... 

разобрать-серверный пример \ node_modules \ разбора сервер \ Lib \ Контроллеры \ 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); 
} 
}, ... 

разбора сервера Пример \ node_modules \ разбора сервер \ Lib \ Переходники \ 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

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 Оригинальный ответ дается @Bragegs здесь - https://github.com/ParsePlatform/parse-server/issues/1440#issuecomment-212815625. Пользователь @ Stav1 также упомянул об этом в этой теме, но, к сожалению, он был заблокирован?

0

Для тех, кто приземляется здесь, глядя на новый пример Parse-Server, Parse-server теперь распознает потоковое вещание; однако для извлечения видео вы должны использовать метод parse iOS sdk. Ниже приведен код сервера, если вы развертываете собственный синтаксический анализатор. Я следую за списком некоторых методов потоковой передачи.

изменение Серверный код найден в:

синтаксическое-сервера, например \ node_modules \ разбора сервер \ 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.'); 
    }); 
    } 
}}, 

Пример использования метода для потоковой передачи с прошивкой синтаксического анализа (SDK быстрый):

vidObject.video.getDataStreamInBackground(block: <#T##PFDataStreamResultBlock?##PFDataStreamResultBlock?##(InputStream?, Error?) -> Void#>) 
Смежные вопросы