Convert mp4 or Avi to m3u8 in pure node js - javascript

I am searching a way to convert a mp4 or an .avi to .m3u8 in pure node js (firebase cloud function). Do you have ideas ?
Thank's, but I tried that :
const ffmpegInstaller = require('#ffmpeg-installer/ffmpeg');
const ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath(ffmpegInstaller.path);
const ffmpeg_static = require('ffmpeg-static');
var cmd = ffmpeg('./flir_20191202T174341.mp4')
.setFfmpegPath(ffmpeg_static.path)
.videoBitrate(1024)
.videoCodec('divx')
.format('m3u8')
.on('end', () => {
// ...
})
.on('error', err => {
console.error(err);
})
.save('./file-out.m3u8');
console.log('Hello !');
console.log(cmd);
And I have this error :
Error: Cannot find ffmpeg
at /Users/jeremy/Dev/ssv-api/node_modules/fluent-ffmpeg/lib/processor.js:136:22
at FfmpegCommand.proto._getFfmpegPath (/Users/jeremy/Dev/ssv-api/node_modules/fluent-ffmpeg/lib/capabilities.js:90:14)
at FfmpegCommand.proto._spawnFfmpeg (/Users/jeremy/Dev/ssv-api/node_modules/fluent-ffmpeg/lib/processor.js:132:10)
at FfmpegCommand.proto.availableFormats.proto.getAvailableFormats (/Users/jeremy/Dev/ssv-api/node_modules/fluent-ffmpeg/lib/capabilities.js:517:10)
at /Users/jeremy/Dev/ssv-api/node_modules/fluent-ffmpeg/lib/capabilities.js:568:14
at nextTask (/Users/jeremy/Dev/ssv-api/node_modules/async/dist/async.js:4576:27)
at Object.waterfall (/Users/jeremy/Dev/ssv-api/node_modules/async/dist/async.js:4587:9)
at Object.awaitable [as waterfall] (/Users/jeremy/Dev/ssv-api/node_modules/async/dist/async.js:208:32)
at FfmpegCommand.proto._checkCapabilities (/Users/jeremy/Dev/ssv-api/node_modules/fluent-ffmpeg/lib/capabilities.js:565:11)
at /Users/jeremy/Dev/ssv-api/node_modules/fluent-ffmpeg/lib/processor.js:298:14
Any ideas ?
Thanks in advance.
Jérémy.

Found this answer: https://stackoverflow.com/a/42777596/8006046. It shows how you can run FFmpeg in the firebase cloud. You can replace 'path_or_readstream.mp4' with either the path to the file you want to convert, or, which is more probable in a cloud function, you could pass the readable stream with the file you want to convert.
const ffmpeg = require('fluent-ffmpeg');
const ffmpeg_static = require('ffmpeg-static');
var cmd = ffmpeg('path_or_readstream.mp4')
.setFfmpegPath(ffmpeg_static.path)
.videoBitrate(1024)
.videoCodec('divx')
.format('m3u8')
.on('end', () => {
// ...
})
.on('error', err => {
console.error(err);
})
.save('/tmp/file-out.m3u8');

Related

Spawning Java File

How can i spawn a java file while receiving stdout output?
I am trying to start a minecraft server file using child_process' spawn function, and attempting to get the output thats getting sent.
Heres what i've tried
var childP = require("child_process")
var server = childP.spawn("java", ["-jar", "Launch.jar", "nogui"])
server.on("spawn", () => {
console.log("Server started")
})
server.on("message", (message) => {
console.log(message)
})
server.on("error", (err) => {
console.log(err)
})
server.on("disconnect", () => {
console.log("Server disconnected");
})
server.on("exit", (code) => {
console.log(`Server exited with code ${code}`)
})
Easily done by just doing server.stdout.on("data"), should've looked more into the spawn event before asking the question :p
var childP = require("child_process")
var server = childP.spawn("java", ["-jar", "Launch.jar", "nogui"])
server.stdout.on("data", (data) => {
console.log(data.toString().trim())
})
To spawn a Java file and receive its standard output using the child_process module in Node.js, you can use the spawn function as follows:
`const { spawn } = require('child_process');
const javaProcess = spawn('java', ['-jar', 'minecraft_server.jar']);
javaProcess.stdout.on('data', (data) => {
console.log(stdout: ${data});
});
javaProcess.stderr.on('data', (data) => {
console.error(stderr: ${data});
});
javaProcess.on('close', (code) => {
console.log(child process exited with code ${code});
});`

ffmpeg error when generating screenshots from videos in Node js

