Source: transmuxer-worker.js

  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. import window from 'global/window';
  15. import mp4 from 'mux.js/lib/mp4';
  16. /**
  17. * Re-emits transmuxer events by converting them into messages to the
  18. * world outside the worker.
  19. *
  20. * @param {Object} transmuxer the transmuxer to wire events on
  21. * @private
  22. */
  23. const wireTransmuxerEvents = function(transmuxer) {
  24. transmuxer.on('data', function(segment) {
  25. // transfer ownership of the underlying ArrayBuffer
  26. // instead of doing a copy to save memory
  27. // ArrayBuffers are transferable but generic TypedArrays are not
  28. // @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)
  29. let initArray = segment.initSegment;
  30. segment.initSegment = {
  31. data: initArray.buffer,
  32. byteOffset: initArray.byteOffset,
  33. byteLength: initArray.byteLength
  34. };
  35. let typedArray = segment.data;
  36. segment.data = typedArray.buffer;
  37. window.postMessage({
  38. action: 'data',
  39. segment,
  40. byteOffset: typedArray.byteOffset,
  41. byteLength: typedArray.byteLength
  42. }, [segment.data]);
  43. });
  44. if (transmuxer.captionStream) {
  45. transmuxer.captionStream.on('data', function(caption) {
  46. window.postMessage({
  47. action: 'caption',
  48. data: caption
  49. });
  50. });
  51. }
  52. transmuxer.on('done', function(data) {
  53. window.postMessage({ action: 'done' });
  54. });
  55. transmuxer.on('gopInfo', function(gopInfo) {
  56. window.postMessage({
  57. action: 'gopInfo',
  58. gopInfo
  59. });
  60. });
  61. };
  62. /**
  63. * All incoming messages route through this hash. If no function exists
  64. * to handle an incoming message, then we ignore the message.
  65. *
  66. * @class MessageHandlers
  67. * @param {Object} options the options to initialize with
  68. */
  69. class MessageHandlers {
  70. constructor(options) {
  71. this.options = options || {};
  72. this.init();
  73. }
  74. /**
  75. * initialize our web worker and wire all the events.
  76. */
  77. init() {
  78. if (this.transmuxer) {
  79. this.transmuxer.dispose();
  80. }
  81. this.transmuxer = new mp4.Transmuxer(this.options);
  82. wireTransmuxerEvents(this.transmuxer);
  83. }
  84. /**
  85. * Adds data (a ts segment) to the start of the transmuxer pipeline for
  86. * processing.
  87. *
  88. * @param {ArrayBuffer} data data to push into the muxer
  89. */
  90. push(data) {
  91. // Cast array buffer to correct type for transmuxer
  92. let segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);
  93. this.transmuxer.push(segment);
  94. }
  95. /**
  96. * Recreate the transmuxer so that the next segment added via `push`
  97. * start with a fresh transmuxer.
  98. */
  99. reset() {
  100. this.init();
  101. }
  102. /**
  103. * Set the value that will be used as the `baseMediaDecodeTime` time for the
  104. * next segment pushed in. Subsequent segments will have their `baseMediaDecodeTime`
  105. * set relative to the first based on the PTS values.
  106. *
  107. * @param {Object} data used to set the timestamp offset in the muxer
  108. */
  109. setTimestampOffset(data) {
  110. let timestampOffset = data.timestampOffset || 0;
  111. this.transmuxer.setBaseMediaDecodeTime(Math.round(timestampOffset * 90000));
  112. }
  113. setAudioAppendStart(data) {
  114. this.transmuxer.setAudioAppendStart(Math.ceil(data.appendStart * 90000));
  115. }
  116. /**
  117. * Forces the pipeline to finish processing the last segment and emit it's
  118. * results.
  119. *
  120. * @param {Object} data event data, not really used
  121. */
  122. flush(data) {
  123. this.transmuxer.flush();
  124. }
  125. resetCaptions() {
  126. this.transmuxer.resetCaptions();
  127. }
  128. alignGopsWith(data) {
  129. this.transmuxer.alignGopsWith(data.gopsToAlignWith.slice());
  130. }
  131. }
  132. /**
  133. * Our web wroker interface so that things can talk to mux.js
  134. * that will be running in a web worker. the scope is passed to this by
  135. * webworkify.
  136. *
  137. * @param {Object} self the scope for the web worker
  138. */
  139. const TransmuxerWorker = function(self) {
  140. self.onmessage = function(event) {
  141. if (event.data.action === 'init' && event.data.options) {
  142. this.messageHandlers = new MessageHandlers(event.data.options);
  143. return;
  144. }
  145. if (!this.messageHandlers) {
  146. this.messageHandlers = new MessageHandlers();
  147. }
  148. if (event.data && event.data.action && event.data.action !== 'init') {
  149. if (this.messageHandlers[event.data.action]) {
  150. this.messageHandlers[event.data.action](event.data);
  151. }
  152. }
  153. };
  154. };
  155. export default (self) => {
  156. return new TransmuxerWorker(self);
  157. };