我希望能够使用FFmpeg捕获我的桌面,并通过WebSocket将视频发送到可以在HTML5视频标签中播放视频流的客户端。目前实现这一目标的方法似乎是发送JPG数据并将其放在canvas元素上。在诉诸于此之前,我宁愿传输实际的视频和音频数据。
以下是我的服务器代码。请注意,我在Linux上运行Ruby 2.2.0(Debian Stable)。
require 'bundler'
Bundler.require
EM.run do
EM::WebSocket.run host: "0.0.0.0", port: 9393 do |ws|
cmd = "ffmpeg -y -f x11grab -s 1600x900 -r 15 -i :0.0 -tune fastdecode -b:v 150k -threads 4 -f webm -"
@handler = EM.popen3(cmd, stdout: Proc.new { |data|
puts(data)
ws.send(Base64.encode64(data))
}, stderr: Proc.new{|err|})
@handler.callback do
puts "hey"
end
@handler.errback do |err_code|
puts err_code
end
ws.onopen do |handshake|
puts "WebSocket connection open"
end
ws.onclose do
puts "Connection closed"
# @handler.kill('TERM', true)
end
end
class SimpleView < Sinatra::Base
set :public_folder, './'
configure do
set :threaded, false
end
get '/' do
send_file
end
end
EM.run do
Rack::Server.start({
app: Rack::Builder.app{map('/'){ run SimpleView.new }},
server: 'thin',
Host: '0.0.0.0',
Port: '8181'
})
end
end
这是客户端代码(JavaScript):
var stream = new WebSocket('ws://localhost:9393')
var videoElement = document.querySelector("#desktop")
var videoSource = document.querySelector("source")
window.MediaSource = window.MediaSource || window.WebKitMediaSource;
var mediaSource = new MediaSource()
videoElement.src = window.URL.createObjectURL(mediaSource)
stream.onopen = function(){
console.log('connection open')
}
stream.onclose = function(){
console.log('connection closed')
}
mediaSource.addEventListener('sourceopen', function(e){
var sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8,vorbis"')
stream.onmessage = function(e){
var byteCharacters = atob(e.data)
var byteNumbers = new Array(byteCharacters.length)
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i)
}
var byteArray = new Uint8Array(byteNumbers)
sourceBuffer.appendStream(byteArray)
}
}, false)
我正在发生的事情是捕获FFmpeg的stdout,将每个数据块转换为base64,通过websocket发送,然后客户端尝试将base64块解码为源缓冲区可以理解并播放视频元素中的媒体资源。
虽然这并不让我感到惊讶,但这并不令我感到惊讶,我仍然会喜欢它,我希望也许只有一件小事我能做到。失踪。除了视频元素中的黑色外,我什么也得不到。
注意:我使用的是原始的FFmpeg,而不是Avconv。我在启用所有编解码器的情况下编译了它。