transmuxer-worker.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /**
  2. * @file transmuxer-worker.js
  3. */
  4. /**
  5. * videojs-contrib-media-sources
  6. *
  7. * Copyright (c) 2015 Brightcove
  8. * All rights reserved.
  9. *
  10. * Handles communication between the browser-world and the mux.js
  11. * transmuxer running inside of a WebWorker by exposing a simple
  12. * message-based interface to a Transmuxer object.
  13. */
  14. 'use strict';
  15. Object.defineProperty(exports, '__esModule', {
  16. value: true
  17. });
  18. var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
  19. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  20. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
  21. var _globalWindow = require('global/window');
  22. var _globalWindow2 = _interopRequireDefault(_globalWindow);
  23. var _muxJsLibMp4 = require('mux.js/lib/mp4');
  24. var _muxJsLibMp42 = _interopRequireDefault(_muxJsLibMp4);
  25. /**
  26. * Re-emits transmuxer events by converting them into messages to the
  27. * world outside the worker.
  28. *
  29. * @param {Object} transmuxer the transmuxer to wire events on
  30. * @private
  31. */
  32. var wireTransmuxerEvents = function wireTransmuxerEvents(transmuxer) {
  33. transmuxer.on('data', function (segment) {
  34. // transfer ownership of the underlying ArrayBuffer
  35. // instead of doing a copy to save memory
  36. // ArrayBuffers are transferable but generic TypedArrays are not
  37. // @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)
  38. var initArray = segment.initSegment;
  39. segment.initSegment = {
  40. data: initArray.buffer,
  41. byteOffset: initArray.byteOffset,
  42. byteLength: initArray.byteLength
  43. };
  44. var typedArray = segment.data;
  45. segment.data = typedArray.buffer;
  46. _globalWindow2['default'].postMessage({
  47. action: 'data',
  48. segment: segment,
  49. byteOffset: typedArray.byteOffset,
  50. byteLength: typedArray.byteLength
  51. }, [segment.data]);
  52. });
  53. if (transmuxer.captionStream) {
  54. transmuxer.captionStream.on('data', function (caption) {
  55. _globalWindow2['default'].postMessage({
  56. action: 'caption',
  57. data: caption
  58. });
  59. });
  60. }
  61. transmuxer.on('done', function (data) {
  62. _globalWindow2['default'].postMessage({ action: 'done' });
  63. });
  64. transmuxer.on('gopInfo', function (gopInfo) {
  65. _globalWindow2['default'].postMessage({
  66. action: 'gopInfo',
  67. gopInfo: gopInfo
  68. });
  69. });
  70. };
  71. /**
  72. * All incoming messages route through this hash. If no function exists
  73. * to handle an incoming message, then we ignore the message.
  74. *
  75. * @class MessageHandlers
  76. * @param {Object} options the options to initialize with
  77. */
  78. var MessageHandlers = (function () {
  79. function MessageHandlers(options) {
  80. _classCallCheck(this, MessageHandlers);
  81. this.options = options || {};
  82. this.init();
  83. }
  84. /**
  85. * Our web wroker interface so that things can talk to mux.js
  86. * that will be running in a web worker. the scope is passed to this by
  87. * webworkify.
  88. *
  89. * @param {Object} self the scope for the web worker
  90. */
  91. /**
  92. * initialize our web worker and wire all the events.
  93. */
  94. _createClass(MessageHandlers, [{
  95. key: 'init',
  96. value: function init() {
  97. if (this.transmuxer) {
  98. this.transmuxer.dispose();
  99. }
  100. this.transmuxer = new _muxJsLibMp42['default'].Transmuxer(this.options);
  101. wireTransmuxerEvents(this.transmuxer);
  102. }
  103. /**
  104. * Adds data (a ts segment) to the start of the transmuxer pipeline for
  105. * processing.
  106. *
  107. * @param {ArrayBuffer} data data to push into the muxer
  108. */
  109. }, {
  110. key: 'push',
  111. value: function push(data) {
  112. // Cast array buffer to correct type for transmuxer
  113. var segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);
  114. this.transmuxer.push(segment);
  115. }
  116. /**
  117. * Recreate the transmuxer so that the next segment added via `push`
  118. * start with a fresh transmuxer.
  119. */
  120. }, {
  121. key: 'reset',
  122. value: function reset() {
  123. this.init();
  124. }
  125. /**
  126. * Set the value that will be used as the `baseMediaDecodeTime` time for the
  127. * next segment pushed in. Subsequent segments will have their `baseMediaDecodeTime`
  128. * set relative to the first based on the PTS values.
  129. *
  130. * @param {Object} data used to set the timestamp offset in the muxer
  131. */
  132. }, {
  133. key: 'setTimestampOffset',
  134. value: function setTimestampOffset(data) {
  135. var timestampOffset = data.timestampOffset || 0;
  136. this.transmuxer.setBaseMediaDecodeTime(Math.round(timestampOffset * 90000));
  137. }
  138. }, {
  139. key: 'setAudioAppendStart',
  140. value: function setAudioAppendStart(data) {
  141. this.transmuxer.setAudioAppendStart(Math.ceil(data.appendStart * 90000));
  142. }
  143. /**
  144. * Forces the pipeline to finish processing the last segment and emit it's
  145. * results.
  146. *
  147. * @param {Object} data event data, not really used
  148. */
  149. }, {
  150. key: 'flush',
  151. value: function flush(data) {
  152. this.transmuxer.flush();
  153. }
  154. }, {
  155. key: 'resetCaptions',
  156. value: function resetCaptions() {
  157. this.transmuxer.resetCaptions();
  158. }
  159. }, {
  160. key: 'alignGopsWith',
  161. value: function alignGopsWith(data) {
  162. this.transmuxer.alignGopsWith(data.gopsToAlignWith.slice());
  163. }
  164. }]);
  165. return MessageHandlers;
  166. })();
  167. var TransmuxerWorker = function TransmuxerWorker(self) {
  168. self.onmessage = function (event) {
  169. if (event.data.action === 'init' && event.data.options) {
  170. this.messageHandlers = new MessageHandlers(event.data.options);
  171. return;
  172. }
  173. if (!this.messageHandlers) {
  174. this.messageHandlers = new MessageHandlers();
  175. }
  176. if (event.data && event.data.action && event.data.action !== 'init') {
  177. if (this.messageHandlers[event.data.action]) {
  178. this.messageHandlers[event.data.action](event.data);
  179. }
  180. }
  181. };
  182. };
  183. exports['default'] = function (self) {
  184. return new TransmuxerWorker(self);
  185. };
  186. module.exports = exports['default'];