AWS Lambda transcoder returning distorted audio - node.js

I have been at this for three days straight and it's driving me insane.
I have an event notification set up on an S3 bucket to field file.wav uploads, transcode them using a static ffmpeg binary hosted on an node.js AWS Lambda instance, then re-upload the file to the same bucket.
The issue I'm having - and this does work on my local XUbuntu machine - is that the file is read, encoded, and written synchronously, yet some sort of asynchronous access is distorting the audio file. A symptom of the distortion is static white noise, and previously (although it may have been fixed) there was overlapping audio.
This is the process:
File is uploaded via frontend
Lambda is invoked
Handler is entered and all necessary endpoint construction is performed
exports.handler = async (event, context, callback) => {
callback();
const buckinfo = event.Records[0].s3;
const filename = buckinfo.object.key.toString().replace(/\+/g, " ");
var des = filename.split('/');
var newFile = des[des.length - 1];
console.log('filename : ', filename);
const logKey = event.logKey || `${'logKey'}.log`;
s3Bucket = event.s3Bucket || process.env.S3_UPLOADS;
var meta = null;
const inputFilename = tempy.file({extension: 'wav'});
const temp3Filename = tempy.file({extension: 'mp3'});
console.log('input file', inputFilename);
console.log('output file', temp3Filename);
var mp3Filename = filename.split('/');
mp3Filename[4] = 'mp3';
mp3Filename = mp3Filename[0] + '/' +
mp3Filename[1] + '/' +
mp3Filename[2] + '/' +
mp3Filename[3] + '/' +
mp3Filename[4] + '/' +
newFile.split('.').slice(0, -1).join('.') + '.mp3';
console.log('mp3Filename : ', mp3Filename);
await readIn(filename, inputFilename, false);
await encodeFile(inputFilename, temp3Filename, false);
await writeOut(temp3Filename, mp3Filename, false);
};
(YES it's gross, but it works, so only worry about the last three lines)
The file is read in from the key passed to it via the upload event
async function readIn(inputFilename, transfer, local) {
console.log('reading in locally?', local);
console.log(`reading from ${inputFilename} to ${transfer}`);
const writeStream = fs.createWriteStream(transfer);
var file;
local? await new Promise((resolve, revoke) => {
file = fs.createReadStream(inputFilename);
writeStream.on('finish', () => {
console.log('file finished reading');
resolve();
});
writeStream.on('error', (err) => {
console.log('things messed up');
revoke();
});
file.pipe(writeStream);
}) : await new Promise((resolve, revoke) => {
writeStream.on('finish', () => {
console.log('file finished reading');
resolve();
});
writeStream.on('error', (err) => {
console.log('things messed up');
revoke();
});
s3.getObject({
Bucket :s3Bucket,
Key :inputFilename
}, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log('data got!');
}
}).createReadStream().pipe(writeStream);
});
console.log('returning to main from reading');
return ;
}
The file is then transcoded using the Linux x86-64 static binary
async function encodeFile(inputFilename, temp3Filename) {
const ffmpeg = path.resolve(__dirname, 'ffmpeg');
const ffmpegArgs = ['-i', inputFilename, '-vn', '-acodec', 'libmp3lame', temp3Filename];
console.log('arguments to ffmpeg', ffmpegArgs);
const ps = child_process.spawn(ffmpeg, ffmpegArgs);
await new Promise((resolve, revoke) => {
console.log('beginning encoding process');
ps.stderr.on('data', (data) => {console.log(`stderr: ${data}`);});
ps.on('exit', function(code, signal) {
console.log('child process exited with ' + `code ${code} and signal ${signal}`);
});
ps.on('error', function(code, signal) {
console.log('child process erred with ' + `code ${code} and signal ${signal}`);
});
ps.on('close', (code) => {
if (code === 0) {
resolve(code);
} else {
revoke(code);
}
});
});
console.log('returning to main from encoding');
return ;
}
The temporary encoded file is then re-uploaded to the S3 bucket async
function writeOut(transfer, outFile, local) {
console.log('writing out locally?', local);
console.log(`writing to ${outFile} from ${transfer}`);
const data = fs.createReadStream(transfer);
local? await new Promise((resolve, revoke) => {
const file = fs.createWriteStream(outFile);
file.on('finish', () => {
console.log('file finished writing');
resolve();
});
file.on('error', (err) => {
console.log('things messed up');
revoke();
});
data.pipe(file);
}) : await new Promise((resolve, revoke) => {
const params = {
Bucket: s3Bucket,
Key: outFile,
Body: data,
ContentType: 'audio/mpeg'
};
const options = {
partSize: 40 * 1024 * 1024,
queueSize: 1
};
s3.upload(params, options, function(err, data) {
if (err) {
console.log('error uploading', err, err.stack);
revoke(err);
} else {
console.log(data);
resolve();
}
});
});
console.log('returning to main from writing');
}
Any tips or suggestions are more than welcome.
Here is the main() I use for local testing:
async function main(input, output) {
const inputFilename = tempy.file({extension: 'wav'});
const temp3Filename = tempy.file({extension: 'mp3'});
await readIn(input, inputFilename, true);
const logs = await encodeFile(inputFilename, temp3Filename, true);
await writeOut(temp3Filename, output, true);
}
main('../../../../../../Downloads/<file>.wav', './local.mp3');
You will need to uncomment the s3 modules require statements to get this to run. All you need are the node_modules required above and the static fmmpeg binary dependent on your OS.
Thanks!
S3 Logs:
START RequestId: eb6dfbc7-e927-11e8-9a7e-c172e5d12174 Version: $LATEST
2018-11-15T22:43:50.558Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 filename : <S3/endpoint.wav>
2018-11-15T22:43:50.573Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 input file /tmp/80e9f1a9539d322a6a9cfd429b78a2f3.wav
2018-11-15T22:43:50.573Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 output file /tmp/0e1119ad256b7bfa6f5cc270eaa273cc.mp3
2018-11-15T22:43:50.573Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 mp3Filename : <S3/endpoint.mp3>
2018-11-15T22:43:50.573Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 reading in locally? false
2018-11-15T22:43:50.573Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 reading from <S3/endpoint.wav> to /tmp/80e9f1a9539d322a6a9cfd429b78a2f3.wav
2018-11-15T22:43:53.073Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 data got!
2018-11-15T22:43:53.113Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 file finished reading
2018-11-15T22:43:53.113Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 returning to main from reading
2018-11-15T22:43:53.113Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 arguments to ffmpeg [ '-i',
'/tmp/80e9f1a9539d322a6a9cfd429b78a2f3.wav',
'-vn',
'-acodec',
'libmp3lame',
'/tmp/0e1119ad256b7bfa6f5cc270eaa273cc.mp3' ]
2018-11-15T22:43:53.153Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 beginning encoding process
2018-11-15T22:43:53.913Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: ffmpeg version 4.1-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-6 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg
2018-11-15T22:43:53.972Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: libavutil 56. 22.100 / 56. 22.100
libavcodec 58. 35.100 / 58. 35.100
libavformat 58. 20.100 / 58. 20.100
libavdevice 58. 5.100 / 58. 5.100
libavfilter 7. 40.101 / 7. 40.101
libswscale 5. 3.100 / 5. 3.100
libswresample 3. 3.100 / 3. 3.100
libpostproc 55. 3.100 / 55. 3.100
2018-11-15T22:43:54.453Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from '/tmp/80e9f1a9539d322a6a9cfd429b78a2f3.wav':
Duration: 00:00:56.57, bitrate: 1059 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, mono, s16, 705 kb/s
2018-11-15T22:43:54.472Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: Stream mapping:
Stream #0:0 -> #0:0 (pcm_s16le (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
2018-11-15T22:43:54.612Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: Output #0, mp3, to '/tmp/0e1119ad256b7bfa6f5cc270eaa273cc.mp3':
Metadata:
TSSE : Lavf58.20.100
2018-11-15T22:43:54.612Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: Stream #0:0: Audio: mp3 (libmp3lame), 44100 Hz, mono, s16p
Metadata:
encoder : Lavc58.35.100 libmp3lame
2018-11-15T22:43:54.994Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 10kB time=00:00:01.25 bitrate= 66.7kbits/s speed=2.41x
2018-11-15T22:43:55.494Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 26kB time=00:00:03.24 bitrate= 65.1kbits/s speed=3.17x
2018-11-15T22:43:56.013Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 42kB time=00:00:05.33 bitrate= 64.6kbits/s speed=3.46x
2018-11-15T22:43:56.514Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 59kB time=00:00:07.47 bitrate= 64.5kbits/s speed=3.66x
2018-11-15T22:43:57.014Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 75kB time=00:00:09.56 bitrate= 64.4kbits/s speed=3.76x
2018-11-15T22:43:57.515Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 91kB time=00:00:11.57 bitrate= 64.3kbits/s speed= 3.8x
2018-11-15T22:43:58.034Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 105kB time=00:00:13.42 bitrate= 64.3kbits/s speed=3.77x
2018-11-15T22:43:58.534Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 122kB time=00:00:15.51 bitrate= 64.2kbits/s speed=3.82x
2018-11-15T22:43:59.035Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 138kB time=00:00:17.60 bitrate= 64.2kbits/s speed=3.86x
2018-11-15T22:43:59.535Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 153kB time=00:00:19.54 bitrate= 64.2kbits/s speed=3.86x
2018-11-15T22:44:00.054Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 169kB time=00:00:21.60 bitrate= 64.2kbits/s speed=3.87x
2018-11-15T22:44:00.574Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 187kB time=00:00:23.87 bitrate= 64.1kbits/s speed=3.91x
2018-11-15T22:44:01.093Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 204kB time=00:00:26.04 bitrate= 64.1kbits/s speed=3.93x
2018-11-15T22:44:01.614Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 221kB time=00:00:28.23 bitrate= 64.1kbits/s speed=3.95x
2018-11-15T22:44:02.114Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 236kB time=00:00:30.09 bitrate= 64.1kbits/s speed=3.94x
2018-11-15T22:44:02.614Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 252kB time=00:00:32.26 bitrate= 64.1kbits/s speed=3.96x
2018-11-15T22:44:03.152Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:34.40 bitrate= 61.0kbits/s speed=3.98x
2018-11-15T22:44:03.653Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:36.54 bitrate= 57.4kbits/s speed= 4x
2018-11-15T22:44:04.153Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:38.58 bitrate= 54.4kbits/s speed= 4x
2018-11-15T22:44:04.634Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:40.59 bitrate= 51.7kbits/s speed= 4x
2018-11-15T22:44:05.134Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:42.81 bitrate= 49.0kbits/s speed=4.02x
2018-11-15T22:44:05.672Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:44.95 bitrate= 46.6kbits/s speed=4.03x
2018-11-15T22:44:06.192Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:46.99 bitrate= 44.6kbits/s speed=4.02x
2018-11-15T22:44:06.674Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:49.18 bitrate= 42.6kbits/s speed=4.03x
2018-11-15T22:44:07.954Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:51.22 bitrate= 40.9kbits/s speed=4.03x
size= 256kB time=00:00:53.36 bitrate= 39.3kbits/s speed=4.03x
2018-11-15T22:44:08.214Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 256kB time=00:00:54.83 bitrate= 38.2kbits/s speed=3.99x
2018-11-15T22:44:08.613Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 stderr: size= 442kB time=00:00:56.58 bitrate= 64.1kbits/s speed= 4x
video:0kB audio:442kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.050126%
2018-11-15T22:44:08.713Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 child process exited with code 0 and signal null
2018-11-15T22:44:08.713Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 returning to main from encoding
2018-11-15T22:44:08.713Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 writing out locally? false
2018-11-15T22:44:08.713Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 writing to <S3/endpoint.mp3> from /tmp/0e1119ad256b7bfa6f5cc270eaa273cc.mp3
2018-11-15T22:44:09.045Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 { ETag: <ETag>,
Location: <S3/endpoint.mp3>,
key: <S3/endpoint.mp3>,
Key: <S3/endpoint.mp3>,
Bucket: <S3> }
2018-11-15T22:44:09.072Z eb6dfbc7-e927-11e8-9a7e-c172e5d12174 returning to main from writing
END RequestId: eb6dfbc7-e927-11e8-9a7e-c172e5d12174
REPORT RequestId: eb6dfbc7-e927-11e8-9a7e-c172e5d12174 Duration: 18536.93 ms Billed Duration: 18600 ms Memory Size: 192 MB Max Memory Used: 107 MB

