transmux.js
3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/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);