Playing Video - Server is not correctly configured - 12939

此生再无相见时 提交于 2019-12-08 04:19:57

问题


I have an ios app with laravel (lumen) on the server side. I am trying to play the videos in the server, on application.

I am using a Player that plays videos with a direct link (e.g vine video link), however when I save the same vine video on my local server, the application doesn't play the video. In fact, when I try the video with my api route, surprisingly it plays the video on Chrome! But on the application end, I receive error:

The server is not correctly configured - 12939

(Please note that if I copy the same mp4 file into the xCode project, add it on 'copy bundle resources', and try with fileWithPath, it works. So I believe it's definitely caused by the server, not vidoo file/codec. )

My route: $app->get('/player/{filename}', 'PlayerController@show');

Methods:

public function show ($filename)
{
  $this->playVideo($filename, 'recordings');
}

public function playVideo($filename, $showType)
{
    if (file_exists("../uploads/" . $showType . "/" . $filename)) {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $type = finfo_file($finfo, "../uploads/" . $showType . "/" . $filename);


        header("Content-Type: " . $type);
        readfile("../uploads/" . $showType . "/" . $filename);
    }
}

To recap my problem, the video is playing on Chrome but receiving '12939' - 'Server is not correctly configured' on the mobile app.

Edit:

I tried using this as mentioned in the Apple Documentations:

curl --range 0-99 http://myapi.dev/test.mp4 -o /dev/null

However the documentation says:

"If the tool reports that it downloaded 100 bytes, the media server correctly handled the byte-range request. If it downloads the entire file, you may need to update the media server."

I received 100% and it downloaded the whole file for me, so I believe this is my problem. But I am not sure how to overcome this issue? What am I doing wrong? What should I do?


回答1:


To wrap up, this solved my problem:

  • Placed this to VideoController:

    public function streamVideo() 
    {
      $video_path = 'somedirectory/somefile.mp4';
      $stream = new VideoStream($video_path);
      $stream->start(); 
    }
    
  • and then created a file in app > helpers > VideoStream.php:

     <?php
     {
         private $path = "";
         private $stream = "";
         private $buffer = 102400;
         private $start  = -1;
         private $end    = -1;
         private $size   = 0;
    
         function __construct($filePath) 
         {
             $this->path = $filePath;
         }
    
         /**
          *      * Open stream
          *           */
         private function open()
         {
             if (!($this->stream = fopen($this->path, 'rb'))) {
                 die('Could not open stream for reading');
             }
    
         }
    
         /**
          *      * Set proper header to serve the video content
          *           */
         private function setHeader()
         {
             ob_get_clean();
             header("Content-Type: video/mp4");
             header("Cache-Control: max-age=2592000, public");
             header("Expires: ".gmdate('D, d M Y H:i:s', time()+2592000) . ' GMT');
             header("Last-Modified: ".gmdate('D, d M Y H:i:s', @filemtime($this->path)) . ' GMT' );
             $this->start = 0;
             $this->size  = filesize($this->path);
             $this->end   = $this->size - 1;
             header("Accept-Ranges: 0-".$this->end);
    
             if (isset($_SERVER['HTTP_RANGE'])) {
    
                 $c_start = $this->start;
                 $c_end = $this->end;
    
                 list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
                 if (strpos($range, ',') !== false) {
                     header('HTTP/1.1 416 Requested Range Not Satisfiable');
                     header("Content-Range: bytes $this->start-$this->end/$this->size");
                     exit;
                 }
                 if ($range == '-') {
                     $c_start = $this->size - substr($range, 1);
                 }else{
                     $range = explode('-', $range);
                     $c_start = $range[0];
    
                     $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
                 }
                 $c_end = ($c_end > $this->end) ? $this->end : $c_end;
                 if ($c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size) {
                     header('HTTP/1.1 416 Requested Range Not Satisfiable');
                     header("Content-Range: bytes $this->start-$this->end/$this->size");
                     exit;
                 }
                 $this->start = $c_start;
                 $this->end = $c_end;
                 $length = $this->end - $this->start + 1;
                 fseek($this->stream, $this->start);
                 header('HTTP/1.1 206 Partial Content');
                 header("Content-Length: ".$length);
                 header("Content-Range: bytes $this->start-$this->end/".$this->size);
             }
             else
             {
                 header("Content-Length: ".$this->size);
             }  
    
         }
    
         /**
          *      * close curretly opened stream
          *           */
         private function end()
         {
             fclose($this->stream);
             exit;
         }
    
         /**
          *      * perform the streaming of calculated range
          *           */
         private function stream()
         {
             $i = $this->start;
             set_time_limit(0);
             while(!feof($this->stream) && $i <= $this->end) {
                 $bytesToRead = $this->buffer;
                 if(($i+$bytesToRead) > $this->end) {
                     $bytesToRead = $this->end - $i + 1;
                 }
                 $data = fread($this->stream, $bytesToRead);
                 echo $data;
                 flush();
                 $i += $bytesToRead;
             }
         }
    
         /**
          *      * Start streaming video content
          *           */
         function start()
         {
             $this->open();
             $this->setHeader();
             $this->stream();
             $this->end();
         }
     }
    

Source: http://laravel.io/forum/10-06-2014-streaming-video-files-with-laravel




回答2:


I ran into a problem similar to this one, but your case is going to take a bit more configuration.

The headers for iOS need to be set appropriately using range requests, and the only way I was able to do that for all browsers was by reworking this gist to what I needed.

In my case, I did something like this in Laravel:

//Video controller
...
public function showVideo($id){
    $video = Video::find($id);
    return $this->videoService->stream($video);
}

//Video Service
namespace App\Services\VideoService;
use Illuminate\Routing\ResponseFactory as Response;
use App\Models\Video;
class VideoService implements VideoServiceInterface
{
    protected $response;
    protected $video;
    private $stream = "";
    private $buffer = 102400;
    private $start  = -1;
    private $end    = -1;
    private $size   = 0;
    public function __construct(Response $response){
        $this->response = $response;
    }
    public function stream(Video $video){
        $this->video = $video;
        return $this->response->stream(function(){
            $this->start();
        });
    }
    //Implement the rest of the gist here, renaming where appropriate....
}

Problem is, you're using Lumen which does not support a stream method on the response factory. What you'll need to do is rework the code I gave you to include Symfony's StreamedResponse Object.

If you look at how Laravel does it, you can probably do something like this:

//Video Service
namespace App\Services\VideoService;
use Symfony\Component\HttpFoundation\StreamedResponse as Response;
use App\Models\Video;
class VideoService implements VideoServiceInterface
{
    protected $video;
    private $stream = "";
    private $buffer = 102400;
    private $start  = -1;
    private $end    = -1;
    private $size   = 0;

    public function stream(Video $video){
        $this->video = $video;
        return new Response(function(){
            $this->start();
        });
    }
    //Implement the rest of the gist here, renaming where appropriate....
}

This isn't exact, and it won't work for you out of the box. But this should give you all of the components you need to register your own Service Provider and apply this appropriately to your own use-case.

Good luck.



来源:https://stackoverflow.com/questions/34386634/playing-video-server-is-not-correctly-configured-12939

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!