timestamp-rollover-stream.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /**
  2. * mux.js
  3. *
  4. * Copyright (c) Brightcove
  5. * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
  6. *
  7. * Accepts program elementary stream (PES) data events and corrects
  8. * decode and presentation time stamps to account for a rollover
  9. * of the 33 bit value.
  10. */
  11. 'use strict';
  12. var Stream = require('../utils/stream');
  13. var MAX_TS = 8589934592;
  14. var RO_THRESH = 4294967296;
  15. var TYPE_SHARED = 'shared';
  16. var handleRollover = function(value, reference) {
  17. var direction = 1;
  18. if (value > reference) {
  19. // If the current timestamp value is greater than our reference timestamp and we detect a
  20. // timestamp rollover, this means the roll over is happening in the opposite direction.
  21. // Example scenario: Enter a long stream/video just after a rollover occurred. The reference
  22. // point will be set to a small number, e.g. 1. The user then seeks backwards over the
  23. // rollover point. In loading this segment, the timestamp values will be very large,
  24. // e.g. 2^33 - 1. Since this comes before the data we loaded previously, we want to adjust
  25. // the time stamp to be `value - 2^33`.
  26. direction = -1;
  27. }
  28. // Note: A seek forwards or back that is greater than the RO_THRESH (2^32, ~13 hours) will
  29. // cause an incorrect adjustment.
  30. while (Math.abs(reference - value) > RO_THRESH) {
  31. value += (direction * MAX_TS);
  32. }
  33. return value;
  34. };
  35. var TimestampRolloverStream = function(type) {
  36. var lastDTS, referenceDTS;
  37. TimestampRolloverStream.prototype.init.call(this);
  38. // The "shared" type is used in cases where a stream will contain muxed
  39. // video and audio. We could use `undefined` here, but having a string
  40. // makes debugging a little clearer.
  41. this.type_ = type || TYPE_SHARED;
  42. this.push = function(data) {
  43. /**
  44. * Rollover stream expects data from elementary stream.
  45. * Elementary stream can push forward 2 types of data
  46. * - Parsed Video/Audio/Timed-metadata PES (packetized elementary stream) packets
  47. * - Tracks metadata from PMT (Program Map Table)
  48. * Rollover stream expects pts/dts info to be available, since it stores lastDTS
  49. * We should ignore non-PES packets since they may override lastDTS to undefined.
  50. * lastDTS is important to signal the next segments
  51. * about rollover from the previous segments.
  52. */
  53. if (data.type === 'metadata') {
  54. this.trigger('data', data);
  55. return;
  56. }
  57. // Any "shared" rollover streams will accept _all_ data. Otherwise,
  58. // streams will only accept data that matches their type.
  59. if (this.type_ !== TYPE_SHARED && data.type !== this.type_) {
  60. return;
  61. }
  62. if (referenceDTS === undefined) {
  63. referenceDTS = data.dts;
  64. }
  65. data.dts = handleRollover(data.dts, referenceDTS);
  66. data.pts = handleRollover(data.pts, referenceDTS);
  67. lastDTS = data.dts;
  68. this.trigger('data', data);
  69. };
  70. this.flush = function() {
  71. referenceDTS = lastDTS;
  72. this.trigger('done');
  73. };
  74. this.endTimeline = function() {
  75. this.flush();
  76. this.trigger('endedtimeline');
  77. };
  78. this.discontinuity = function() {
  79. referenceDTS = void 0;
  80. lastDTS = void 0;
  81. };
  82. this.reset = function() {
  83. this.discontinuity();
  84. this.trigger('reset');
  85. };
  86. };
  87. TimestampRolloverStream.prototype = new Stream();
  88. module.exports = {
  89. TimestampRolloverStream: TimestampRolloverStream,
  90. handleRollover: handleRollover
  91. };