Video - extract image from DASH m4s file using ffmpeg - node.js

I'm trying to create a thumbnail from a dash stream m4s file.
I have the mpd, init.mp4 file and the m4s files.
I have the code using nodeJS ffmpeg package that extracts image from an mp4 file:
try {
var process = new ffmpeg('video.mp4');
process.then(function (video) {
// Callback mode
video.fnExtractFrameToJPG('C:\\files\\nodejs', {
start_time: `1:50:30`,
frame_rate : 1,
file_name : 'my_frame_%t_%s'
}, function (error, files) {
if (!error)
console.log('Frames: ' + files);
});
}, function (err) {
console.log('Error: ' + err);
});
} catch (e) {
console.log(e.code);
console.log(e.msg);
}
But because i'm reading my files from a dash-stream i'm getting an m4s files.
I've tried to convert the m4s format into mp4 and then use the code above, but the ffmpeg( fluent-ffmpeg to be exact) is returning an error message
an error occured: ffmpeg exited with code 1:
C:\files\nodejs\testFiles\000000.m4s: Invalid data found when
processing input
The code i used to convert is:
var proc = new fluent({source: "C:\\files\\nodejs\\testFiles\\000000.m4s",
nolog: true})
//useless i think - not working
//proc.setFfmpegPath("C:\\files\\ffmpeg-20170620-ae6f6d4-win64-static\\bin")
proc.withSize('50%').withFps(24).toFormat('mp4')
.on('end', function(){
console.log('file has been converted successfully');
})
.on('error', function(err){
console.log('an error occured: ' + err.message);
})
.saveToFile("C:\\files\\nodejs\\new.mp4");
Is it possible to convert a single m4s file to mp4?
If not, what is the right way of converting m4s to mp4 using ffmpeg with nodejs?
I couldn't find any reference for that, but if it is possible to extract an image directly from the m4s file i think it will solve the problem faster.
It is possible to use this site to download all the *.m4s files, mpd and init.mp4 files using the network section (f12 in Chrome browser) and check the code.

Related

How to convert Uint8Array video to frames in nodejs

I want to be able to extract jpegs from a Uint8 array containing the data for a mpeg or avi video.
The module ffmpeg has the function fnExtractFrameToJPG but it only accepts a filename pointing to the video file. I want to be able to extract the frames from the UInt8Array.
One way to do it is to write the UInt8Array to a tmp file and then use the tmp file with ffmpeg to extract the frames:
const tmp = require("tmp");
const ffmpeg_ = require("ffmpeg");
function convert_images(video_bytes_array){
var tmpobj = tmp.fileSync({ postfix: '.avi' })
fs.writeFileSync(tmpobj.name, video_bytes_array);
try {
var process = new ffmpeg(tmpobj.name);
console.log(tmpobj.name)
process.then(function (video) {
// Callback mode
video.fnExtractFrameToJPG('./', { // make sure you defined the directory where you want to save the images
frame_rate : 1,
number : 10,
file_name : 'my_frame_%t_%s'
}, function (error, files) {
if (!error)
tmpobj.removeCallback();
});
});
} catch (e) {
console.log(e.code);
console.log(e.msg);
}
}
Another possibitlity is to use opencv after you save the UInt8Array to a tmp file. Another solution is to use stream and ffmpeg-fluent which would not require using tmp files.

merge multiple videos to a single .mp4 files using fluent-ffmpeg

Version information
fluent-ffmpeg version: 2.1.2
ffmpeg version:4
OS:linux mint
Code to reproduce
var fluent_ffmpeg = require("fluent-ffmpeg");
var mergedVideo = fluent_ffmpeg();
mergedVideo
.mergeAdd('./Video1.mp4')
.mergeAdd('./Video2.mp4')
// .inputOptions(['-loglevel error','-hwaccel vdpau'])
// .outputOptions('-c:v h264_nvenc')
.on('error', function(err) {
console.log('Error ' + err.message);
})
.on('end', function() {
console.log('Finished!');
})
.mergeToFile('./mergedVideo8.mp4', '/tmp');
When I run this code, then I get conversion failed error.
Observed results
Error ffmpeg exited with code 1: Error reinitializing filters!
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #3:0
Conversion failed!
I have tried the same conversion using the command line:
ffmpeg -f concat -i textfile -c copy -fflags +genpts merged8.mp4
Where textfile has the following content-
file 'Video1.mp4'
file 'Video2.mp4'
And I was able to concatenate the video file. But I want to get the same result using fluent-ffmpeg.

HLS from node to iOS app

