Home Reference Source

src/demux/demuxer-inline.js

  1. /**
  2. *
  3. * inline demuxer: probe fragments and instantiate
  4. * appropriate demuxer depending on content type (TSDemuxer, AACDemuxer, ...)
  5. *
  6. */
  7.  
  8. import Event from '../events';
  9. import { ErrorTypes, ErrorDetails } from '../errors';
  10. import Decrypter from '../crypt/decrypter';
  11. import AACDemuxer from '../demux/aacdemuxer';
  12. import MP4Demuxer from '../demux/mp4demuxer';
  13. import TSDemuxer from '../demux/tsdemuxer';
  14. import MP3Demuxer from '../demux/mp3demuxer';
  15. import MP4Remuxer from '../remux/mp4-remuxer';
  16. import PassThroughRemuxer from '../remux/passthrough-remuxer';
  17.  
  18. import { getSelfScope } from '../utils/get-self-scope';
  19. import { logger } from '../utils/logger';
  20.  
  21. // see https://stackoverflow.com/a/11237259/589493
  22. const global = getSelfScope(); // safeguard for code that might run both on worker and main thread
  23.  
  24. let now;
  25. // performance.now() not available on WebWorker, at least on Safari Desktop
  26. try {
  27. now = global.performance.now.bind(global.performance);
  28. } catch (err) {
  29. logger.debug('Unable to use Performance API on this environment');
  30. now = global.Date.now;
  31. }
  32.  
  33. class DemuxerInline {
  34. constructor (observer, typeSupported, config, vendor) {
  35. this.observer = observer;
  36. this.typeSupported = typeSupported;
  37. this.config = config;
  38. this.vendor = vendor;
  39. }
  40.  
  41. destroy () {
  42. let demuxer = this.demuxer;
  43. if (demuxer) {
  44. demuxer.destroy();
  45. }
  46. }
  47.  
  48. push (data, decryptdata, initSegment, audioCodec, videoCodec, timeOffset, discontinuity, trackSwitch, contiguous, duration, accurateTimeOffset, defaultInitPTS) {
  49. if ((data.byteLength > 0) && (decryptdata != null) && (decryptdata.key != null) && (decryptdata.method === 'AES-128')) {
  50. let decrypter = this.decrypter;
  51. if (decrypter == null) {
  52. decrypter = this.decrypter = new Decrypter(this.observer, this.config);
  53. }
  54.  
  55. const startTime = now();
  56. decrypter.decrypt(data, decryptdata.key.buffer, decryptdata.iv.buffer, (decryptedData) => {
  57. const endTime = now();
  58. this.observer.trigger(Event.FRAG_DECRYPTED, { stats: { tstart: startTime, tdecrypt: endTime } });
  59. this.pushDecrypted(new Uint8Array(decryptedData), decryptdata, new Uint8Array(initSegment), audioCodec, videoCodec, timeOffset, discontinuity, trackSwitch, contiguous, duration, accurateTimeOffset, defaultInitPTS);
  60. });
  61. } else {
  62. this.pushDecrypted(new Uint8Array(data), decryptdata, new Uint8Array(initSegment), audioCodec, videoCodec, timeOffset, discontinuity, trackSwitch, contiguous, duration, accurateTimeOffset, defaultInitPTS);
  63. }
  64. }
  65.  
  66. pushDecrypted (data, decryptdata, initSegment, audioCodec, videoCodec, timeOffset, discontinuity, trackSwitch, contiguous, duration, accurateTimeOffset, defaultInitPTS) {
  67. let demuxer = this.demuxer;
  68. let remuxer = this.remuxer;
  69. if (!demuxer ||
  70. // in case of continuity change, or track switch
  71. // we might switch from content type (AAC container to TS container, or TS to fmp4 for example)
  72. (discontinuity || trackSwitch)) {
  73. const observer = this.observer;
  74. const typeSupported = this.typeSupported;
  75. const config = this.config;
  76. // probing order is TS/MP4/AAC/MP3
  77. const muxConfig = [
  78. { demux: TSDemuxer, remux: MP4Remuxer },
  79. { demux: MP4Demuxer, remux: PassThroughRemuxer },
  80. { demux: AACDemuxer, remux: MP4Remuxer },
  81. { demux: MP3Demuxer, remux: MP4Remuxer }
  82. ];
  83.  
  84. // probe for content type
  85. let mux;
  86. for (let i = 0, len = muxConfig.length; i < len; i++) {
  87. mux = muxConfig[i];
  88. if (mux.demux.probe(data)) {
  89. break;
  90. }
  91. }
  92. if (!mux) {
  93. observer.trigger(Event.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: true, reason: 'no demux matching with content found' });
  94. return;
  95. }
  96. // so let's check that current remuxer and demuxer are still valid
  97. if (!remuxer || !(remuxer instanceof mux.remux)) {
  98. remuxer = new mux.remux(observer, config, typeSupported, this.vendor);
  99. }
  100. if (!demuxer || !(demuxer instanceof mux.demux)) {
  101. demuxer = new mux.demux(observer, remuxer, config, typeSupported);
  102. this.probe = mux.demux.probe;
  103. }
  104. this.demuxer = demuxer;
  105. this.remuxer = remuxer;
  106. }
  107.  
  108. if (discontinuity || trackSwitch) {
  109. demuxer.resetInitSegment(initSegment, audioCodec, videoCodec, duration);
  110. remuxer.resetInitSegment();
  111. }
  112. if (discontinuity) {
  113. demuxer.resetTimeStamp(defaultInitPTS);
  114. remuxer.resetTimeStamp(defaultInitPTS);
  115. }
  116. if (typeof demuxer.setDecryptData === 'function') {
  117. demuxer.setDecryptData(decryptdata);
  118. }
  119.  
  120. demuxer.append(data, timeOffset, contiguous, accurateTimeOffset);
  121. }
  122. }
  123.  
  124. export default DemuxerInline;