我可以通过WebSocket将WebM视频流式传输到视频元素吗?

时间:2015-02-04 23:15:24

标签: javascript html5 video websocket ffmpeg

我希望能够使用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。我在启用所有编解码器的情况下编译了它。

完整来源位于https://github.com/Ravenstine/simpleview

0 个答案:

没有答案