Here's a similar question from a user who reported something similar via Lambda with Python.
The accepted answer mentions a fix by explicitly ignoring STDIN for the subprocess. Perhaps you can try something similar with Node's child_process.spawn and options.stdio? Check out the child_process.spawn option docs for more info.
Also, have you seen this very comprehensive blog post Building a Media Transcoder with Exodus, FFmpeg, and AWS Lambda? That post covers a solution built with JS that might also be helpful in pointing you in the right direction.

Related

Not hearing any audio from ONVIF audio backchannel

I'm trying to write a small program using node-JS and ffmpeg to test the audio backchannel functionality of my Hikvision DS-2CD2145FWD-IS IP camera. I'm using a lightgly modified version of the rtsp-client libraray (so I can add in the "Require:www.onvif.org/ver20/backchannel" header) to sent up the stream, and then ffmpeg to actually stream the audio.
The problem is after I have sent the play request (to which I get a 200/OK response) and then start playing the audio I want to stream, I'm not hearing anything coming out of the speaker connected to my camera, and a few seconds after trying to start playing the audio the rtsp connection resets. I'm pretty sure I've encoded the audio correctly (8000Hz, 16bit, PCM), and I can see from the response to the describe message that the camera definitely supports this feature.
Here is my code
const RTSPClient = require('rtsp-client');
const { exec } = require("child_process");
var client;
var session;
async function shutdown()
{
console.log("Doing shutdown now");
const tear = await client.teardown();
console.log("---- teardown ----");
console.log(tear);
}
function setup()
{
//Create client
client = new RTSPClient();
client.on("error", function(e, err){
console.log("***GOT ERROR:", err);
setup();
})
//Connect to url
client.connect("rtsp://192.168.0.41");
const headers = {"Require" : "www.onvif.org/ver20/backchannel"};
client.addExtraHeaders(headers);
client.authenticate("admin","changeme1");
if(session)
{
console.log("Re suing old session " + session);
client.setSession(session);
}
}
async function start()
{
setup();
//Get options
const options = await client.options();
//Describe
const describe = await client.describe();
console.log("---- DESC ----");
console.log(describe.body.plain);
//Dump SDP
const parts = describe.body.plain.split("\r\n");
var isSend = false;
var controlUrl = false;
for(i in parts)
{
const p = parts[i];
if(isSend && 0 == p.indexOf("a=control:"))
{
controlUrl = p.split(":").splice(1).join(":");
break;
}
else if(p == "a=sendonly")
{
isSend = true;
}
else if (p == "a=recvonly")
{
isSend = false;
}
}
if(controlUrl === false)
{
console.log("no backchannel url");
}
console.log("Backchannel control url = " + controlUrl);
const set = await client.setup(controlUrl, "RTP/AVP");
console.log("---- SETUP ----")
console.log(set);
port = 0
ssrc = "0000"
for(i in set.headers)
{
if("Session" == set.headers[i].name)
{
session = set.headers[i].values[0].value.split(";")[0];
console.log("Session:" + session);
client.setSession(session);
}
else if ("Transport" == set.headers[i].name)
{
console.log("Transport:", set.headers[i].values);
var transParts = set.headers[i].values[0].value.split(";");
for(i=0; i< transParts.length;i++)
{
if(transParts[i].indexOf("server_port=") ==0)
{
port = transParts[i].split("=")[1].split("-")[0];
}
else if(transParts[i].indexOf("ssrc=") ==0)
{
ssrc = transParts[i].split("=")[1].split("-")[0];
}
}
}
}
console.log("Got port:" + port);
console.log("Got ssrc:" + ssrc);
ssrcInt = parseInt(ssrc, 16);
console.log("Got ssrc(dec)" + ssrcInt);
const start = await client.play().catch(function(err){ console.log("Got error ", err)});
console.log("---- play ----");
console.log(start);
const ffmpegCmd = "ffmpeg -re -i ./stt.1073.8000.wav -c:a copy -f rtp -ssrc " + ssrcInt + " -sdp_file ./out.sdp rtp://192.168.0.41:" + port;
console.log("Running ffmpeg Command " + ffmpegCmd);
exec(ffmpegCmd, (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
}
console.log(`stdout: ${stdout}`);
shutdown();
});
}
start();
And here is the output.
---- DESC ----
v=0
o=- 3714769719012 3714769719012 IN IP4 192.168.0.41
s=Media Presentation
e=NONE
b=AS:5100
t=0 0
a=control:rtsp://192.168.0.41/
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:5000
a=recvonly
a=x-dimensions:1280,720
a=control:rtsp://192.168.0.41/trackID=1
a=rtpmap:96 H264/90000
a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z01AH42NQCgC3/gLcBAQFAAAD6AAAw1DoYA9MAANWfrvLjQwB6YAAas/XeXCgA==,aO44gA==
m=audio 0 RTP/AVP 0 102
a=rtpmap:102 G726/8000
c=IN IP4 0.0.0.0
b=AS:50
a=sendonly
a=control:rtsp://192.168.0.41/trackID=4
a=rtpmap:0 PCMU/8000
a=Media_header:MEDIAINFO=494D4B48010300000400000100000000000000000000000000000000000000000000000000000000;
a=appversion:1.0
Backchannel control url = rtsp://192.168.0.41/trackID=4
---- SETUP ----
{
protocolVersion: 'RTSP/1.0',
statusCode: 200,
statusMessage: 'OK',
messageSize: 172,
headersSize: 145,
bodySize: 0,
headers: [
{ name: 'CSeq', values: [Array] },
{ name: 'Session', values: [Array] },
{ name: 'Transport', values: [Array] },
{ name: 'Date', values: [Array] }
]
}
Session:818031296
Transport: [
{ value: 'RTP/AVP;server_port=8342-8343;ssrc=40a54b6c;mode="play"' }
]
Got port:8342
Got ssrc:40a54b6c
Got ssrc(dec)1084574572
---- play ----
{
protocolVersion: 'RTSP/1.0',
statusCode: 200,
statusMessage: 'OK',
messageSize: 105,
headersSize: 78,
bodySize: 0,
headers: [
{ name: 'CSeq', values: [Array] },
{ name: 'Session', values: [Array] },
{ name: 'RTP-Info', values: [] },
{ name: 'Date', values: [Array] }
]
}
Running ffmpeg Command ffmpeg -re -i ./stt.1073.8000.wav -c:a copy -f rtp -ssrc 1084574572 -sdp_file ./out.sdp rtp://192.168.0.41:8342
***GOT ERROR: Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:209:20) {
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read'
}
Re suing old session 818031296
stderr: ffmpeg version 4.4.1-3ubuntu5 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 11 (Ubuntu 11.2.0-18ubuntu1)
configuration: --prefix=/usr --extra-version=3ubuntu5 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
libavutil 56. 70.100 / 56. 70.100
libavcodec 58.134.100 / 58.134.100
libavformat 58. 76.100 / 58. 76.100
libavdevice 58. 13.100 / 58. 13.100
libavfilter 7.110.100 / 7.110.100
libswscale 5. 9.100 / 5. 9.100
libswresample 3. 9.100 / 3. 9.100
libpostproc 55. 9.100 / 55. 9.100
Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from './stt.1073.8000.wav':
Metadata:
encoder : Lavf58.76.100
Duration: 00:01:01.05, bitrate: 128 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 8000 Hz, mono, s16, 128 kb/s
Output #0, rtp, to 'rtp://192.168.0.41:8342':
Metadata:
encoder : Lavf58.76.100
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 8000 Hz, mono, s16, 128 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
size= 963kB time=00:01:00.92 bitrate= 129.4kbits/s speed= 1x
video:0kB audio:954kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.913954%
stdout:
Doing shutdown now
Stopping 818031296 on rtsp://192.168.0.41
---- teardown ----
{
protocolVersion: 'RTSP/1.0',
statusCode: 454,
statusMessage: 'Session Not Found',
messageSize: 357,
headersSize: 68,
bodySize: 249,
headers: [
{ name: 'CSeq', values: [Array] },
{ name: 'Session', values: [Array] },
{ name: 'Date', values: [Array] }
],
body: {
plain: 'RTSP/1.0 401 Unauthorized\r\n' +
'CSeq: 1\r\n' +
'Session: 0\r\n' +
'Date: Thu, Feb 12 1970 23:53:50 GMT\r\n' +
'WWW-Authenticate: Digest realm="IP Camera(F2585)", nonce="98dd3d29b86a40ee2ed1cc9c74b54ed0", stale="FALSE"\r\n' +
'Date: Thu, Feb 12 1970 23:53:50 GMT\r\n' +
'\r\n'
}
}
An linux shows the file I'm trying to send as
$ file ./stt.1073.8000.wav
./stt.1073.8000.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 8000 Hz

