From 4d29e7bf3a1de850b8c3810610d16bd14698de0d Mon Sep 17 00:00:00 2001 From: Nick Date: Sat, 24 Oct 2015 12:28:39 -0700 Subject: [PATCH] Added a websocket livestream demo --- demo/libde265_websocket.html | 73 ++++++++++++ demo/livevideoserver.py | 60 ++++++++++ lib/libde265.js | 212 +++++++++++++++++++++++++++++++++++ post.js | 212 +++++++++++++++++++++++++++++++++++ 4 files changed, 557 insertions(+) create mode 100644 demo/libde265_websocket.html create mode 100644 demo/livevideoserver.py diff --git a/demo/libde265_websocket.html b/demo/libde265_websocket.html new file mode 100644 index 0000000..0778145 --- /dev/null +++ b/demo/libde265_websocket.html @@ -0,0 +1,73 @@ + + + + +libde265.js + + + +

libde265.js

+ Fork me on GitHub +
+
Simple HEVC/H.265 bitstream player in pure JavaScript.
+
Copyright © 2014 by struktur AG
+ +
+ + + + diff --git a/demo/livevideoserver.py b/demo/livevideoserver.py new file mode 100644 index 0000000..438bd26 --- /dev/null +++ b/demo/livevideoserver.py @@ -0,0 +1,60 @@ +import tornado.ioloop +import tornado.web +import tornado.websocket +import time + +def start(ws): + f = open("spreedmovie.hevc", "rb") + while True: + data = f.read(ws.chunk_size) + if not data: + print "Done!" + ws.send_message("flush") + break + ws.send_message(data) + time.sleep(1 / ws.fps) + +class VideoStreamWebSocket(tornado.websocket.WebSocketHandler): + def open(self): + print "WebSocket opened" + self.chunk_size = 0 + self.fps = 0.0 + + @tornado.web.asynchronous + def on_message(self, message): + cmd = message.split() + if len(cmd) > 0: + if cmd[0] == "start": + start(self) + if cmd[0] == "chunk_size": + self.chunk_size = int(cmd[1]) + if cmd[0] == "fps": + self.fps = float(cmd[1]) + + @tornado.web.asynchronous + def send_message(self, data): + self.write_message(data, binary=True) + + def on_close(self): + print "WebSocket closed" + +class MainHandler(tornado.web.RequestHandler): + def get(self): + import os + f = open("libde265_websocket.html") + self.write(f.read()) + self.finish() + +class Application(tornado.web.Application): + def __init__(self): + handlers = [ + (r"/", MainHandler), + (r"/websocket", VideoStreamWebSocket), + (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': '../lib'}), + ] + tornado.web.Application.__init__(self, handlers) + print "Waiting for WebSocket..." + +application = Application() +application.listen(8080) +tornado.ioloop.IOLoop.instance().start() diff --git a/lib/libde265.js b/lib/libde265.js index 481758c..61f3dbc 100644 --- a/lib/libde265.js +++ b/lib/libde265.js @@ -11393,10 +11393,222 @@ RawPlayer.prototype.disable_filters = function(disable) { this.filters = disable; }; +/** + * A simple raw stream bitstream player interface. + * + * @constructor + */ +var StreamPlayer = function(canvas) { + this.canvas = canvas; + this.ctx = canvas.getContext("2d"); + this.status_cb = null; + this.error_cb = null; + this.ratio = null; + this.filters = false; + this._reset(); +}; + +StreamPlayer.prototype._reset = function() { + this.start = null; + this.frames = 0; + this.image_data = null; + this.running = false; + this.pending_image_data = null; +}; + +/** @expose */ +StreamPlayer.prototype.set_status_callback = function(callback) { + this.status_cb = callback; +}; + +StreamPlayer.prototype._set_status = function() { + if (this.status_cb) { + this.status_cb.apply(this.status_cb, arguments); + } +}; + +/** @expose */ +StreamPlayer.prototype.set_error_callback = function(callback) { + this.error_cb = callback; +}; + +StreamPlayer.prototype._set_error = function(error, message) { + if (this.error_cb) { + this.error_cb(error, message); + } +}; + +StreamPlayer.prototype._display_image = function(image) { + if (!this.start) { + this.start = new Date(); + this._set_status("playing"); + } else { + this.frames += 1; + var duration = (new Date()) - this.start; + if (duration > 1000) { + this._set_status("fps", this.frames / (duration * 0.001)); + } + } + + var w = image.get_width(); + var h = image.get_height(); + if (w != this.canvas.width || h != this.canvas.height || !this.image_data) { + this.canvas.width = w; + this.canvas.height = h; + this.image_data = this.ctx.createImageData(w, h); + var image_data = this.image_data.data; + for (var i=0; i 1000) { + this._set_status("fps", this.frames / (duration * 0.001)); + } + } + + var w = image.get_width(); + var h = image.get_height(); + if (w != this.canvas.width || h != this.canvas.height || !this.image_data) { + this.canvas.width = w; + this.canvas.height = h; + this.image_data = this.ctx.createImageData(w, h); + var image_data = this.image_data.data; + for (var i=0; i