我想通过 Rails 应用程序提供原始视频流。我知道最好的方法是劫持套接字并直接发送我的视频流(来自远程位置)。 所以基本上是一个视频反向代理。 我也希望在我的应用程序中使用它,以便能够应用逻辑。否则我只会使用 nginx。 我正在使用
puma
。
我可以通过
config.ru
做到这一点,但我希望它位于应用程序控制器内部,以便能够使用更多逻辑并使对远程的调用更加动态。
我的config.ru:
map '/video' do
io_lambda = lambda do |io|
uri = URI("http://10.0.0.20/myvideo.ts")
Net::HTTP.start(uri.host, uri.port) do |http|
request = Net::HTTP::Get.new uri
http.request request do |response|
response.read_body do |chunk|
io.write chunk
end
end
end
end
app = lambda do |env|
response_headers = {}
response_headers['Transfer-Encoding'] = 'binary'
response_headers["Content-Type"] = "video/mp2t"
response_headers["rack.hijack"] = io_lambda
[200, response_headers, nil]
end
run app
end
将相同的内容放入应用程序控制器的方法中不起作用,我得到一个空回复。我刚刚添加了
:head ok
来规避 TemplateError,并删除了 run app
行和 app 变量的赋值。
我对 Rails 很陌生,也许我的处理方式是错误的。任何帮助我指明正确方向的帮助都是值得赞赏的,因为我能找到的大多数资源仅适用于 websockets。
我还知道这篇文章:Rack 的轻量级流式 HTTP 代理(Ruby CPU-轻量级 HTTP 客户端库),它为我指明了一个好的方向,并且为我提供了很多需要吸收和学习的信息。 sendfile gem 似乎是最终的解决方案,但我不知道如何劫持套接字并使应用程序控制器仅将原始数据流式传输到客户端。
class SocketController < ApplicationController
include ActionController::Live
def test
i = 0
response.headers['Content-Type'] = 'video/mp4'
Net::HTTP.start(uri.host, uri.port) do |http|
request = Net::HTTP::Get.new uri
http.request request do |remote_response|
remote_response.read_body do |chunk|
i += 1
puts i if i % 1000 == 0
response.stream.write chunk
end
end
end
ensure
response.stream.close
end
end
标头。但是,rack.hijack 标头仅在
rack.hijack
文件中受支持。要使用 Rails 应用程序提供原始视频流,您可以使用 config.ru
gem。
sendfile
gem 允许您直接将文件发送到客户端,而无需先将其读入内存。这非常适合提供大文件(例如视频流)。要使用 sendfile gem,您需要将其添加到您的 sendfile
:
Gemfile
然后,您可以使用 Rails 应用程序控制器中的
gem 'sendfile'
方法将视频流发送到客户端:
send_file
send_file 方法有两个参数:要发送的文件的路径和文件的内容类型。在本例中,文件位于
def stream_video
send_file '/path/to/video.mp4', type: 'video/mp4'
end
,内容类型为
/path/to/video.mp4
。您还可以使用 video/mp4
gem 从远程位置提供原始视频流。为此,您需要首先使用
sendfile
库将视频流下载到您的 Rails 应用程序。然后,您可以使用Net::HTTP
方法将视频流发送到客户端。以下是如何从远程位置提供原始视频流的示例:
send_file
此代码首先将视频流从远程位置下载到名为“response”的变量中。然后,它使用
def stream_video
uri = URI('http://example.com/video.mp4')
response = Net::HTTP.get(uri)
send_file response.body, type: 'video/mp4'
end
方法将视频流发送到客户端。
希望对你有帮助!