ytdl-core no stream data

I am making a NodeJS Music bot for discord, and I suddenly encountered a problem. The bot properly joins the channel, lights up (indicating it is speaking), but then there's no audio. After trying to find the root cause of the problem, I believe it to be a problem with the ytdl() function from the ytdl-core module.
const stream = await ytdl(song.url, {
filter: 'audioonly',
type: 'opus',
highWaterMark: waterMark
});
Looking at the result of stream, I found this:
PassThrough {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 524288,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
...
Which meant that I am not getting any buffer/stream data. It is indeed playing, but because there's nothing-- there's only silence to be heard.
I tried using pipe() and it worked just fine, but I can't play it as it is through my Music Bot.
ytdl function is like synchronous function.
"ytdl-core": "^4.10.1"
const stream = await ytdl(song.url); pause code execution until ytdl finished downloading stream.
console.log("YTDL Start");
const stream = await ytdl(song.url, {
filter: 'audioonly',
type: 'opus',
highWaterMark: waterMark
});
console.log("Is it done?");
stream.on('close', () => {
console.log('Read stream closed');
});
stream.on('finish', () => {
console.log('Read stream Finished');
});

Duration of wav file saved in S3 using AWS Lambda

Objective
To calculate the duration of a wav file which is saved in S3 by AWS Lambda using node.js. I had to add ffmpeg and ffprobe executable inside a lambda layer (Downloaded linux-64 version from here). These files could be found in /opt folder on lambda file system.
What I have tried
I have been trying using ffprobe in numerous ways, but I get Invalid Data as error.
Here's one example
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
exports.handler = async function(event) {
let path = await load();
console.log(`Saved Path ${path}`);
ffmpeg.setFfmpegPath('/opt/ffmpeg');
ffmpeg.setFfprobePath("/opt/ffprobe");
let dur = await duration(path).catch(err => {
console.log(err);
})
console.log(dur);
}
function duration(path) {
return new Promise((resolve, reject) => {
ffmpeg(path).ffprobe(path, function(err, metadata) {
//console.dir(metadata); // all metadata
if (err) {
reject(err);
}
else {
resolve(metadata.format.duration);
}
});
})
}
async function listFiles(path) {
console.log('list files');
return new Promise((resolve, reject) => {
fs.readdir(path, (err, files) => {
if (err) {
console.error('Error in readdir');
reject(err);
}
else {
console.log('recieved files');
resolve(files);
}
});
});
}
async function load() {
return new Promise((resolve, reject) => {
let params = {
Key: 'Fanfare60.wav',
Bucket: 'samplevideosshamim'
};
console.log(`Getting s3 object : ${JSON.stringify(params)}`);
s3.getObject(params, (err, data) => {
if (err) {
console.error(err);
reject(err);
}
else if (data) {
console.log('Recieved Data');
let path = `/tmp/${params.Key}`;
console.log('Path: ' + path);
fs.writeFileSync(path, data.body);
resolve(path);
}
});
});
}
Error:
Error: ffprobe exited with code 1
ffprobe version 4.2.1-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2007-2019 the FFmpeg developers
built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-6 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gmp --enable-libgme --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libdav1d --enable-libxvid --enable-libzvbi --enable-libzimg
libavutil 56. 31.100 / 56. 31.100
libavcodec 58. 54.100 / 58. 54.100
libavformat 58. 29.100 / 58. 29.100
libavdevice 58. 8.100 / 58. 8.100
libavfilter 7. 57.100 / 7. 57.100
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
/tmp/Fanfare60.wav: Invalid data found when processing input
at ChildProcess.<anonymous> (/var/task/node_modules/fluent-ffmpeg/lib/ffprobe.js:233:22)
at ChildProcess.emit (events.js:314:20)
at ChildProcess.EventEmitter.emit (domain.js:483:12)
at Process.ChildProcess._handle.onexit (internal/child_process.js:276:12)
I am guessing it doesn't support wav format, but internet searches provide no proof of that.
A point to note here is, I was able to get the duration of a local file when I ran this code on my local machine, but I have a windows machine, so perhaps only linux executable of ffprobe has issue?
Possible Solutions I am looking for
Is there a way to specify format?
Can I use a different library (code example for the same)?
Any possible way to get duration of a wav file in the mentioned scenario (AWS Lambda NodeJS and S3 file (private file)?

Node-JS convert mp4 to m3u8 with FFMPEG : Unable to find a suitable output format for 'v:1,a:1"'

I am writing a server-side function to convert a mp4 file to m3u8, but there is an error with the differents video size. I want to have my video in differents sizes (4k UHD, 2k, 1080p, 720p...) but, with this line : "-var_stream_map", "'v:0,a:0 v:1,a:1'",, there is an error :
[NULL # 0x7fe9de00d800] Unable to find a suitable output format for 'v:1,a:1"'
v:1,a:1": Invalid argument
When I delete this line, all work, but I have just the v0 in 640x360 and not the v1 (960x540).
How can I bypass this error to have all the video sizes ?
const ffmpeg = require('fluent-ffmpeg');
var infs = new ffmpeg
infs.addInput(doc.data().url).outputOptions([
'-preset slow', '-g 48', '-sc_threshold 0',
'-map 0:0', '-map 0:1', '-map 0:0', '-map 0:1',
'-s:v:0 640x360', '-c:v:0 libx264', '-b:v:0 365k',
'-s:v:1 960x540', '-c:v:1 libx264', '-b:v:1 2000k',
"-var_stream_map", "'v:0,a:0 v:1,a:1'",
'-master_pl_name master.m3u8',
'-f hls', '-hls_time 6', '-hls_list_size 0',
'-hls_segment_filename fileSequence%d|v%v.ts',
'-max_muxing_queue_size 1024',
]).output('./video.m3u8')
.on('start', function (commandLine) {
console.log('Spawned Ffmpeg with command: ' + commandLine);
})
.on('error', function (err, stdout, stderr) {
console.log('An error occurred: ' + err.message, err, stderr);
})
.on('progress', function (progress) {
console.log('Processing: ' + progress.percent + '% done')
})
.on('end', function (err, stdout, stderr) {
console.log('Finished processing!' /*, err, stdout, stderr*/)
})
.run()
I also facing same problem which resolved by putting var_stream_map in another outputOption(option...).
infs.addInput(doc.data().url)
.outputOptions([option...])
.outputOption('-var_stream_map', 'v:0,a:0 v:1,a:1') ...

how can I execute "ffmpeg -video_size 1024x768 -framerate 25 -f x11grab -i :0.0+100,200 output.mp4" command in nodejs

As I am new to Node and started working on cross platform desktop application using NWjs please assist me how to execute "ffmpeg -video_size 1024x768 -framerate 25 -f x11grab -i :0.0+100,200 output.mp4" command in nodejs.
you might want to look at the child_process module which is included in nodejs by default.
Here's a code example from the documentation using ls to list files in a directory:
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});

Resources