HTML5视频不会循环播放


73

我有一个视频作为网页的背景,并且我试图使其循环播放。这是代码:

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

即使我告诉视频循环播放,也不会。我还尝试使其与onended属性循环(根据此Mozilla支持线程,我也尝试了jQuery的那一部分)。到目前为止没有任何工作。Chrome或我的代码有问题吗?

编辑:

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

Chrome浏览器的检查器的“网络”标签显示,在我的应用程序中,视频被请求了3次。状态一次为“待定”,第二次为“取消”,最后一次为200 OK。工作副本仅显示两个请求,一个状态为待处理,另一个为206部分内容。但是,视频播放一次后,该请求将更改为“已取消”,并再次请求该视频。在我的应用程序中,这不会发生。

至于类型,在我的应用程序中,两个是“ undefined”,另一个是“ video / mp4”(应该是)。在工作的应用中,所有请求均为“ video / mp4”。

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

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

无论如何,来源在这里。您可以提供的任何见解都将受到赞赏。

Answers:


128

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

事实证明,只有在视频文件由理解部分内容请求的服务器提供服务的情况下,Chrome上的元素中的循环(或任何形式的查找)<video>才有效。也就是说,服务器需要接受包含“ Range”标头和206“ Partial Content”响应的请求。即使视频足够小以至于可以被chrome完全缓冲,并且不再进行服务器往返旅行时,甚至是这种情况:如果您的服务器第一次不符合chrome的Range请求,则视频将无法循环播放或搜索。

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


3
只是有同样的问题。我正在使用nginx,因此我必须清除nginx,使用nginx.org/en/docs/http/ngx_http_mp4_module.html从源代码安装并重新启动所有内容。
chriscauley 2012年

php内置服务器也会发生同样的情况(在我的开发环境中)。
Marcel Burkhard

3
Django 1.7.10运行服务器同样存在问题。
Lauri Elias

由于公司防火墙配置不正确,我遇到了同样的问题-范围请求被剥离,您将整个文件取回。Safari完全拒绝播放,Chrome播放一次。除了切换到HLS和一些支持该功能的后备JS播放器之外,别无他法。我可以通过curl -v -r0-1 ...
w00t

@Marcel Burkhard嘿,您能告诉我您用来解决此问题的PHP代码吗?我有同样的问题,对PHP也很陌生。
Ng2-Fun

18

最简单的解决方法:

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

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

这在Amazon S3上效果很好,在Amazon S3上您对服务器响应没有太多控制,并且还可以解决与Firefox有关的问题,即video.currentTime如果视频缺少其长度元数据,则无法设置。

没有jQuery的类似JavaScript:

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

您是否知道无jQuery的等效功能?
布赖恩·布朗顿

尽管视频在重新加载时会短暂闪烁,但效果很好。
引人注目

6

过去似乎是一个问题,上面至少有两个已关闭的错误,但是都声明已修复:

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解决它们/

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

@Ramesh你们也可以看看这个问题吗? stackoverflow.com/questions/31634678/... 具有视频数据做
committedandroider

3

我的情况:

我有完全相同的问题,但是仅更改响应消息的标头并没有做。没有循环,重播或搜寻。纯粹的停止也行不通,但这可能是我的配置。

回答:

根据某些站点(无法再找到它们)的说法,也有可能在视频结束之后,应该在下一个视频开始之前触发load()方法。这将重新加载源,从而导致视频/音频元素再次正常工作。

@约翰

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

希望对您有所帮助,我仍在寻找解决方案。


我实际上最终要做的是从另一个来源获得服务:在我使用MongoDB的GridFS之前。我认为问题出在不正确地提供文件。我现在正在使用Amazon S3,没有任何问题。
Ethan Turkeltaub

哦..我们也解决了它,但我无法真正解释。范围请求似乎不适用于该服务,因此我们将这些行添加到了下载文件的方法中。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
WhoKnows

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;
WhoKnows

如果这还不清楚,我很抱歉,但是也许有一天它将对某人有所帮助:)感谢您指出正确的方向!
WhoKnows

谢谢!我正在使用video.js并最终调用load使视频循环进入生产环境,而以前只在本地进行。我发现我可以检查currentTime ===的持续时间是否结束,以查看视频是否没有环回开始播放,在这种情况下,调用加载而不是播放。
funrob

3

以防万一以上答案都无法帮助您,请确保您没有在检查器中选中“禁用缓存”选项来运行。由于Chrome浏览器从缓存中抓取视频,因此它基本上只能运行一次。刚刚调试了20分钟,然后才意识到这是原因。仅供参考,所以我知道我不是唯一的其他人的铬臭虫报告


1

这是超级la脚,但保管箱使用正确的状态代码。因此,上传到保管箱并用dl替换www。

因此,使用保管箱网址可以正常播放视频。


0

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

例如,这是带有PHP laravel刀片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 Class是我从GitHub要点发现的流媒体类

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

-1

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

我正在加载mp4webm文件,并注意到该视频未在Chrome中循环播放。这是因为该webm文件是第一个source列出的webm文件,因此Chrome浏览器正在加载文件,而不是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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.