You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.3 KiB
127 lines
3.3 KiB
#!/usr/bin/env node
|
|
/* eslint-disable no-console */
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const {Transmuxer} = require('../lib/mp4');
|
|
const {version} = require('../package.json');
|
|
const {concatTypedArrays} = require('@videojs/vhs-utils/cjs/byte-helpers');
|
|
const {ONE_SECOND_IN_TS} = require('../lib/utils/clock.js');
|
|
|
|
const showHelp = function() {
|
|
console.log(`
|
|
transmux media-file > foo.mp4
|
|
transmux media-file -o foo.mp4
|
|
curl -s 'some-media-ulr' | transmux.js -o foo.mp4
|
|
wget -O - -o /dev/null 'some-media-url' | transmux.js -o foo.mp4
|
|
|
|
transmux a supported segment (ts or adts) info an fmp4
|
|
|
|
-h, --help print help
|
|
-v, --version print the version
|
|
-o, --output <string> write to a file instead of stdout
|
|
-d, --debugger add a break point just before data goes to transmuxer
|
|
`);
|
|
};
|
|
|
|
const parseArgs = function(args) {
|
|
const options = {};
|
|
|
|
for (let i = 0; i < args.length; i++) {
|
|
const arg = args[i];
|
|
|
|
if ((/^--version|-v$/).test(arg)) {
|
|
console.log(`transmux.js v${version}`);
|
|
process.exit(0);
|
|
} else if ((/^--help|-h$/).test(arg)) {
|
|
showHelp();
|
|
process.exit(0);
|
|
} else if ((/^--debugger|-d$/).test(arg)) {
|
|
options.debugger = true;
|
|
} else if ((/^--output|-o$/).test(arg)) {
|
|
i++;
|
|
options.output = args[i];
|
|
} else {
|
|
options.file = arg;
|
|
}
|
|
}
|
|
|
|
return options;
|
|
};
|
|
|
|
const cli = function(stdin) {
|
|
const options = parseArgs(process.argv.slice(2));
|
|
let inputStream;
|
|
let outputStream;
|
|
|
|
// if stdin was provided
|
|
if (stdin && options.file) {
|
|
console.error(`You cannot pass in a file ${options.file} and pipe from stdin!`);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (stdin) {
|
|
inputStream = process.stdin;
|
|
} else if (options.file) {
|
|
inputStream = fs.createReadStream(path.resolve(options.file));
|
|
}
|
|
|
|
if (!inputStream) {
|
|
console.error('A file or stdin must be passed in as an argument or via pipeing to this script!');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (options.output) {
|
|
outputStream = fs.createWriteStream(path.resolve(options.output), {
|
|
encoding: null
|
|
});
|
|
} else {
|
|
outputStream = process.stdout;
|
|
}
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
let allData;
|
|
|
|
inputStream.on('data', (chunk) => {
|
|
allData = concatTypedArrays(allData, chunk);
|
|
});
|
|
inputStream.on('error', reject);
|
|
|
|
inputStream.on('close', () => {
|
|
if (!allData || !allData.length) {
|
|
return reject('file is empty');
|
|
}
|
|
resolve(allData);
|
|
});
|
|
}).then(function(inputData) {
|
|
const transmuxer = new Transmuxer();
|
|
|
|
// Setting the BMDT to ensure that captions and id3 tags are not
|
|
// time-shifted by this value when they are output and instead are
|
|
// zero-based
|
|
transmuxer.setBaseMediaDecodeTime(ONE_SECOND_IN_TS);
|
|
|
|
transmuxer.on('data', function(data) {
|
|
if (data.initSegment) {
|
|
outputStream.write(concatTypedArrays(data.initSegment, data.data));
|
|
} else {
|
|
outputStream.write(data.data);
|
|
}
|
|
});
|
|
|
|
if (options.debugger) {
|
|
// eslint-disable-next-line
|
|
debugger;
|
|
}
|
|
transmuxer.push(inputData);
|
|
transmuxer.flush();
|
|
process.exit(0);
|
|
}).catch(function(e) {
|
|
console.error(e);
|
|
process.exit(1);
|
|
});
|
|
};
|
|
|
|
// no stdin if isTTY is set
|
|
cli(!process.stdin.isTTY ? process.stdin : null);
|