Rails send_file don't play mp4

匿名 (未验证) 提交于 2019-12-03 03:10:03

问题:

I have a Rails app that protects the uploaded videos putting them into a private folder.

Now I need to play these videos, and when I do something like this in the controller:

  def show     video = Video.find(params[:id])     send_file(video.full_path, type: "video/mp4", disposition: "inline")   end

And open the browser(Chrome or FF) at /videos/:id it doesn't play the video.

If I put the same video at the public folder, and access it like /video.mp4 it will play.

If I remove the dispositon: "inline" it will download the video and I can play it from my computer. Samething happens with webm videos.

What am I missing? Is this something possible to do?

回答1:

To stream videos, we have to handle the requested byte range for some browsers.

Solution 1: Use the send_file_with_range gem

The easy way would be to have the send_file method patched by the send_file_with_range gem.

Include the gem in the Gemfile

# Gemfile gem 'send_file_with_range'

and provide the range: true option for send_file:

def show   video = Video.find(params[:id])   send_file video.full_path, type: "video/mp4",      disposition: "inline", range: true end

The patch is quite short and worth a look. But, unfortunately, it did not work for me with Rails 4.2.

Solution 2: Patch send_file manually

Inspired by the gem, extending the controller manually is fairly easy:

class VideosController < ApplicationController    def show     video = Video.find(params[:id])     send_file video.full_path, type: "video/mp4",       disposition: "inline", range: true   end  private    def send_file(path, options = {})     if options[:range]       send_file_with_range(path, options)     else       super(path, options)     end   end    def send_file_with_range(path, options = {})     if File.exist?(path)       size = File.size(path)       if !request.headers["Range"]         status_code = 200 # 200 OK         offset = 0         length = File.size(path)       else         status_code = 206 # 206 Partial Content         bytes = Rack::Utils.byte_ranges(request.headers, size)[0]         offset = bytes.begin         length = bytes.end - bytes.begin       end       response.header["Accept-Ranges"] = "bytes"       response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes        send_data IO.binread(path, length, offset), options     else       raise ActionController::MissingFile, "Cannot read file #{path}."     end   end  end

Further reading

Because, at first, I did not know the difference between stream: true and range: true, I found this railscast helpful:

http://railscasts.com/episodes/266-http-streaming



转载请标明出处:Rails send_file don't play mp4
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!