@lumen5/beamcoder 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +41 -0
- package/.circleci/images/testbeam10-4.1/Dockerfile +12 -0
- package/.circleci/test_image/Dockerfile +14 -0
- package/.circleci/test_image/build.md +13 -0
- package/.eslintrc.js +27 -0
- package/.github/workflows/publish-npm.yml +33 -0
- package/LICENSE +674 -0
- package/README.md +1221 -0
- package/beamstreams.js +692 -0
- package/binding.gyp +103 -0
- package/examples/encode_h264.js +92 -0
- package/examples/jpeg_app.js +55 -0
- package/examples/jpeg_filter_app.js +101 -0
- package/examples/make_mp4.js +123 -0
- package/images/beamcoder_small.jpg +0 -0
- package/index.d.ts +83 -0
- package/index.js +44 -0
- package/install_ffmpeg.js +240 -0
- package/package.json +45 -0
- package/scratch/decode_aac.js +38 -0
- package/scratch/decode_avci.js +50 -0
- package/scratch/decode_hevc.js +38 -0
- package/scratch/decode_pcm.js +39 -0
- package/scratch/make_a_mux.js +68 -0
- package/scratch/muxer.js +74 -0
- package/scratch/read_wav.js +35 -0
- package/scratch/simple_mux.js +39 -0
- package/scratch/stream_avci.js +127 -0
- package/scratch/stream_mp4.js +78 -0
- package/scratch/stream_mux.js +47 -0
- package/scratch/stream_pcm.js +82 -0
- package/scratch/stream_wav.js +62 -0
- package/scripts/install_beamcoder_dependencies.sh +25 -0
- package/src/adaptor.h +202 -0
- package/src/beamcoder.cc +937 -0
- package/src/beamcoder_util.cc +1129 -0
- package/src/beamcoder_util.h +206 -0
- package/src/codec.cc +7386 -0
- package/src/codec.h +44 -0
- package/src/codec_par.cc +1818 -0
- package/src/codec_par.h +40 -0
- package/src/decode.cc +569 -0
- package/src/decode.h +75 -0
- package/src/demux.cc +584 -0
- package/src/demux.h +88 -0
- package/src/encode.cc +496 -0
- package/src/encode.h +72 -0
- package/src/filter.cc +1888 -0
- package/src/filter.h +30 -0
- package/src/format.cc +5287 -0
- package/src/format.h +77 -0
- package/src/frame.cc +2681 -0
- package/src/frame.h +52 -0
- package/src/governor.cc +286 -0
- package/src/governor.h +30 -0
- package/src/hwcontext.cc +378 -0
- package/src/hwcontext.h +35 -0
- package/src/log.cc +186 -0
- package/src/log.h +20 -0
- package/src/mux.cc +834 -0
- package/src/mux.h +106 -0
- package/src/packet.cc +762 -0
- package/src/packet.h +49 -0
- package/test/codecParamsSpec.js +148 -0
- package/test/decoderSpec.js +56 -0
- package/test/demuxerSpec.js +41 -0
- package/test/encoderSpec.js +69 -0
- package/test/filtererSpec.js +47 -0
- package/test/formatSpec.js +343 -0
- package/test/frameSpec.js +145 -0
- package/test/introspectionSpec.js +73 -0
- package/test/muxerSpec.js +34 -0
- package/test/packetSpec.js +122 -0
- package/types/Beamstreams.d.ts +98 -0
- package/types/Codec.d.ts +123 -0
- package/types/CodecContext.d.ts +555 -0
- package/types/CodecPar.d.ts +108 -0
- package/types/Decoder.d.ts +137 -0
- package/types/Demuxer.d.ts +113 -0
- package/types/Encoder.d.ts +94 -0
- package/types/Filter.d.ts +324 -0
- package/types/FormatContext.d.ts +380 -0
- package/types/Frame.d.ts +295 -0
- package/types/HWContext.d.ts +62 -0
- package/types/Muxer.d.ts +121 -0
- package/types/Packet.d.ts +82 -0
- package/types/PrivClass.d.ts +25 -0
- package/types/Stream.d.ts +165 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Aerostat Beam Coder - Node.js native bindings for FFmpeg.
|
|
3
|
+
Copyright (C) 2019 Streampunk Media Ltd.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
https://www.streampunk.media/ mailto:furnace@streampunk.media
|
|
19
|
+
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const beamcoder = require('../index.js');
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
// const util = require('util');
|
|
25
|
+
|
|
26
|
+
async function run() {
|
|
27
|
+
// let demuxer = await createDemuxer('../../media/dpp/AS11_DPP_HD_EXAMPLE_1.mxf');
|
|
28
|
+
let demuxerStream = beamcoder.demuxerStream({ highwaterMark: 65536 });
|
|
29
|
+
fs.createReadStream('../../media/dpp/AS11_DPP_HD_EXAMPLE_1.mxf').pipe(demuxerStream);
|
|
30
|
+
let demuxer = await demuxerStream.demuxer({});
|
|
31
|
+
// console.log(demuxer);
|
|
32
|
+
|
|
33
|
+
let decoder = await beamcoder.decoder({ name: 'h264' });
|
|
34
|
+
// console.log(decoder);
|
|
35
|
+
|
|
36
|
+
const vidStream = demuxer.streams[0];
|
|
37
|
+
let filterer = await beamcoder.filterer({
|
|
38
|
+
filterType: 'video',
|
|
39
|
+
inputParams: [
|
|
40
|
+
{
|
|
41
|
+
name: 'in0:v',
|
|
42
|
+
width: vidStream.codecpar.width,
|
|
43
|
+
height: vidStream.codecpar.height,
|
|
44
|
+
pixelFormat: vidStream.codecpar.format,
|
|
45
|
+
timeBase: vidStream.time_base,
|
|
46
|
+
pixelAspect: vidStream.sample_aspect_ratio
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'in1:v',
|
|
50
|
+
width: vidStream.codecpar.width,
|
|
51
|
+
height: vidStream.codecpar.height,
|
|
52
|
+
pixelFormat: vidStream.codecpar.format,
|
|
53
|
+
timeBase: vidStream.time_base,
|
|
54
|
+
pixelAspect: vidStream.sample_aspect_ratio
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
outputParams: [
|
|
58
|
+
{
|
|
59
|
+
name: 'out0:v',
|
|
60
|
+
pixelFormat: 'yuv422p'
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
filterSpec: '[in0:v] scale=1280:720 [left]; [in1:v] scale=640:360 [right]; [left][right] overlay=format=auto:x=640 [out0:v]'
|
|
64
|
+
});
|
|
65
|
+
// console.log(filterer.graph);
|
|
66
|
+
// console.log(util.inspect(filterer.graph, {depth: null}));
|
|
67
|
+
console.log(filterer.graph.dump());
|
|
68
|
+
|
|
69
|
+
// width = '1000';
|
|
70
|
+
// const scaleFilter = filterer.graph.filters.find(f => 'scale' === f.filter.name);
|
|
71
|
+
// scaleFilter.priv = { width: 1000 };
|
|
72
|
+
// console.log(util.inspect(scaleFilter, {depth: null}));
|
|
73
|
+
|
|
74
|
+
// const overlayFilter = filterer.graph.filters.find(f => 'overlay' === f.filter.name);
|
|
75
|
+
// overlayFilter.priv = { x: 100, y: 100 };
|
|
76
|
+
// console.log(util.inspect(overlayFilter, {depth: null}));
|
|
77
|
+
|
|
78
|
+
let encParams = {
|
|
79
|
+
name: 'libx264',
|
|
80
|
+
width: 1280,
|
|
81
|
+
height: 720,
|
|
82
|
+
// bit_rate: 10000000,
|
|
83
|
+
time_base: [1, 25],
|
|
84
|
+
framerate: [25, 1],
|
|
85
|
+
// gop_size: 50,
|
|
86
|
+
// max_b_frames: 1,
|
|
87
|
+
pix_fmt: 'yuv422p',
|
|
88
|
+
priv_data: {
|
|
89
|
+
crf: 23
|
|
90
|
+
// preset: 'slow',
|
|
91
|
+
// profile: 'high422',
|
|
92
|
+
// level: '4.2'
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
let encoder = beamcoder.encoder(encParams);
|
|
97
|
+
// console.log(encoder);
|
|
98
|
+
|
|
99
|
+
let outFile = fs.createWriteStream('wibble.h264');
|
|
100
|
+
|
|
101
|
+
// await demuxer.seek({ frame: 4200, stream_index: 0});
|
|
102
|
+
|
|
103
|
+
let packet = {};
|
|
104
|
+
for ( let x = 0 ; x < 10 && packet !== null; x++ ) {
|
|
105
|
+
packet = await demuxer.read();
|
|
106
|
+
if (packet.stream_index == 0) {
|
|
107
|
+
// console.log(packet);
|
|
108
|
+
let frames = await decoder.decode(packet);
|
|
109
|
+
// console.log(frames);
|
|
110
|
+
let filtFrames = await filterer.filter([
|
|
111
|
+
{ name: 'in0:v', frames: frames.frames },
|
|
112
|
+
{ name: 'in1:v', frames: frames.frames },
|
|
113
|
+
]);
|
|
114
|
+
// console.log(filtFrames);
|
|
115
|
+
|
|
116
|
+
let packets = await encoder.encode(filtFrames[0].frames[0]);
|
|
117
|
+
// console.log(x, packets.totalTime);
|
|
118
|
+
packets.packets.forEach(x => outFile.write(x.data));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
let frames = await decoder.flush();
|
|
122
|
+
console.log('flush', frames.total_time, frames.frames.length);
|
|
123
|
+
|
|
124
|
+
demuxerStream.destroy();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
run().catch(console.error);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Aerostat Beam Coder - Node.js native bindings for FFmpeg.
|
|
3
|
+
Copyright (C) 2019 Streampunk Media Ltd.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
https://www.streampunk.media/ mailto:furnace@streampunk.media
|
|
19
|
+
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const beamcoder = require('../index.js');
|
|
23
|
+
|
|
24
|
+
async function run() {
|
|
25
|
+
const urls = [ 'file:../../Media/big_buck_bunny_1080p_h264.mov' ];
|
|
26
|
+
const spec = { start: 0, end: 24 };
|
|
27
|
+
|
|
28
|
+
const params = {
|
|
29
|
+
video: [
|
|
30
|
+
{
|
|
31
|
+
sources: [
|
|
32
|
+
{ url: urls[0], ms: spec, streamIndex: 0 }
|
|
33
|
+
],
|
|
34
|
+
filterSpec: '[in0:v] scale=1280:720, colorspace=all=bt709 [out0:v]',
|
|
35
|
+
streams: [
|
|
36
|
+
{ name: 'h264', time_base: [1, 90000],
|
|
37
|
+
codecpar: {
|
|
38
|
+
width: 1280, height: 720, format: 'yuv422p', color_space: 'bt709',
|
|
39
|
+
sample_aspect_ratio: [1, 1]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
audio: [
|
|
46
|
+
{
|
|
47
|
+
sources: [
|
|
48
|
+
{ url: urls[0], ms: spec, streamIndex: 2 }
|
|
49
|
+
],
|
|
50
|
+
filterSpec: '[in0:a] aformat=sample_fmts=fltp:channel_layouts=mono [out0:a]',
|
|
51
|
+
streams: [
|
|
52
|
+
{ name: 'aac', time_base: [1, 90000],
|
|
53
|
+
codecpar: {
|
|
54
|
+
sample_rate: 48000, format: 'fltp', frame_size: 1024,
|
|
55
|
+
channels: 1, channel_layout: 'mono'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
out: {
|
|
62
|
+
formatName: 'mp4',
|
|
63
|
+
url: 'file:temp.mp4'
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await beamcoder.makeSources(params);
|
|
68
|
+
const beamStreams = await beamcoder.makeStreams(params);
|
|
69
|
+
|
|
70
|
+
await beamStreams.run();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log('Running mp4 maker');
|
|
74
|
+
let start = Date.now();
|
|
75
|
+
run()
|
|
76
|
+
.then(() => console.log(`Finished ${Date.now() - start}ms`))
|
|
77
|
+
.catch(console.error);
|
|
78
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Aerostat Beam Coder - Node.js native bindings for FFmpeg.
|
|
3
|
+
Copyright (C) 2019 Streampunk Media Ltd.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
https://www.streampunk.media/ mailto:furnace@streampunk.media
|
|
19
|
+
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const beamcoder = require('../index.js');
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
|
|
25
|
+
async function run() {
|
|
26
|
+
let demuxer = await beamcoder.demuxer('../../media/sound/BBCNewsCountdown.wav');
|
|
27
|
+
|
|
28
|
+
let muxerStream = beamcoder.muxerStream({ highwaterMark: 65536 });
|
|
29
|
+
muxerStream.pipe(fs.createWriteStream('test.wav'));
|
|
30
|
+
|
|
31
|
+
let muxer = muxerStream.muxer({ format_name: 'wav' });
|
|
32
|
+
let stream = muxer.newStream(demuxer.streams[0]); // eslint-disable-line
|
|
33
|
+
// stream.time_base = demuxer.streams[0].time_base;
|
|
34
|
+
// stream.codecpar = demuxer.streams[0].codecpar;
|
|
35
|
+
await muxer.openIO();
|
|
36
|
+
|
|
37
|
+
await muxer.writeHeader();
|
|
38
|
+
let packet = {};
|
|
39
|
+
for ( let x = 0 ; x < 10000 && packet !== null ; x++ ) {
|
|
40
|
+
packet = await demuxer.read();
|
|
41
|
+
if (packet)
|
|
42
|
+
await muxer.writeFrame(packet);
|
|
43
|
+
}
|
|
44
|
+
await muxer.writeTrailer();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
run();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Aerostat Beam Coder - Node.js native bindings for FFmpeg.
|
|
3
|
+
Copyright (C) 2019 Streampunk Media Ltd.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
https://www.streampunk.media/ mailto:furnace@streampunk.media
|
|
19
|
+
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const beamcoder = require('../index.js');
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const util = require('util'); // eslint-disable-line
|
|
25
|
+
|
|
26
|
+
async function run() {
|
|
27
|
+
let demuxerStream = beamcoder.demuxerStream({ highwaterMark: 65536 });
|
|
28
|
+
// fs.createReadStream('../../media/dpp/AS11_DPP_HD_EXAMPLE_1.mxf').pipe(demuxerStream);
|
|
29
|
+
fs.createReadStream('../../media/sound/BBCNewsCountdown.wav').pipe(demuxerStream);
|
|
30
|
+
|
|
31
|
+
let demuxer = await demuxerStream.demuxer();
|
|
32
|
+
console.log(demuxer.streams);
|
|
33
|
+
|
|
34
|
+
let decoder = await beamcoder.decoder({ demuxer: demuxer, stream_index : 0 });
|
|
35
|
+
// console.log(decoder);
|
|
36
|
+
|
|
37
|
+
const audStream = demuxer.streams[0];
|
|
38
|
+
let filterer = await beamcoder.filterer({
|
|
39
|
+
filterType: 'audio',
|
|
40
|
+
inputParams: [
|
|
41
|
+
{
|
|
42
|
+
name: '0:a',
|
|
43
|
+
sampleRate: audStream.codecpar.sample_rate,
|
|
44
|
+
sampleFormat: audStream.codecpar.format,
|
|
45
|
+
channelLayout: 'stereo', //audStream.codecpar.channel_layout,
|
|
46
|
+
timeBase: audStream.time_base
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
outputParams: [
|
|
50
|
+
{
|
|
51
|
+
name: 'out0:a',
|
|
52
|
+
sampleRate: 8000,
|
|
53
|
+
sampleFormat: 's16',
|
|
54
|
+
channelLayout: 'stereo'
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
filterSpec: '[0:a] aresample=8000, aformat=sample_fmts=s16:channel_layouts=stereo [out0:a]'
|
|
58
|
+
});
|
|
59
|
+
// console.log(filterer.graph);
|
|
60
|
+
// console.log(util.inspect(filterer.graph.filters[2], {depth: null}));
|
|
61
|
+
console.log(filterer.graph.dump());
|
|
62
|
+
|
|
63
|
+
// const abuffersink = filterer.graph.filters.find(f => 'abuffersink' === f.filter.name);
|
|
64
|
+
// console.log(util.inspect(abuffersink, {depth: null}));
|
|
65
|
+
|
|
66
|
+
let packet = {};
|
|
67
|
+
for ( let x = 0 ; x < 10000 && packet !== null ; x++ ) {
|
|
68
|
+
packet = await demuxer.read();
|
|
69
|
+
if (packet && packet.stream_index == 0) {
|
|
70
|
+
// console.log(packet);
|
|
71
|
+
let frames = await decoder.decode(packet);
|
|
72
|
+
// console.log(frames);
|
|
73
|
+
|
|
74
|
+
let filtFrames = await filterer.filter([ // eslint-disable-line
|
|
75
|
+
{ name: '0:a', frames: frames.frames }
|
|
76
|
+
]);
|
|
77
|
+
// console.log(filtFrames);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
run().catch(console.error);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Aerostat Beam Coder - Node.js native bindings for FFmpeg.
|
|
3
|
+
Copyright (C) 2019 Streampunk Media Ltd.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
https://www.streampunk.media/ mailto:furnace@streampunk.media
|
|
19
|
+
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const beamcoder = require('../index.js');
|
|
23
|
+
|
|
24
|
+
async function run() {
|
|
25
|
+
const urls = [ 'file:../Media/sound/Countdown.wav' ];
|
|
26
|
+
const spec = { start: 50, end: 58 };
|
|
27
|
+
const params = {
|
|
28
|
+
video: [],
|
|
29
|
+
audio: [
|
|
30
|
+
{
|
|
31
|
+
sources: [
|
|
32
|
+
{ url: urls[0], ms: spec, streamIndex: 0 }
|
|
33
|
+
],
|
|
34
|
+
filterSpec: '[in0:a] \
|
|
35
|
+
volume=precision=float:volume=0.8 \
|
|
36
|
+
[out0:a]',
|
|
37
|
+
streams: [
|
|
38
|
+
{ name: 'aac', time_base: [1, 90000],
|
|
39
|
+
codecpar: {
|
|
40
|
+
sample_rate: 48000, format: 'fltp', channel_layout: 'stereo'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
out: {
|
|
47
|
+
formatName: 'mp4',
|
|
48
|
+
url: 'file:temp.mp4'
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
await beamcoder.makeSources(params);
|
|
53
|
+
const beamStreams = await beamcoder.makeStreams(params);
|
|
54
|
+
await beamStreams.run();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('Running wav maker');
|
|
58
|
+
let start = Date.now();
|
|
59
|
+
run()
|
|
60
|
+
.then(() => console.log(`Finished ${Date.now() - start}ms`))
|
|
61
|
+
.catch(console.error);
|
|
62
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
ARCH=$(uname -m)
|
|
4
|
+
|
|
5
|
+
if [[ "$ARCH" == "x86_64" ]]; then
|
|
6
|
+
echo "Detected 64 bit intel"
|
|
7
|
+
BINARIES_URL="https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n5.1-latest-linux64-gpl-shared-5.1.tar.xz"
|
|
8
|
+
elif [[ "$ARCH" == "aarch64" ]]; then
|
|
9
|
+
# ARM linux setup
|
|
10
|
+
echo "Detected ARM"
|
|
11
|
+
BINARIES_URL="https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n5.1-latest-linuxarm64-gpl-shared-5.1.tar.xz"
|
|
12
|
+
else
|
|
13
|
+
echo "\n\n\UNSUPPORTED ARCH $ARCH\n\n\n"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
rm -rf ./.ffmpeg
|
|
18
|
+
mkdir ./.ffmpeg
|
|
19
|
+
cd ./.ffmpeg
|
|
20
|
+
wget $BINARIES_URL -O ffmpeg.tar.xz
|
|
21
|
+
tar -xf ffmpeg.tar.xz
|
|
22
|
+
rm ffmpeg.tar.xz
|
|
23
|
+
mv $(ls -1) ffmpeg
|
|
24
|
+
|
|
25
|
+
ldconfig $(realpath .)/ffmpeg/lib/
|
package/src/adaptor.h
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Aerostat Beam Coder - Node.js native bindings for FFmpeg.
|
|
3
|
+
Copyright (C) 2019 Streampunk Media Ltd.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
https://www.streampunk.media/ mailto:furnace@streampunk.media
|
|
19
|
+
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#ifndef ADAPTOR_H
|
|
23
|
+
#define ADAPTOR_H
|
|
24
|
+
|
|
25
|
+
#include "node_api.h"
|
|
26
|
+
#include <queue>
|
|
27
|
+
#include <mutex>
|
|
28
|
+
#include <condition_variable>
|
|
29
|
+
|
|
30
|
+
template <class T>
|
|
31
|
+
class Queue {
|
|
32
|
+
public:
|
|
33
|
+
Queue(uint32_t maxQueue) : mActive(true), mMaxQueue(maxQueue), qu(), m(), cv() {}
|
|
34
|
+
~Queue() {}
|
|
35
|
+
|
|
36
|
+
void enqueue(T t) {
|
|
37
|
+
std::unique_lock<std::mutex> lk(m);
|
|
38
|
+
while(mActive && (qu.size() >= mMaxQueue)) {
|
|
39
|
+
cv.wait(lk);
|
|
40
|
+
}
|
|
41
|
+
qu.push(t);
|
|
42
|
+
cv.notify_one();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
T dequeue() {
|
|
46
|
+
std::unique_lock<std::mutex> lk(m);
|
|
47
|
+
while(mActive && qu.empty()) {
|
|
48
|
+
cv.wait(lk);
|
|
49
|
+
}
|
|
50
|
+
T val = 0;
|
|
51
|
+
if (!qu.empty()) {
|
|
52
|
+
val = qu.front();
|
|
53
|
+
qu.pop();
|
|
54
|
+
cv.notify_one();
|
|
55
|
+
}
|
|
56
|
+
return val;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
size_t size() const {
|
|
60
|
+
std::lock_guard<std::mutex> lk(m);
|
|
61
|
+
return qu.size();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
void quit() {
|
|
65
|
+
std::lock_guard<std::mutex> lk(m);
|
|
66
|
+
mActive = false;
|
|
67
|
+
if ((0 == qu.size()) || (qu.size() >= mMaxQueue)) {
|
|
68
|
+
// ensure release of any blocked thread
|
|
69
|
+
cv.notify_all();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private:
|
|
74
|
+
bool mActive;
|
|
75
|
+
uint32_t mMaxQueue;
|
|
76
|
+
std::queue<T> qu;
|
|
77
|
+
mutable std::mutex m;
|
|
78
|
+
std::condition_variable cv;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
class Chunk {
|
|
82
|
+
public:
|
|
83
|
+
Chunk(napi_ref bufRef, void *buf, size_t bufLen)
|
|
84
|
+
: mBufRef(bufRef), mBuf(buf), mLen(bufLen), mLocalAlloc(nullptr == bufRef) {}
|
|
85
|
+
~Chunk() { if (mLocalAlloc) free(mBuf); }
|
|
86
|
+
|
|
87
|
+
napi_ref buf_ref() const { return mBufRef; }
|
|
88
|
+
const void *buf() const { return mBuf; }
|
|
89
|
+
size_t len() const { return mLen; }
|
|
90
|
+
|
|
91
|
+
private:
|
|
92
|
+
const napi_ref mBufRef;
|
|
93
|
+
void *mBuf;
|
|
94
|
+
const size_t mLen;
|
|
95
|
+
const bool mLocalAlloc;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
class Adaptor {
|
|
99
|
+
public:
|
|
100
|
+
Adaptor(uint32_t queueLen)
|
|
101
|
+
: mQueue(new Queue<Chunk *>(queueLen)), mCurChunk(nullptr), mChunkPos(0), m(), mBuf(1024) {}
|
|
102
|
+
~Adaptor() {
|
|
103
|
+
delete mQueue;
|
|
104
|
+
std::unique_lock<std::mutex> lk(m);
|
|
105
|
+
while (mDone.size()) {
|
|
106
|
+
Chunk *chunk = mDone.back();
|
|
107
|
+
mDone.pop_back();
|
|
108
|
+
delete chunk;
|
|
109
|
+
}
|
|
110
|
+
mDone.clear();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
int write(const uint8_t *buf, int bufSize) {
|
|
114
|
+
uint8_t *qBuf = (uint8_t *)malloc(bufSize);
|
|
115
|
+
memcpy(qBuf, buf, bufSize);
|
|
116
|
+
mQueue->enqueue(new Chunk(nullptr, qBuf, bufSize));
|
|
117
|
+
return bufSize;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void *read(size_t numBytes, size_t *bytesRead) {
|
|
121
|
+
uint8_t *buf = (uint8_t *)malloc(numBytes);
|
|
122
|
+
*bytesRead = fillBuf(buf, numBytes);
|
|
123
|
+
if (numBytes != *bytesRead) {
|
|
124
|
+
if (0 == *bytesRead) {
|
|
125
|
+
free(buf);
|
|
126
|
+
buf = nullptr;
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
buf = (uint8_t *)realloc(buf, *bytesRead);
|
|
130
|
+
}
|
|
131
|
+
return buf;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
void write(napi_ref bufRef, void *buf, size_t bufLen) {
|
|
135
|
+
mQueue->enqueue(new Chunk(bufRef, buf, bufLen));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
int read(uint8_t *buf, int bufSize) {
|
|
139
|
+
return fillBuf(buf, bufSize);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
void finish() { mQueue->quit(); }
|
|
143
|
+
|
|
144
|
+
napi_status finaliseBufs(napi_env env) {
|
|
145
|
+
napi_status status = napi_ok;
|
|
146
|
+
std::unique_lock<std::mutex> lk(m);
|
|
147
|
+
while (mDone.size()) {
|
|
148
|
+
Chunk *chunk = mDone.back();
|
|
149
|
+
mDone.pop_back();
|
|
150
|
+
if (chunk->buf_ref())
|
|
151
|
+
status = napi_delete_reference(env, chunk->buf_ref());
|
|
152
|
+
delete chunk;
|
|
153
|
+
if (napi_ok != status) break;
|
|
154
|
+
}
|
|
155
|
+
return status;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// convenience buffer for avio_alloc_context
|
|
159
|
+
// - it shouldn't be needed but avformat_write_header crashes if no buffer is provided
|
|
160
|
+
unsigned char *buf() { return &mBuf[0]; }
|
|
161
|
+
int bufLen() const { return (int)mBuf.size(); }
|
|
162
|
+
|
|
163
|
+
private:
|
|
164
|
+
Queue<Chunk *> *mQueue;
|
|
165
|
+
std::vector<Chunk *> mDone;
|
|
166
|
+
Chunk *mCurChunk;
|
|
167
|
+
size_t mChunkPos;
|
|
168
|
+
mutable std::mutex m;
|
|
169
|
+
std::vector<unsigned char> mBuf;
|
|
170
|
+
|
|
171
|
+
int fillBuf(uint8_t *buf, size_t numBytes) {
|
|
172
|
+
int bufOff = 0;
|
|
173
|
+
while (numBytes) {
|
|
174
|
+
if (!mCurChunk || (mCurChunk && mCurChunk->len() == mChunkPos))
|
|
175
|
+
if (!nextChunk())
|
|
176
|
+
break;
|
|
177
|
+
|
|
178
|
+
int curSize = FFMIN(numBytes, mCurChunk->len() - mChunkPos);
|
|
179
|
+
void *srcBuf = (uint8_t *)mCurChunk->buf() + mChunkPos;
|
|
180
|
+
memcpy(buf + bufOff, srcBuf, curSize);
|
|
181
|
+
|
|
182
|
+
bufOff += curSize;
|
|
183
|
+
mChunkPos += curSize;
|
|
184
|
+
numBytes -= curSize;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return bufOff;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
bool nextChunk() {
|
|
191
|
+
if (mCurChunk) {
|
|
192
|
+
std::unique_lock<std::mutex> lk(m);
|
|
193
|
+
mDone.push_back(mCurChunk);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
mCurChunk = mQueue->dequeue();
|
|
197
|
+
mChunkPos = 0;
|
|
198
|
+
return nullptr != mCurChunk;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
#endif
|