Player.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. usage:
  3. p = new Player({
  4. useWorker: <bool>,
  5. workerFile: <defaults to "Decoder.js"> // give path to Decoder.js
  6. webgl: true | false | "auto" // defaults to "auto"
  7. });
  8. // canvas property represents the canvas node
  9. // put it somewhere in the dom
  10. p.canvas;
  11. p.webgl; // contains the used rendering mode. if you pass auto to webgl you can see what auto detection resulted in
  12. p.decode(<binary>);
  13. */
  14. // 通用模块定义
  15. (function (root, factory) {
  16. if (typeof define === 'function' && define.amd) {
  17. define(["./Decoder", "./YUVCanvas"], factory);
  18. } else if (typeof exports === 'object') {
  19. module.exports = factory(require("./Decoder"), require("./YUVCanvas"));
  20. } else {
  21. // 浏览器全局(根是窗口)
  22. root.Player = factory(root.Decoder, root.YUVCanvas);
  23. }
  24. }(this, function (Decoder, WebGLCanvas) {
  25. "use strict";
  26. var nowValue = Decoder.nowValue;
  27. var Player = function(parOptions){
  28. console.log(1111111)
  29. var self = this;
  30. this._config = parOptions || {};
  31. this.render = true;
  32. if (this._config.render === false){
  33. this.render = false;
  34. };
  35. this.nowValue = nowValue;
  36. this._config.workerFile = this._config.workerFile || "Decoder.js";
  37. if (this._config.preserveDrawingBuffer){
  38. this._config.contextOptions = this._config.contextOptions || {};
  39. this._config.contextOptions.preserveDrawingBuffer = true;
  40. };
  41. var webgl = "auto";
  42. if (this._config.webgl === true){
  43. webgl = true;
  44. }else if (this._config.webgl === false){
  45. webgl = false;
  46. };
  47. if (webgl == "auto"){
  48. webgl = true;
  49. try{
  50. if (!window.WebGLRenderingContext) {
  51. // 浏览器甚至不知道WebGLjs
  52. webgl = false;
  53. } else {
  54. var canvas = document.createElement('canvas');
  55. var ctx = canvas.getContext("webgl");
  56. if (!ctx) {
  57. // 浏览器支持WebGL,但初始化失败。
  58. webgl = false;
  59. };
  60. };
  61. }catch(e){
  62. webgl = false;
  63. };
  64. };
  65. this.webgl = webgl;
  66. // 选择函数
  67. if (this.webgl){
  68. this.createCanvasObj = this.createCanvasWebGL;
  69. this.renderFrame = this.renderFrameWebGL;
  70. }else{
  71. this.createCanvasObj = this.createCanvasRGB;
  72. this.renderFrame = this.renderFrameRGB;
  73. };
  74. var lastWidth;
  75. var lastHeight;
  76. var onPictureDecoded = function(buffer, width, height, infos) {
  77. self.onPictureDecoded(buffer, width, height, infos);
  78. var startTime = nowValue();
  79. if (!buffer || !self.render) {
  80. return;
  81. };
  82. self.renderFrame({
  83. canvasObj: self.canvasObj,
  84. data: buffer,
  85. width: width,
  86. height: height
  87. });
  88. if (self.onRenderFrameComplete){
  89. self.onRenderFrameComplete({
  90. data: buffer,
  91. width: width,
  92. height: height,
  93. infos: infos,
  94. canvasObj: self.canvasObj
  95. });
  96. };
  97. };
  98. // 提供大小
  99. if (!this._config.size){
  100. this._config.size = {};
  101. };
  102. this._config.size.width = this._config.size.width || 200;
  103. this._config.size.height = this._config.size.height || 200;
  104. if (this._config.useWorker){
  105. var worker = new Worker(this._config.workerFile);
  106. this.worker = worker;
  107. worker.addEventListener('message', function(e) {
  108. var data = e.data;
  109. if (data.consoleLog){
  110. console.log(data.consoleLog);
  111. return;
  112. };
  113. onPictureDecoded.call(self, new Uint8Array(data.buf, 0, data.length), data.width, data.height, data.infos);
  114. }, false);
  115. worker.postMessage({type: "Broadway.js - Worker init", options: {
  116. rgb: !webgl,
  117. memsize: this.memsize,
  118. reuseMemory: this._config.reuseMemory ? true : false
  119. }});
  120. if (this._config.transferMemory){
  121. this.decode = function(parData, parInfo){
  122. worker.postMessage({buf: parData.buffer, offset: parData.byteOffset, length: parData.length, info: parInfo}, [parData.buffer]); // Send data to our worker.
  123. };
  124. }else{
  125. this.decode = function(parData, parInfo){
  126. var copyU8 = new Uint8Array(parData.length);
  127. copyU8.set( parData, 0, parData.length );
  128. worker.postMessage({buf: copyU8.buffer, offset: 0, length: parData.length, info: parInfo}, [copyU8.buffer]); // Send data to our worker.
  129. };
  130. };
  131. if (this._config.reuseMemory){
  132. this.recycleMemory = function(parArray){
  133. //this.beforeRecycle();
  134. worker.postMessage({reuse: parArray.buffer}, [parArray.buffer]); // Send data to our worker.
  135. //this.afterRecycle();
  136. };
  137. }
  138. }else{
  139. this.decoder = new Decoder({
  140. rgb: !webgl
  141. });
  142. this.decoder.onPictureDecoded = onPictureDecoded;
  143. this.decode = function(parData, parInfo){
  144. self.decoder.decode(parData, parInfo);
  145. };
  146. };
  147. if (this.render){
  148. this.canvasObj = this.createCanvasObj({
  149. contextOptions: this._config.contextOptions
  150. });
  151. this.canvas = this.canvasObj.canvas;
  152. };
  153. this.domNode = this.canvas;
  154. lastWidth = this._config.size.width;
  155. lastHeight = this._config.size.height;
  156. };
  157. Player.prototype = {
  158. onPictureDecoded: function(buffer, width, height, infos){},
  159. // call when memory of decoded frames is not used anymore
  160. recycleMemory: function(buf){
  161. },
  162. /*beforeRecycle: function(){},
  163. afterRecycle: function(){},*/
  164. // for both functions options is:
  165. //
  166. // width
  167. // height
  168. // enableScreenshot
  169. //
  170. // returns a object that has a property canvas which is a html5 canvas
  171. createCanvasWebGL: function(options){
  172. var canvasObj = this._createBasicCanvasObj(options);
  173. canvasObj.contextOptions = options.contextOptions;
  174. return canvasObj;
  175. },
  176. createCanvasRGB: function(options){
  177. var canvasObj = this._createBasicCanvasObj(options);
  178. return canvasObj;
  179. },
  180. // part that is the same for webGL and RGB
  181. _createBasicCanvasObj: function(options){
  182. options = options || {};
  183. var obj = {};
  184. var width = options.width;
  185. if (!width){
  186. width = this._config.size.width;
  187. };
  188. var height = options.height;
  189. if (!height){
  190. height = this._config.size.height;
  191. };
  192. obj.canvas = document.createElement('canvas');
  193. obj.canvas.width = width;
  194. obj.canvas.height = height;
  195. obj.canvas.style.backgroundColor = "#0D0E1B";
  196. return obj;
  197. },
  198. // options:
  199. //
  200. // canvas
  201. // data
  202. renderFrameWebGL: function(options){
  203. var canvasObj = options.canvasObj;
  204. var width = options.width || canvasObj.canvas.width;
  205. var height = options.height || canvasObj.canvas.height;
  206. if (canvasObj.canvas.width !== width || canvasObj.canvas.height !== height || !canvasObj.webGLCanvas){
  207. canvasObj.canvas.width = width;
  208. canvasObj.canvas.height = height;
  209. canvasObj.webGLCanvas = new WebGLCanvas({
  210. canvas: canvasObj.canvas,
  211. contextOptions: canvasObj.contextOptions,
  212. width: width,
  213. height: height
  214. });
  215. };
  216. var ylen = width * height;
  217. var uvlen = (width / 2) * (height / 2);
  218. canvasObj.webGLCanvas.drawNextOutputPicture({
  219. yData: options.data.subarray(0, ylen),
  220. uData: options.data.subarray(ylen, ylen + uvlen),
  221. vData: options.data.subarray(ylen + uvlen, ylen + uvlen + uvlen)
  222. });
  223. var self = this;
  224. self.recycleMemory(options.data);
  225. },
  226. renderFrameRGB: function(options){
  227. var canvasObj = options.canvasObj;
  228. var width = options.width || canvasObj.canvas.width;
  229. var height = options.height || canvasObj.canvas.height;
  230. if (canvasObj.canvas.width !== width || canvasObj.canvas.height !== height){
  231. canvasObj.canvas.width = width;
  232. canvasObj.canvas.height = height;
  233. };
  234. var ctx = canvasObj.ctx;
  235. var imgData = canvasObj.imgData;
  236. if (!ctx){
  237. canvasObj.ctx = canvasObj.canvas.getContext('2d');
  238. ctx = canvasObj.ctx;
  239. canvasObj.imgData = ctx.createImageData(width, height);
  240. imgData = canvasObj.imgData;
  241. };
  242. imgData.data.set(options.data);
  243. ctx.putImageData(imgData, 0, 0);
  244. var self = this;
  245. self.recycleMemory(options.data);
  246. }
  247. };
  248. return Player;
  249. }));