I have a function that is supposed to generate a thumbnail from a mp4 file with fluent-ffmpeg in Node, and store it as a jpg file.
In my first function I tried to solve this by creating a stream of the external url:
const got = require('got');
const ffmpeg = require('fluent-ffmpeg');
const ffmpeg_static = require('ffmpeg-static');
const fs = require('fs');
function generateThumbnail() {
const url = 'https://gateway.pinata.cloud/ipfs/QmUWD7dewFZB9bFamyvR5uEUpX1FEkjuoZYzhUZBm8U4mT/nft.mp4'
const request = await got.stream(url);
function asyncThumbnail() {
return new Promise((resolve, reject) => {
ffmpeg(request)
.setFfmpegPath(ffmpeg_static)
.screenshots({
size: '?x512',
count: 1,
timemarks: ['3'],
filename: `filename.jpg`,
folder: __dirname + '/../ffmpeg/output',
})
.on('end', function () {
resolve();
console.log('Thumbnail created');
})
.on('error', (err) => {
return reject(new Error(err));
});
});
}
}
A thumbnail is generated for a lot of videos I have tested, but not for this video (the video loads a bit slow because it's hosted on IPFS, but it doesn't have anything to do with my error), which returns the following error:
ffmpeg exited with code 1: pipe:0: Invalid data found when processing input
Cannot determine format of input stream 0:0 after EOF
After reading that ffmpeg is supposed to work better if I download a video locally before converting it (link), I changed my code to do that:
const got = require('got');
const ffmpeg = require('fluent-ffmpeg');
const ffmpeg_static = require('ffmpeg-static');
const fs = require('fs');
function generateThumbnail() {
const url = 'https://gateway.pinata.cloud/ipfs/QmUWD7dewFZB9bFamyvR5uEUpX1FEkjuoZYzhUZBm8U4mT/nft.mp4'
const request = await got.stream(url);
await request.pipe(
fs.createWriteStream(
__dirname + `/../ffmpeg/input/fileName.mp4`
)
);
function asyncThumbnail() {
return new Promise((resolve, reject) => {
ffmpeg(__dirname + `/../ffmpeg/input/filename.mp4`)
.setFfmpegPath(ffmpeg_static)
.screenshots({
size: '?x512',
count: 1,
timemarks: ['3'],
filename: `filename.jpg`,
folder: __dirname + '/../ffmpeg/output',
})
.on('end', function () {
resolve();
console.log('Thumbnail created');
})
.on('error', (err) => {
return reject(new Error(err));
});
});
}
await asyncThumbnail();
}
This gives me a similar error, but for every video I have tested, without generating a single thumbnail:
ffmpeg exited with code 1: C:\path\src/../ffmpeg/input/baroque-fndnft-945.mp4: Invalid data found when processing input
Running the last function with fs.createReadStream() as the ffmpeg() input istead gives me this error:
ffmpeg exited with code 1: pipe:0: Invalid data found when processing input

Discord.js record MP3 of voice channel?

I'm trying to make a record command in my discord.js bot. My code so far is:
const channel = message.member.voice.channel;
if(!channel) return message.channel.send('Join a VC first!');
const connection = await channel.join();
const receiver = connection.receiver.createStream(message.member, {
mode: "pcm",
end: "silence"
});
const writer = receiver.pipe(fs.createWriteStream('./recording.pcm'));
writer.on('finish', () => {
channel.leave();
message.channel.send('It went quiet, so I left...');
});
That saves recording.pcm to my PC. If I try to open the file in windows media player or anything, it doesn't recognise the file type. I used Audacity import raw audio function, and I could hear my recording, so I know it works. However, giving a user that type of file is very inconvenient. How can I turn this .pcm file into a .wav or .mp3 in node.js? Thanks!
You could use ffmpeg - npm i ffmpeg
const ffmpeg = require('ffmpeg');
try {
var process = new ffmpeg('path/to/pcm/file');
process.then(function (audio) {
audio.fnExtractSoundToMP3('path/to/new/file.mp3', function (error, file) {
if (!error) console.log('Audio File: ' + file);
});
}, function (err) {
console.log('Error: ' + err);
});
} catch (e) {
console.log(e);
}
This should save the new mp3 file to the specified location.

Upload Image to Cloud Storage from Cloud Function Trigger

