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