I created a API in node that you can upload a video (.mp4, .avi, etc). Then, the video is request by a iOS app in swift.
I would like to use HTTP Live streaming from the app. Can you help me how can I transform the video file to chunks .ts and generate the playlist file (m3u8) to be consumed by the app?
This is the correct flow?
What it's the best solution?
Thanks!
Finally I have a solution, I use fluent-ffmpeg like this :
var ffmpeg = require('fluent-ffmpeg');
ffmpeg(video, { timeout: 432000 })
.addOption('-level', 3.0)
// size
.addOption('-s','640x360')
// start_number
.addOption('-start_number', 0)
// set hls segments time
.addOption('-hls_time', 10)
// include all the segments in the list
.addOption('-hls_list_size', 0)
// format -f
.format('hls')
// setup event handlers
.on('start', function(cmd) {
console.log('Started ' + cmd);
})
.on('error', function(err) {
logger.error('an error happened: ' + err.message);
})
.on('end', function() {
logger.debug('File has been converted succesfully');
})
.save(outputDir)
ffmpeg comes with HLS streaming capability.
ffmpeg -i "input" output.m3u8
For more information visit: ffmpeg hls documentation

JPEG File Encoding and writeFile in Node JS

I'm using http.request to download JPEG file. I am then using fs.writeFile to try to write the JPEG file out to the hard drive.
None of my JPEG files can be opened, they all show an error (but they do have a file size). I have tried all of the different encodings with fs.writeFile.
What am I messing up in this process?
Here's what the working one is showing when viewing it raw:
And here is what the bad one using fs.writeFile is showing:
Figured it out, needed to use res.setEncoding('binary'); on my http.request.
Thank you, looking to the previous response, I was able to save de media correctly:
fs.writeFile(
filepath + fileName + extension,
mediaReceived, // to use with writeFile
{ encoding: "binary" }, // to use with writeFile ***************WORKING
(err) => {
if (err) {
console.log("An error ocurred while writing the media file.");
return console.log(err);
}
}
);

fluent-ffmpeg thumbnail creation error

i try to create a video thumbnail with fluent-ffmpeg here is my code
var ffmpeg = require('fluent-ffmpeg');
exports.thumbnail = function(){
var proc = new ffmpeg({ source: 'Video/express2.mp4',nolog: true })
.withSize('150x100')
.takeScreenshots({ count: 1, timemarks: [ '00:00:02.000' ] }, 'Video/', function(err, filenames) {
console.log(filenames);
console.log('screenshots were saved');
});
}
but i keep getting this error
"mate data contains no duration, aborting screenshot creation"
any idea why,
by the way am on windows, and i put the ffmpeg folder in c/ffmpeg ,and i added the ffmpeg/bin in to my environment varableļ¼Œ i dont know if fluent-ffmpeg need to know the path of ffmpeg,but i can successfully create a thumbnail with the code below
exec("C:/ffmpeg/bin/ffmpeg -i Video/" + Name + " -ss 00:01:00.00 -r 1 -an -vframes 1 -s 300x200 -f mjpeg Video/" + Name + ".jpg")
please help me!!!
I think the issue can be caused by the .withSize('...') method call.
The doc says:
It doesn't interract well with filters. In particular, don't use the size() method to resize thumbnails, use the size option instead.
And the size() method is an alias of withSize().
Also - but this is not the problem in your case - you don't need to set either the count and the timemarks at the same time. The doc says:
count is ignored when timemarks or timestamps is specified.
Then you probably could solve with:
const ffmpeg = require('fluent-ffmpeg');
exports.thumbnail = function(){
const proc = new ffmpeg({ source: 'Video/express2.mp4',nolog: true })
.takeScreenshots({ timemarks: [ '00:00:02.000' ], size: '150x100' }, 'Video/', function(err, filenames) {
console.log(filenames);
console.log('screenshots were saved');
});
}
Have a look at the doc:
https://github.com/fluent-ffmpeg/node-fluent-ffmpeg#screenshotsoptions-dirname-generate-thumbnails
FFmpeg needs to know the duration of a video file, while most videos have this information in the file header some file don't, mostly raw videos like a raw H.264 stream.
A simple solution could be to remux the video prior to take the snapshot, the FFmpeg 0.5 command for this task it's quite simple:
ffmpeg -i input.m4v -acodec copy -vcodec copy output.m4v
This command tells FFmpeg to read the "input.m4v" file, to use the same audio encoder and video encoder (no encoding at all) for the output, and to output the data into the file output.m4v.
FFmpeg automatically adds all extra metadata/header information needed to take the snapshot later.
Try this code to create thumbnails from Video
// You have to Install Below packages First
var ffmpegPath = require('#ffmpeg-installer/ffmpeg').path;
var ffprobePath = require('#ffprobe-installer/ffprobe').path;
var ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath(ffmpegPath);
ffmpeg.setFfprobePath(ffprobePath);
var proc = ffmpeg(sourceFilePath)
.on('filenames', function(filenames) {
console.log('screenshots are ' + filenames.join(', '));
})
.on('end', function() {
console.log('screenshots were saved');
})
.on('error', function(err) {
console.log('an error happened: ' + err.message);
})
// take 1 screenshots at predefined timemarks and size
.takeScreenshots({ count: 1, timemarks: [ '00:00:01.000' ], size: '200x200' }, "Video/");

Resources