/* usage: p = new Player({ useWorker: , workerFile: // give path to Decoder.js webgl: true | false | "auto" // defaults to "auto" }); // canvas property represents the canvas node // put it somewhere in the dom p.canvas; p.webgl; // contains the used rendering mode. if you pass auto to webgl you can see what auto detection resulted in p.decode(); */ // universal module definition (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(["./Decoder", "./YUVCanvas"], factory); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(require("./Decoder"), require("./YUVCanvas")); } else { // Browser globals (root is window) root.Player = factory(root.Decoder, root.YUVCanvas); } }(this, function (Decoder, WebGLCanvas) { "use strict"; var nowValue = Decoder.nowValue; var Player = function(parOptions){ var self = this; this._config = parOptions || {}; this.render = true; if (this._config.render === false){ this.render = false; }; this.nowValue = nowValue; this._config.workerFile = this._config.workerFile || "Decoder.js"; if (this._config.preserveDrawingBuffer){ this._config.contextOptions = this._config.contextOptions || {}; this._config.contextOptions.preserveDrawingBuffer = true; }; var webgl = "auto"; if (this._config.webgl === true){ webgl = true; }else if (this._config.webgl === false){ webgl = false; }; if (webgl == "auto"){ webgl = true; try{ if (!window.WebGLRenderingContext) { // the browser doesn't even know what WebGL is webgl = false; } else { var canvas = document.createElement('canvas'); var ctx = canvas.getContext("webgl"); if (!ctx) { // browser supports WebGL but initialization failed. webgl = false; }; }; }catch(e){ webgl = false; }; }; this.webgl = webgl; // choose functions if (this.webgl){ this.createCanvasObj = this.createCanvasWebGL; this.renderFrame = this.renderFrameWebGL; }else{ this.createCanvasObj = this.createCanvasRGB; this.renderFrame = this.renderFrameRGB; }; var lastWidth; var lastHeight; var onPictureDecoded = function(buffer, width, height, infos) { self.onPictureDecoded(buffer, width, height, infos); var startTime = nowValue(); if (!buffer || !self.render) { return; }; self.renderFrame({ canvasObj: self.canvasObj, data: buffer, width: width, height: height }); if (self.onRenderFrameComplete){ self.onRenderFrameComplete({ data: buffer, width: width, height: height, infos: infos, canvasObj: self.canvasObj }); }; }; // provide size if (!this._config.size){ this._config.size = {}; }; this._config.size.width = this._config.size.width || 200; this._config.size.height = this._config.size.height || 200; if (this._config.useWorker){ var worker = new Worker(this._config.workerFile); this.worker = worker; worker.addEventListener('message', function(e) { var data = e.data; if (data.consoleLog){ console.log(data.consoleLog); return; }; onPictureDecoded.call(self, new Uint8Array(data.buf, 0, data.length), data.width, data.height, data.infos); }, false); worker.postMessage({type: "Broadway.js - Worker init", options: { rgb: !webgl, memsize: this.memsize, reuseMemory: this._config.reuseMemory ? true : false }}); if (this._config.transferMemory){ this.decode = function(parData, parInfo){ // no copy // instead we are transfering the ownership of the buffer // dangerous!!! worker.postMessage({buf: parData.buffer, offset: parData.byteOffset, length: parData.length, info: parInfo}, [parData.buffer]); // Send data to our worker. }; }else{ this.decode = function(parData, parInfo){ // Copy the sample so that we only do a structured clone of the // region of interest var copyU8 = new Uint8Array(parData.length); copyU8.set( parData, 0, parData.length ); worker.postMessage({buf: copyU8.buffer, offset: 0, length: parData.length, info: parInfo}, [copyU8.buffer]); // Send data to our worker. }; }; if (this._config.reuseMemory){ this.recycleMemory = function(parArray){ //this.beforeRecycle(); worker.postMessage({reuse: parArray.buffer}, [parArray.buffer]); // Send data to our worker. //this.afterRecycle(); }; } }else{ this.decoder = new Decoder({ rgb: !webgl }); this.decoder.onPictureDecoded = onPictureDecoded; this.decode = function(parData, parInfo){ self.decoder.decode(parData, parInfo); }; }; if (this.render){ this.canvasObj = this.createCanvasObj({ contextOptions: this._config.contextOptions }); this.canvas = this.canvasObj.canvas; }; this.domNode = this.canvas; lastWidth = this._config.size.width; lastHeight = this._config.size.height; }; Player.prototype = { onPictureDecoded: function(buffer, width, height, infos){}, // call when memory of decoded frames is not used anymore recycleMemory: function(buf){ }, /*beforeRecycle: function(){}, afterRecycle: function(){},*/ // for both functions options is: // // width // height // enableScreenshot // // returns a object that has a property canvas which is a html5 canvas createCanvasWebGL: function(options){ var canvasObj = this._createBasicCanvasObj(options); canvasObj.contextOptions = options.contextOptions; return canvasObj; }, createCanvasRGB: function(options){ var canvasObj = this._createBasicCanvasObj(options); return canvasObj; }, // part that is the same for webGL and RGB _createBasicCanvasObj: function(options){ options = options || {}; var obj = {}; var width = options.width; if (!width){ width = this._config.size.width; }; var height = options.height; if (!height){ height = this._config.size.height; }; obj.canvas = document.createElement('canvas'); obj.canvas.width = width; obj.canvas.height = height; obj.canvas.style.backgroundColor = "#0D0E1B"; return obj; }, // options: // // canvas // data renderFrameWebGL: function(options){ var canvasObj = options.canvasObj; var width = options.width || canvasObj.canvas.width; var height = options.height || canvasObj.canvas.height; if (canvasObj.canvas.width !== width || canvasObj.canvas.height !== height || !canvasObj.webGLCanvas){ canvasObj.canvas.width = width; canvasObj.canvas.height = height; canvasObj.webGLCanvas = new WebGLCanvas({ canvas: canvasObj.canvas, contextOptions: canvasObj.contextOptions, width: width, height: height }); }; var ylen = width * height; var uvlen = (width / 2) * (height / 2); canvasObj.webGLCanvas.drawNextOutputPicture({ yData: options.data.subarray(0, ylen), uData: options.data.subarray(ylen, ylen + uvlen), vData: options.data.subarray(ylen + uvlen, ylen + uvlen + uvlen) }); var self = this; self.recycleMemory(options.data); }, renderFrameRGB: function(options){ var canvasObj = options.canvasObj; var width = options.width || canvasObj.canvas.width; var height = options.height || canvasObj.canvas.height; if (canvasObj.canvas.width !== width || canvasObj.canvas.height !== height){ canvasObj.canvas.width = width; canvasObj.canvas.height = height; }; var ctx = canvasObj.ctx; var imgData = canvasObj.imgData; if (!ctx){ canvasObj.ctx = canvasObj.canvas.getContext('2d'); ctx = canvasObj.ctx; canvasObj.imgData = ctx.createImageData(width, height); imgData = canvasObj.imgData; }; imgData.data.set(options.data); ctx.putImageData(imgData, 0, 0); var self = this; self.recycleMemory(options.data); } }; return Player; }));