Safari无法在Rails应用程序中加载HTML5视频

10

我有一个Rails应用程序,我正在尝试使用以下标记播放HTML5视频:

不起作用:

<video controls poster="http://lvh.me:3000/assets/videos/myvideo.png">
  <source src="http://lvh.me:3000/assets/images/videos/myvideo.mp4" type="video/mp4">
  <source src="http://lvh.me:3000/assets/images/videos/myvideo.webm" type="video/webm">
  <source src="http://lvh.me:3000/assets/images/videos/myvideo.ogv" type="video/ogg">
</video>

在Safari中,视频显示“正在加载...”但从未播放,尽管在Chrome和Firefox中按预期工作。一开始我以为可能是路径的问题,但我已经尝试了绝对路径、相对路径以及Rails的image_path 助手,但没有结果。

为了调试,我复制了这个示例HTML5视频标签,在Safari中按预期播放(唯一的区别是源视频):

正常工作:外部托管的示例视频

<video controls poster="http://easyhtml5video.com/assets/video/Penguins_of_Madagascar.jpg">
  <source src="http://easyhtml5video.com/assets/video/new/Penguins_of_Madagascar.mp4" type="video/mp4">
  <source src="http://easyhtml5video.com/assets/video/new/Penguins_of_Madagascar.webm" type="video/webm">
  <source src="http://easyhtml5video.com/assets/video/new/Penguins_of_Madagascar.ogv" type="video/ogg">
</video>

但是,当我使用完全相同的标记并在本地主机上托管同样的文件时,视频在Safari中停止工作:

无法工作:本地托管的示例视频

<video controls poster="http://lvh.me:3000/assets/videos/Penguins_of_Madagascar.jpg">
  <source src="http://lvh.me:3000/assets/videos/new/Penguins_of_Madagascar.mp4" type="video/mp4">
  <source src="http://lvh.me:3000/assets/videos/new/Penguins_of_Madagascar.webm" type="video/webm">
  <source src="http://lvh.me:3000/assets/videos/new/Penguins_of_Madagascar.ogv" type="video/ogg">
</video>

注:

  • 在Safari控制台或Rails日志中没有错误; 文件也没有404错误等。
  • 在Chrome和FF中,本地托管的视频可以正常工作,因此我知道路径是正确的。
  • 在Safari中,外部托管的视频可以正常工作。
  • 在Rails应用程序之外的Safari中,本地托管的视频可以正常工作-我创建了一个静态页面,并使用了上述所有示例,效果很好。

根据所有这些,似乎是Safari和Rails的某种组合阻止了视频的加载。


也许与内容类型有关,您可以尝试将以下代码添加到您的mime_types.rb文件中:Rack::Mime::MIME_TYPES.merge!( ".ogg" => "application/ogg", ".ogx" => "application/ogg", ".ogv" => "video/ogg", ".wemb" => "video/webm", ".mp4" => "video/mp4", ".m4v" => "video/mp4") - Chris
@Chris 我已经添加了这个并重新启动了Rails,但没有成功。根据curl的显示,我发现MIME类型已经正确,不需要进行更改。如果你从重要的地方获取了那个列表,请注意其中有一个错别字:".wemb"。在本地测试时,我将其更改为".webm"。 - Shepmaster
有趣的是,当我将应用程序部署到Heroku时,文件确实可以正确下载并开始播放。 - Shepmaster
@devanand 有趣的观点,但您能澄清一下您指的是哪个版本的Rails吗?我正在使用Rails 4.2.5.1,这是目前在RubyGems上托管的最新版本。 - Shepmaster
Safari是否支持通过带有端口号的URL加载?尝试为每个文件链接使用<source src="http://127.0.0.1/assets/videos/等等...并查看是否有所帮助(assets文件夹必须存在于本地主机服务器的根目录中)。 - VC.One
显示剩余5条评论
3个回答

5
我遇到了相同的问题,并发现这是在视频中前后移动所需的字节范围。
这里有一个中间件,可以添加对字节范围HTTP标头的支持: https://gist.github.com/fritzsche/2758045
# (c) Thomas Fritzsche
# This is prove-of-concept coding only
# iOS devices insist on support for byte-rage http header, that is not native
# supported by rack apps like dragonfly
# this rack middleware will evaluate the http header and provide byte range support.

# For a dragonfly Rails (3.2.3) app I have tested this will call like this.
# I reload Rack::Cache that case trouble when initialized by Rails.
# This small trick makes it working :-)
#-----------------------
#require 'dragonfly/rails/images'
#require "range"
#
#
#Rails.application.middleware.delete(Rack::Cache)
#Rails.application.middleware.insert 0, Rack::Cache, {
#  :verbose     => true,
#  :metastore   => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"), 
#  :entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
#}
#
#Rails.application.middleware.insert_before Rack::Cache, RangeFilter
#
# [...]
#-------------------


class RangeFilter
  def initialize(app)
    @app = app
  end

  def call(env)
    dup._call(env)
  end   

  def _call(env)
    @status, @headers, @response = @app.call(env)    
    range = env["HTTP_RANGE"]
    if @status == 200 and range and /\Abytes=(\d*)-(\d*)\z/ =~ range
      @first_byte, @last_byte = $1, $2


      @data = "".encode("BINARY")
      @response.each do |s|
        @data << s
      end             
      @length = @data.bytesize if @length.nil? 
      if @last_byte.empty?
        @last_byte = @length - 1
      else
        @last_byte = @last_byte.to_i
      end
      if @first_byte.empty?
        @first_byte = @length - @last_byte
        @last_byte = @length - 1
      else
        @first_byte = @first_byte.to_i
      end    
      @range_length = @last_byte - @first_byte + 1
      @headers["Content-Range"] = "bytes #{@first_byte}-#{@last_byte}/#{@length}"
      @headers["Content-Length"] = @range_length.to_s
      [@status, @headers, self]
    else     
      [@status, @headers, @response]
    end  
  end

  def each(&block)
    block.call(@data[@first_byte..@last_byte])
    @response.close if @response.respond_to?(:close)
  end   

end

如需进一步了解,请查看Rails媒体文件流通过send_data或send_file方法接受字节范围请求这篇Ruby论坛帖子


谢谢。我适应了这个要点,它运行得很好。正如提到的那样,这可能不是一个好的生产设置,如果是这种情况,我会使用类似于 X-Sendfile 的东西。然而,在开发过程中,它确实允许在Safari中工作,这正是我所需要的! - Shepmaster

1
我知道这个问题已经超过5年了,但我遇到了同样的问题并解决了它,所以我会在这里发布我的解决方案。
当您将视频文件放入资产文件夹中时,它们以特殊方式提供服务。然后,不提供字节范围请求。这意味着Safari无法播放视频,因为它需要字节范围请求才能跳转到视频中不同的位置并以不同的速度播放。
如果您将视频放入public文件夹并从那里提供服务,则是中间件提供服务,在这种情况下提供范围请求。(Rails 5)
因此,所有必需的就是将您的视频移动到public。至少对我来说是这样解决的...

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接