【问题标题】:HTML5 video will not loopHTML5 视频不会循环播放
【发布时间】:2011-12-26 15:57:44
【问题描述】:

我有一个视频作为网页的背景,我正试图让它循环播放。代码如下:

<video autoplay='true' loop='true' muted='true'>
  <source src='/admin/wallpapers/linked/4ebc66e899727777b400003c' type='video/mp4'></source>
</video>

即使我已经让视频循环播放,但它没有。我还尝试使用onended 属性使其循环(根据this Mozilla support thread,我也尝试了那一点jQuery)。到目前为止没有任何效果。是 Chrome 的问题,还是我的代码的问题?

编辑:

我检查了工作副本 (http://fhsclock-labs.heroku.com/no-violence) 的网络事件和 HEAD 与我正在尝试运行的应用程序。不同之处在于,工作副本是从 Heroku 上的静态资产提供视频(显然是通过 Varnish),而我的工作副本是从 GridFS (MongoDB) 提供的。

Chrome 检查器的网络选项卡显示,在我的应用程序中,视频被请求了 3 次。一次Status是“pending”,第二次是“canceled”,最后一次是200 OK。工作副本只显示了两个请求,一个是 Status is pending,另一个是 206 Partial Content。但是,在视频播放一次后,该请求更改为“已取消”,并对该视频发出另一个请求。在我的应用程序中,这不会发生。

至于类型,在我的应用程序中,两个是“未定义”,另一个是“视频/mp4”(它应该是)。在工作应用中,所有请求都是“video/mp4”。

此外,我在控制台中收到Resource interpreted as Other but transferred with MIME type undefined. 警告。

我不太确定从哪里开始。我认为问题出在服务器端,因为将文件作为静态资产提供工作正常。可能是服务器未发送正确的内容类型。这可能是 GridFS 的问题。我不知道。

无论如何,来源是here。感谢您提供任何见解。

【问题讨论】:

    标签: google-chrome mime-types html5-video rack gridfs


    【解决方案1】:

    啊,我只是偶然发现了这个确切的问题。

    事实证明,只有在视频文件由能够理解 部分内容请求。即服务器需要接受包含“范围”标头和 206“部分内容”响应的请求。如果视频足够小以被 chrome 完全缓冲,并且不再进行服务器往返行程,情况也是如此:如果您的服务器第一次没有接受 chrome 的 Range 请求,则视频将不可循环或不可搜索.

    是的,GridFS 存在问题,尽管可以说 Chrome 应该更宽容。

    【讨论】:

    • 刚刚遇到了同样的问题。我正在使用 nginx,所以我必须清除 nginx,使用 nginx.org/en/docs/http/ngx_http_mp4_module.html 从源代码安装并重新启动一切。
    • php 内置服务器(在我的开发环境中)也是如此。
    • 与 Django 1.7.10 runserver 有同样的问题。
    • 由于公司防火墙配置不当,我遇到了同样的问题 - 范围请求被剥离,您可以取回整个文件。 Safari 完全拒绝播放,Chrome 播放一次。除了可能切换到 HLS 和一些支持它的后备 JS 播放器之外,没有什么可以做的。我可以使用curl -v -r0-1 ... 进行故障排除
    • @Marcel Burkhard 嘿,你能告诉我你用来解决这个问题的 PHP 代码吗?我有同样的问题,而且对 PHP 很陌生。
    【解决方案2】:

    最简单的解决方法:

    $('video').on('ended', function () {
      this.load();
      this.play();
    });
    

    'ended' 事件在视频到达结尾时触发,video.load() 将视频重置到开头,video.play() 在加载后立即开始播放。

    这适用于 Amazon S3,您对服务器响应没有太多控制权,并且还解决了与 video.currentTime 相关的 Firefox 问题,如果视频缺少其长度元数据,则无法设置。

    没有 jQuery 的类似 javascript:

    document.getElementsByTagName('video')[0].onended = function () {
      this.load();
      this.play();
    };
    

    【讨论】:

    • 你知道没有 jQuery 的等价物吗?
    • 虽然视频在重新加载时会短暂闪烁,但效果很好。
    【解决方案3】:

    过去似乎是个问题,至少有两个已关闭的错误,但都表示已修复:

    http://code.google.com/p/chromium/issues/detail?id=39683

    http://code.google.com/p/chromium/issues/detail?id=18846

    由于 Chrome 和 Safari 都使用基于 webkit 的浏览器,您或许可以使用以下一些变通方法: http://blog.millermedeiros.com/2011/03/html5-video-issues-on-the-ipad-and-how-to-solve-them/

    function restartVideo(){
    vid.currentTime = 0.1; //setting to zero breaks iOS 3.2, the value won't update, values smaller than 0.1 was causing bug as well.
    vid.play();
    }
    
    //loop video
    vid.addEventListener('ended', restartVideo, false);
    

    【讨论】:

    【解决方案4】:

    万一上述答案对您没有帮助,请确保您没有在检查禁用缓存选项的情况下运行检查器。由于 Chrome 从缓存中抓取视频,它基本上会工作一次。在意识到这是原因之前仅调试了 20 分钟。供参考,所以我知道我不是唯一一个someone else's chromium bug report

    【讨论】:

      【解决方案5】:

      我的情况:

      我有完全相同的问题,但是单独更改响应消息的标题并没有做。没有循环、重播或搜索。纯粹的停止也不起作用,但这可能是我的配置。

      答案:

      根据某些网站(再也找不到它们),它也可以在视频结束后立即触发 load() 方法,并且在下一个应该开始之前。这应该重新加载源,导致再次工作的视频/音频元素。

      @john

      请注意,您的答案/链接是正常的错误,而不是针对这个问题。使用服务器/网络服务器是导致此问题的原因。而这些链接描述的错误是不同类型的。这也是为什么答案不起作用的原因。

      希望对你有帮助,我还在寻找解决方案。

      【讨论】:

      • 我实际上最终做的是从不同的来源提供服务:在我使用 MongoDB 的 GridFS 之前。我认为问题源于错误地提供文件。我现在使用 Amazon S3 没有问题。
      • 哦..我们也解决了,但我无法真正解释。似乎范围请求不适用于该服务,因此我们将这些行添加到下载文件的方法中。 response.Headers.Add("Accept-Ranges", "bytes"); response.Headers.Add("Content-Range", rangeValue.Replace("=", " ") + (resource.Value.Length - 1).ToString() + "/" + resource.Value.Length.ToString( )); response.StatusCode = HttpStatusCode.PartialContent;这启用了范围请求,并操纵标头让服务器等知道它的范围请求。代码 206 而不是 200。
      • response.Headers.Add("Accept-Ranges", "bytes"); response.Headers.Add("Content-Range", rangeValue.Replace("=", " ") + (resource.Value.Length - 1).ToString() + "/" + resource.Value.Length.ToString( )); response.StatusCode = HttpStatusCode.PartialContent;
      • 如果这有点不清楚,我很抱歉,但也许有一天它会对某人有所帮助 :) 感谢您为我指明正确的方向!
      • 谢谢!我正在使用 video.js 并最终调用 load 使视频在生产中循环播放,而以前它只能在本地播放。我发现我可以检查 currentTime === 持续时间是否结束,看看视频是否没有循环回到开始,在这种情况下调用加载而不是播放。
      【解决方案6】:

      我知道这与所提出的问题并不完全相关,但如果有人在遇到类似问题时遇到此问题,请确保您的资源正确有序。

      我正在加载一个 mp4 和一个 webm 文件,并注意到视频没有在 Chrome 中循环播放。这是因为webm 文件是第一个列出的source,所以Chrome 加载的是webm 文件而不是mp4

      希望能帮助遇到此问题的其他人。

      <video autoplay loop>
          <source src="/path-to-vid/video.mp4" type="video/mp4">
          <source src="/path-to-vid/video.webm" type="video/webm">
      </video>
      

      【讨论】:

        【解决方案7】:

        它超级蹩脚,但 Dropbox 使用正确的状态码。所以上传到 Dropbox 并用 dl 替换 www。

        因此使用 Dropbox url 视频可以正常播放。

        【讨论】:

          【解决方案8】:

          我遇到了同样的问题,并且通过流式传输内容不可避免地解决了问题。

          例如,这是请求流式路由的带有 PHP laravel Blade html 代码的代码:

          <video>
              <source src="{{route('getVideoStream',$videoId)}}" type="video/mp4"/>
          </video>
          

          在控制器中,我将流式传输视频并将其作为 laravel 流函数返回:

             public function getVideoStream($videoId){
          
                  $path = $pathOfVideo;
          
                  $headers = [
                      'Content-Type' => 'video/mp2t',
                      'Content-Length' => File::size($path),
                      'Content-Disposition' => 'attachment; filename="start.mp4"'
                  ];
          
                  $stream = new VideoStream($path);
          
                  return response()->stream(function () use ($stream) {
                      $stream->start();
                  });
              }
          

          VideoStream 类是我从 GitHub gist 找到的流媒体类:

          class VideoStream
          {
              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();
              }
          }
          

          【讨论】:

            【解决方案9】:

            对于 9 年后访问此页面的任何人,如果上述所有答案都不起作用:我也遇到了这个问题,我认为问题的根源是我的浏览器或服务器。

            我后来注意到互联网上其他使用循环视频的网站在循环视频方面没有问题。为了解决问题,我从其中一个站点下载了一个随机视频,然后我访问并上传到我自己的服务器上,很高兴地发现它可以正常工作,因此问题的根源似乎是我正在使用的视频。

            然后我用一个在线视频转换器网站修复了我的视频(不想特别公开任何内容,但谷歌快速研究的第一个确实有效),唉,这解决了问题。

            我不确定问题的真正原因是什么。我确实认为我的客户交给我的原始视频存在转换或压缩错误。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-04-18
              • 2012-06-28
              • 1970-01-01
              • 1970-01-01
              • 2011-04-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多