我想用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变量的赋值。我对铁路很陌生,也许我走错了路。任何帮助,以指出我在正确的方向是感激的,因为大多数资源,我可以找到只为websockets。
我也注意到这篇文章:Lightweight streaming HTTP proxy for Rack (Ruby CPU-light HTTP client library)这为我指明了一个很好的方向,对我来说是很多需要吸收和学习的信息。sendfile gem看起来像是最终的解决方案,但我不知道如何劫持套接字并使应用程序控制器将原始数据流传输到客户端。
更新一:
- 我发现了一个解决方案,
ActionController::Live
,“工作”,但它读取所有块的远程文件第一,所以有一个长的客户端等待,如果文件是大的。根据docs,它能够在写入数据时将数据流传输到客户端,但它在写入之前首先读取所有数据。我从我的调试输出中看到,每1000个块,它在客户端获得任何数据之前就填满了。我怎么能为客户服务传递块作为进来?
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
1条答案
按热度按时间t0ybt7op1#
您面临的问题是,您试图在Rails应用程序控制器的操作中使用
rack.hijack
头。但是,rack.hijack头文件仅在config.ru
文件中受支持。要在Rails应用程序中提供原始视频流,可以使用
sendfile
gem。sendfile
gem允许您直接将文件发送到客户端,而无需先将其读入内存。这是提供大文件(如视频流)的理想选择。要使用sendfile gem,您需要将其添加到
Gemfile
:然后,您可以在Rails应用程序控制器中使用
send_file
方法将视频流发送到客户端:send_file方法有两个参数:要发送的文件的路径和文件的内容类型。在这种情况下,文件位于
/path/to/video.mp4
,内容类型为video/mp4
。您还可以使用
sendfile
gem从远程位置提供原始视频流。为此,您需要首先使用Net::HTTP
库将视频流下载到Rails应用程序中。然后,您可以使用send_file
方法将视频流发送到客户端。以下是如何从远程位置提供原始视频流的示例:
这段代码首先将视频流从远程位置下载到一个名为response的变量中。然后,它使用
send_file
方法将视频流发送到客户端。我希望它有帮助!