I have a Rails app I'm trying to play an HTML5 video from using the following markup:
Doesn't work:
<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>
On Safari, the video says "Loading..." but never plays, although it works as expected in Chrome and Firefox. I thought it may have been the path at first, but I've tried absolute paths, relative paths, and the Rails image_path
helper with no results.
To debug, I copied this example HTML5 video tag and it plays in Safari as expected (the only difference here is the source video):
Works: externally hosted sample video
<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>
However, when I take this exact same markup and host these same files locally, the video stops working in Safari:
Doesn't work: locally hosted sample video
<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>
Notes:
- I'm not getting errors in the Safari console or Rails log; no 404s on the files or anything.
- Locally hosted videos work in Chrome and FF, so I know the paths are correct.
- Externally hosted videos work fine in Safari.
- Locally hosted videos work in Safari outside of the Rails app—I created a static page and used all the examples above to good effect.
Based on all of this, it seems like some combination of Safari and Rails that's preventing the videos from loading.
I had the same problem and figured out it's the byte-range you need for moving back and forward in video.
Here's some middleware that adds support for the byte-range HTTP header:
# (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
For further reference, check out rails media file stream accept byte range request through send_data or send_file method or this Ruby Forum post.
Reference link: https://superuser.com/questions/870133/html5-video-tag-not-supported-in-safari-5-1-on-windows-7
As video_tag in rails use HTML5 'video' tag property internally and safari doesn't support HTML5 video tag property.
In order to get HTML5 videos to play through Safari on Windows, you
need to install Quicktime.
I did this and the videos would still not work.
But, once I restarted my machine, everything worked as it was supposed
to!