transmux.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #!/usr/bin/env node
  2. /* eslint-disable no-console */
  3. const fs = require('fs');
  4. const path = require('path');
  5. const {Transmuxer} = require('../lib/mp4');
  6. const {version} = require('../package.json');
  7. const {concatTypedArrays} = require('@videojs/vhs-utils/cjs/byte-helpers');
  8. const {ONE_SECOND_IN_TS} = require('../lib/utils/clock.js');
  9. const showHelp = function() {
  10. console.log(`
  11. transmux media-file > foo.mp4
  12. transmux media-file -o foo.mp4
  13. curl -s 'some-media-ulr' | transmux.js -o foo.mp4
  14. wget -O - -o /dev/null 'some-media-url' | transmux.js -o foo.mp4
  15. transmux a supported segment (ts or adts) info an fmp4
  16. -h, --help print help
  17. -v, --version print the version
  18. -o, --output <string> write to a file instead of stdout
  19. -d, --debugger add a break point just before data goes to transmuxer
  20. `);
  21. };
  22. const parseArgs = function(args) {
  23. const options = {};
  24. for (let i = 0; i < args.length; i++) {
  25. const arg = args[i];
  26. if ((/^--version|-v$/).test(arg)) {
  27. console.log(`transmux.js v${version}`);
  28. process.exit(0);
  29. } else if ((/^--help|-h$/).test(arg)) {
  30. showHelp();
  31. process.exit(0);
  32. } else if ((/^--debugger|-d$/).test(arg)) {
  33. options.debugger = true;
  34. } else if ((/^--output|-o$/).test(arg)) {
  35. i++;
  36. options.output = args[i];
  37. } else {
  38. options.file = arg;
  39. }
  40. }
  41. return options;
  42. };
  43. const cli = function(stdin) {
  44. const options = parseArgs(process.argv.slice(2));
  45. let inputStream;
  46. let outputStream;
  47. // if stdin was provided
  48. if (stdin && options.file) {
  49. console.error(`You cannot pass in a file ${options.file} and pipe from stdin!`);
  50. process.exit(1);
  51. }
  52. if (stdin) {
  53. inputStream = process.stdin;
  54. } else if (options.file) {
  55. inputStream = fs.createReadStream(path.resolve(options.file));
  56. }
  57. if (!inputStream) {
  58. console.error('A file or stdin must be passed in as an argument or via pipeing to this script!');
  59. process.exit(1);
  60. }
  61. if (options.output) {
  62. outputStream = fs.createWriteStream(path.resolve(options.output), {
  63. encoding: null
  64. });
  65. } else {
  66. outputStream = process.stdout;
  67. }
  68. return new Promise(function(resolve, reject) {
  69. let allData;
  70. inputStream.on('data', (chunk) => {
  71. allData = concatTypedArrays(allData, chunk);
  72. });
  73. inputStream.on('error', reject);
  74. inputStream.on('close', () => {
  75. if (!allData || !allData.length) {
  76. return reject('file is empty');
  77. }
  78. resolve(allData);
  79. });
  80. }).then(function(inputData) {
  81. const transmuxer = new Transmuxer();
  82. // Setting the BMDT to ensure that captions and id3 tags are not
  83. // time-shifted by this value when they are output and instead are
  84. // zero-based
  85. transmuxer.setBaseMediaDecodeTime(ONE_SECOND_IN_TS);
  86. transmuxer.on('data', function(data) {
  87. if (data.initSegment) {
  88. outputStream.write(concatTypedArrays(data.initSegment, data.data));
  89. } else {
  90. outputStream.write(data.data);
  91. }
  92. });
  93. if (options.debugger) {
  94. // eslint-disable-next-line
  95. debugger;
  96. }
  97. transmuxer.push(inputData);
  98. transmuxer.flush();
  99. process.exit(0);
  100. }).catch(function(e) {
  101. console.error(e);
  102. process.exit(1);
  103. });
  104. };
  105. // no stdin if isTTY is set
  106. cli(!process.stdin.isTTY ? process.stdin : null);