I'm currently seeking some help with my Cloud Function that is triggered by a Cloud Storage Upload. It checks if the file is a Video, if so we process this Video through ffmpeg to extract a single frame to be used for a Poster Image later.
It all seems to work except my upload of the image back to Cloud Storage doesn't work. At this point where my Cloud Function is it doesn't produce any errors at all, so i have no clue why the upload of the image to Cloud Storage is not working. I would greatly appreciate if anyone with the experience can review my Cloud Function below and provide some insight into why it's not working. Please advice if possible!! Thank you!!!! ^_^
Note: Screenshot of Cloud Function Log is provided below the code snippet
const admin = require('firebase-admin'); // Firebase Admin SDK
const functions = require('firebase-functions'); // Firebase Cloud Functions
const gcs = require('#google-cloud/storage')(); // Cloud Storage Node.js Client
const path = require('path'); // Node.js file and directory utility
const os = require('os'); // Node.js operating system-related utility
const fs = require('fs'); // Node.js file system API
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('#ffmpeg-installer/ffmpeg').path;
const ffprobePath = require('#ffprobe-installer/ffprobe').path;
// Initialize Firebase Admin
admin.initializeApp(functions.config().firebase);
// Listen for changes in Cloud Storage bucket
exports.storageFunction = functions.storage.object()
.onChange((event) => {
const file = event.data; // The Storage object.
const fileBucket = file.bucket; // The Storage bucket that contains the file.
const filePath = file.name; // File path in the bucket.
const fileName = path.basename(filePath); // Get the file name.
const fileType = file.contentType; // File content type.
if (!fileType.startsWith('video/')) {
return;
}
const bucket = gcs.bucket(fileBucket);
const tempFilePath = path.join(os.tmpdir(), fileName);
const tempFolderPath = os.tmpdir();
// Download video to temp directory
return bucket.file(filePath).download({
destination: tempFilePath
}).then(() => {
console.log('Video downloaded locally to', tempFilePath);
// Generate screenshot from video
ffmpeg(tempFilePath)
.setFfmpegPath(ffmpegPath)
.setFfprobePath(ffprobePath)
.on('filenames', (filenames) => {
console.log(`Will generate ${filenames}`);
})
.on('error', (err) => {
console.log(`An error occurred: ${err.message}`);
})
.on('end', () => {
console.log(`Output image created at ${tempFilePath}`);
const targetTempFileName = `${fileName}.png`;
const targetFilePath = path.join(path.dirname(filePath), targetTempFileName);
console.log(targetTempFileName);
console.log(targetFilePath);
// Uploading the image.
return bucket.upload(tempFilePath, { destination: targetFilePath })
.then(() => {
console.log('Output image uploaded to', filePath);
})
.catch((err) => {
console.log(err.message);
});
})
.screenshots({
count: 1,
folder: tempFolderPath
});
});
});
Cloud Function Log
It looks like you're trying to return a promise from the ffmpeg callback API:
.on('end', () => {
return bucket.upload(tempFilePath, { destination: targetFilePath })
.then(...)
})
I don't know the ffmpeg API, but I'm almost certain that will not cause the function to wait for the upload to complete. Instead, you need to return a promise from directly from your function that resolves only after all the async work is complete.
If the last item of work is inside a callback, and you need to wait for that, you can wrap the entire thing into a new promise and manually resolve it at the right time. In pseudocode:
return new Promise((resolve, reject) => {
// ffmpeg stuff here...
.on('end', () => {
// the last bit of work here...
bucket.upload(...)
.then(() => { resolve() })
})
})
Notice how the resolve method provided by the new promise is being called to indicate when that promise should itself resolve.

Do I need the IPFS daemon to upload files from a browser?

I'm working on this project using IPFS and I'm trying to create a website that allows users to upload files directly from their browser to IPFS. My goal was that the website would be a front-end website but whenever I add a file to IPFS and I check it's hash on https://gateway.ipfs.io/ipfs/hash-here nothing happens, which made me think that the files are probably not getting uploaded to IPFS because I'm not running it on my local machine. Is this correct?
const Buffer = require('safe-buffer').Buffer;
export default function uploadFiles(node, files) {
let reader = new FileReader();
reader.onloadend = () => {
let byteData = reader.result.split('base64,')[1];
let fileData = Buffer.from(byteData);
node.files.add(fileData, (err, res) => {
if (err) {
throw err
}
let hash = res[0].hash
console.log(hash); ///////prints a hash that isnt visible on
//gateway
node.files.cat(hash, (err, res) => {
if (err) {
throw err
}
let data = ''
res.on('data', (d) => {
data = data + d
})
res.on('end', () => {
// console.log(data);
// console.log(atob(data));
})
})
});
}
reader.readAsDataURL(files['0']);
};
Are you running a js-ipfs node in your browser? Did you get the chance to look at the examples in the examples folder in js-ipfs repo? Url here: https://github.com/ipfs/js-ipfs/tree/master/examples
If you add a file to your node and the node is on, the IPFS gateway node will be able to find the content from your browser node.

Categories