New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

js-ffmpeg

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

js-ffmpeg - npm Package Compare versions

Comparing version 0.0.1 to 0.0.4

src/ffmpeg-volume-detect.js

4

index.js

@@ -14,4 +14,6 @@ Scoped = require("betajs-scoped/dist/scoped.js");

ffmpeg_simple: require(__dirname + "/src/ffmpeg-simple.js").ffmpeg_simple
ffmpeg_simple: require(__dirname + "/src/ffmpeg-simple.js").ffmpeg_simple,
ffmpeg_volume_detect: require(__dirname + "/src/ffmpeg-volume-detect.js").ffmpeg_volume_detect
};
{
"name": "js-ffmpeg",
"description": "JS FFMpeg",
"version": "0.0.1",
"version": "0.0.4",
"author": "Ziggeo",

@@ -6,0 +6,0 @@ "repository": "https://github.com/jsonize/jsffmpeg",

@@ -1,8 +0,6 @@

# js-ffmpeg 0.0.1
# js-ffmpeg 0.0.4
This is a simple wrapper for FFMPEG and FFPROBE.
This is very much work in progress.
## Getting Started

@@ -39,3 +37,3 @@

// raw call of ffprobe (source(s), arguments, target, progress callback)
// raw call of ffmpeg (source(s), arguments, target, progress callback)
ffmpeg.ffmpeg('video.mp4', [...], 'output.mp4', function (progress) {

@@ -48,2 +46,19 @@ console.log(progress);

});
// improved and simplified call of ffmpeg (source(s), arguments, target, progress callback)
ffmpeg.ffmpeg('video.mp4', {
width: 640,
height: 360,
auto_rotate: true,
ratio_strategy: "fixed",
shrink_strategy: "crop",
mixed_strategy: "crop-pad",
stretch_strategy: "pad"
}, 'output.mp4', function (progress) {
console.log(progress);
}).success(function (json) {
console.log(json);
}).error(function (error) {
console.log(error);
});
```

@@ -23,3 +23,4 @@ Scoped.require([

passes: 2,
modulus: 2
modulus: 2,
params: "-pix_fmt yuv420p"
},

@@ -26,0 +27,0 @@ "ogg": {

@@ -9,2 +9,3 @@ Scoped.require([

var ffprobe_simple = require(__dirname + "/ffprobe-simple.js");
var ffmpeg_volume_detect = require(__dirname + "/ffmpeg-volume-detect.js");
var helpers = require(__dirname + "/ffmpeg-helpers.js");

@@ -18,23 +19,56 @@

files = [files];
options = Objs.extend({
output_type: "video", // video, audio, image
synchronize: true,
framerate: 25, // null
framerate_gop: 250,
image_percentage: null,
image_position: null,
time_limit: null,
time_start: 0,
time_end: null,
video_map: null, //0,1,2,...
audio_map: null, //0,1,2
video_profile: "baseline",
faststart: true,
video_format: "mp4",
audio_bit_rate: null,
video_bit_rate: null,
normalize_audio: false,
width: null,
height: null,
auto_rotate: true,
ratio_strategy: "fixed", // "shrink", "stretch"
shrink_strategy: "shrink-pad", // "crop", "shrink-crop"
stretch_strategy: "pad", // "stretch-pad", "stretch-crop"
mixed_strategy: "shrink-pad", // "stretch-crop", "crop-pad"
watermark: null,
watermark_size: 0.25,
watermark_x: 0.95,
watermark_y: 0.95
}, options);
return Promise.and(files.map(function (file) {
var promises = files.map(function (file) {
return ffprobe_simple.ffprobe_simple(file);
})).mapSuccess(function (infos) {
options = Objs.extend({
output_type: "video", // audio, image
synchronize: true,
framerate: 25, // null
framerate_gop: 250,
image_percentage: null,
image_position: null,
time_limit: null,
time_start: 0,
time_end: null,
video_map: null, //0,1,2,...
audio_map: null, //0,1,2
video_profile: "baseline",
faststart: true,
video_format: "mp4"
}, options);
});
if (options.normalize_audio)
promises.push(ffmpeg_volume_detect.ffmpeg_volume_detect(files[options.audio_map || 0]));
if (options.watermark)
promises.push(ffprobe_simple.ffprobe_simple(options.watermark));
return Promise.and(promises).mapSuccess(function (infos) {
var watermarkInfo = null;
if (options.watermark)
watermarkInfo = infos.pop();
var audioNormalizationInfo = null;
if (options.normalize_audio)
audioNormalizationInfo = infos.pop();
var passes = 1;

@@ -69,3 +103,13 @@

/*
*
* Audio Normalization?
*
*/
if (audioNormalizationInfo) {
args.push("-af");
args.push("volume=" + (-audioNormalizationInfo.max_volume) + "dB");
}
/*

@@ -83,22 +127,167 @@ *

/*
*
* Which sizing should be used?
*
*/
var videoInfo = infos[0].video;
var audioInfo = infos[1] ? infos[1].audio || infos[0].audio : infos[0].audio;
var sourceWidth = 0;
var sourceHeight = 0;
var targetWidth = 0;
var targetHeight = 0;
//try {
if (options.output_type !== 'audio') {
// TODO: Rotation, Resize, Pad, Crop
var source = infos[0];
sourceWidth = source.video.rotated_width;
sourceHeight = source.video.rotated_height;
var sourceRatio = sourceWidth / sourceHeight;
targetWidth = sourceWidth;
targetHeight = sourceHeight;
var targetRatio = sourceRatio;
var ratioSourceTarget = 0;
// '-vf' 'transpose=1' '-metadata:s:v:0' 'rotate=0'
// '-vf' 'transpose=1' '-metadata:s:v:0' 'rotate=0' '-s' '270x480'
}
/*
*
* Which sizing should be used?
*
*/
// Step 1: Fix Rotation
if (options.auto_rotate && source.video.rotation) {
if (source.video.rotation % 180 === 90) {
args.push("-vf");
args.push("transpose=" + (source.video.rotation === 90 ? 1 : 2));
}
if (source.video.otation >= 180) {
args.push("-vf");
args.push("hflip,vflip");
}
args.push("-metadata:s:v:0");
args.push("rotate=0");
}
if (options.width && options.height) {
// Step 2: Fix Size & Ratio
targetWidth = options.width;
targetHeight = options.height;
targetRatio = targetWidth / targetHeight;
ratioSourceTarget = Math.sign(sourceWidth * targetHeight - targetWidth * sourceHeight);
if (options.ratio_strategy !== "fixed" && ratioSourceTarget !== 0) {
if ((options.ratio_strategy === "stretch" && ratioSourceTarget > 0) || (options.ratio_strategy === "shrink" && ratioSourceTarget < 0))
targetWidth = targetHeight * sourceRatio;
if ((options.ratio_strategy === "stretch" && ratioSourceTarget < 0) || (options.ratio_strategy === "shrink" && ratioSourceTarget > 0))
targetHeight = targetWidth / sourceRatio;
targetRatio = sourceRatio;
ratioSourceTarget = 0;
}
var vf = [];
// Step 3: Modulus
var modulus = options.output_type === 'video' ? helpers.videoFormats[options.video_format].modulus || 1 : 1;
targetWidth = targetWidth % modulus === 0 ? targetWidth : (Math.round(targetWidth / modulus) * modulus);
targetHeight = targetHeight % modulus === 0 ? targetHeight : (Math.round(targetHeight / modulus) * modulus);
var cropped = false;
var addCrop = function (x, y, multi) {
x = Math.round(x);
y = Math.round(y);
if (x === 0 && y === 0)
return;
cropped = true;
var cropWidth = targetWidth - 2 * x;
var cropHeight = targetHeight - 2 * y;
args.push("-vf");
args.push("scale=" + [multi || ratioSourceTarget >= 0 ? cropWidth : targetWidth, !multi && ratioSourceTarget >= 0 ? targetHeight : cropHeight].join(":") + "," +
"crop=" + [!multi && ratioSourceTarget <= 0 ? cropWidth : targetWidth, multi || ratioSourceTarget <= 0 ? targetHeight : cropHeight, -x, -y].join(":"));
};
var padded = false;
var addPad = function (x, y, multi) {
x = Math.round(x);
y = Math.round(y);
if (x === 0 && y === 0)
return;
padded = true;
var padWidth = targetWidth - 2 * x;
var padHeight = targetHeight - 2 * y;
args.push("-vf");
args.push("scale=" + [multi || ratioSourceTarget <= 0 ? padWidth : targetWidth, !multi && ratioSourceTarget <= 0 ? targetHeight : padHeight].join(":") + "," +
"pad=" + [!multi && ratioSourceTarget >= 0 ? padWidth : targetWidth, multi || ratioSourceTarget >= 0 ? targetHeight : padHeight, x, y].join(":"));
};
// Step 4: Crop & Pad
if (targetWidth >= sourceWidth && targetHeight >= sourceHeight) {
if (options.stretch_strategy === "pad")
addPad((targetWidth - sourceWidth) / 2,
(targetHeight - sourceHeight) / 2,
true);
else if (options.stretch_strategy === "stretch-pad")
addPad(ratioSourceTarget <= 0 ? (targetWidth - targetHeight * sourceRatio) / 2 : 0,
ratioSourceTarget >= 0 ? (targetHeight - targetWidth / sourceRatio) / 2 : 0);
else // stretch-crop
addCrop(ratioSourceTarget >= 0 ? (targetWidth - targetHeight * sourceRatio) / 2 : 0,
ratioSourceTarget <= 0 ? (targetHeight - targetWidth / sourceRatio) / 2 : 0);
} else if (targetWidth <= sourceWidth && targetHeight <= sourceHeight) {
if (options.shrink_strategy === "crop")
addCrop((targetWidth - sourceWidth) / 2,
(targetHeight - sourceHeight) / 2,
true);
else if (options.shrink_strategy === "shrink-crop")
addCrop(ratioSourceTarget >= 0 ? (targetWidth - targetHeight * sourceRatio) / 2 : 0,
ratioSourceTarget <= 0 ? (targetHeight - targetWidth / sourceRatio) / 2 : 0);
else // shrink-pad
addPad(ratioSourceTarget <= 0 ? (targetWidth - targetHeight * sourceRatio) / 2 : 0,
ratioSourceTarget >= 0 ? (targetHeight - targetWidth / sourceRatio) / 2 : 0);
} else {
if (options.mixed_strategy === "shrink-pad")
addPad(ratioSourceTarget <= 0 ? (targetWidth - targetHeight * sourceRatio) / 2 : 0,
ratioSourceTarget >= 0 ? (targetHeight - targetWidth / sourceRatio) / 2 : 0);
else if (options.mixed_strategy === "stretch-crop")
addCrop(ratioSourceTarget >= 0 ? (targetWidth - targetHeight * sourceRatio) / 2 : 0,
ratioSourceTarget <= 0 ? (targetHeight - targetWidth / sourceRatio) / 2 : 0);
else {
// crop-pad
cropped = true;
padded = true;
var direction = ratioSourceTarget >= 0;
var dirX = Math.abs(Math.round((sourceWidth - targetWidth) / 2));
var dirY = Math.abs(Math.round((sourceHeight - targetHeight) / 2));
args.push("-vf");
args.push("crop=" + [direction ? targetWidth : sourceWidth, direction ? sourceHeight : targetHeight, direction ? dirX : 0, direction ? 0 : dirY].join(":") + "," +
"pad=" + [targetWidth, targetHeight, direction ? 0 : dirX, direction ? dirY : 0].join(":"));
}
}
if (!padded && !cropped) {
args.push("-s");
args.push(targetWidth + "x" + targetHeight);
}
}
/*
*
* Watermark (depends on sizing)
*
*/
if (options.output_type !== 'audio') {
// TODO: Watermark
/*
*
* Watermark (depends on sizing)
*
*/
if (watermarkInfo) {
var scaleWidth = watermarkInfo.video.width;
var scaleHeight = watermarkInfo.video.height;
var maxWidth = targetWidth * options.watermark_size;
var maxHeight = targetHeight * options.watermark_size;
if (scaleWidth > maxWidth || scaleHeight > maxHeight) {
var watermarkRatio = maxWidth * scaleHeight >= maxHeight * scaleWidth;
scaleWidth = watermarkRatio ? scaleWidth * maxHeight / scaleHeight : maxWidth;
scaleHeight = !watermarkRatio ? scaleHeight * maxWidth / scaleWidth : maxHeight;
}
var posX = options.watermark_x * (targetWidth - scaleWidth);
var posY = options.watermark_y * (targetHeight - scaleHeight);
args.push("-vf");
args.push("movie=" + watermarkInfo.filename + "," +
"scale=" + [Math.round(scaleWidth), Math.round(scaleHeight)].join(":") + "[wm];[in][wm]" +
"overlay=" + [Math.round(posX), Math.round(posY)].join(":") + "[out]");
}
}

@@ -115,5 +304,5 @@

if (options.output_type === 'video') {
if (options.video_profile && format === "mp4")
if (options.video_profile && options.video_format === "mp4")
args.push(helpers.paramsVideoProfile(options.video_profile));
if (options.faststart && format === "mp4")
if (options.faststart && options.video_format === "mp4")
args.push(helpers.paramsFastStart);

@@ -125,3 +314,3 @@ var format = helpers.videoFormats[options.video_format];

args.push(helpers.paramsFramerate(options.framerate, format.bframes, options.framerate_gop));
args.push(helpers.paramsVideoCodecUniversalConfig());
args.push(helpers.paramsVideoCodecUniversalConfig);
if (format && format.passes > 1)

@@ -137,9 +326,21 @@ passes = format.passes;

*/
// '-b:v' '211k'
// '-b:a' '64k'
if (options.output_type === "video") {
args.push("-b:v");
var video_bit_rate = options.video_bit_rate || Math.min(videoInfo.bit_rate * targetWidth * targetHeight / sourceWidth / sourceHeight, videoInfo.bit_rate);
args.push(Math.round(video_bit_rate / 1000) + "k");
if (audioInfo) {
args.push("-b:a");
var audio_bit_rate = options.audio_bit_rate || audioInfo.bit_rate;
args.push(Math.round(audio_bit_rate / 1000) + "k");
}
}
//} catch(e) {console.log(e);}
//console.log(files, args, passes, output);
return ffmpeg_multi_pass.ffmpeg_multi_pass(files, args, passes, output, function (progress) {
if (eventCallback)
eventCallback.call(eventContext || this, helper.parseProgress(progress, duration));
}, this).mapSuccess(function () {
return ffprobe_simple.ffprobe_simple(output);
}, this);

@@ -146,0 +347,0 @@ });

@@ -22,3 +22,4 @@ Scoped.require([

commands.push(output);
var file = require("child_process").spawn("ffmpeg", commands);
// console.log(commands.join(" "));
var file = require("child_process").spawn("ffmpeg", commands.join(" ").split(" "));
var lines = "";

@@ -25,0 +26,0 @@ file.stderr.on("data", function (data) {

@@ -25,7 +25,10 @@ Scoped.require([

if (stream.codec_type === 'video') {
var rotation = stream.tags && stream.tags.rotate ? parseInt(stream.tags.rotate, 10) : 0;
result.video = {
index: stream.index,
rotation: stream.tags && stream.tags.rotate ? parseInt(stream.tags.rotate, 10) : 0,
rotation: rotation,
width: stream.width,
height: stream.height,
rotated_width: rotation % 180 === 0 ? stream.width : stream.height,
rotated_height: rotation % 180 === 0 ? stream.height : stream.width,
codec_name: stream.codec_tag_string,

@@ -32,0 +35,0 @@ codec_long_name: stream.codec_long_name,

@@ -8,3 +8,3 @@ var ffmpeg = require(__dirname + "/../../index.js");

stop();
ffmpeg.ffprobe_simple(NOT_EXISTING_VIDEO).callback(function (error, value) {
ffmpeg.ffprobe_simple(NOT_EXISTING_VIDEO).callback(function(error, value) {
QUnit.equal(error, 'File does not exist');

@@ -17,3 +17,3 @@ start();

stop();
ffmpeg.ffprobe_simple(ROTATED_MOV_VIDEO).callback(function (error, value) {
ffmpeg.ffprobe_simple(ROTATED_MOV_VIDEO).callback(function(error, value) {
QUnit.deepEqual(value, {

@@ -27,4 +27,3 @@ filename : ROTATED_MOV_VIDEO,

format_name : 'QuickTime / MOV',
format_extensions : [ 'mov', 'mp4',
'm4a', '3gp', '3g2', 'mj2' ],
format_extensions : [ 'mov', 'mp4', 'm4a', '3gp', '3g2', 'mj2' ],
format_default_extension : 'mov',

@@ -45,2 +44,4 @@ audio : {

height : 320,
rotated_width : 320,
rotated_height : 568,
codec_name : 'avc1',

@@ -54,2 +55,2 @@ codec_long_name : 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10',

});
});
});
var ffmpeg = require(__dirname + "/../../index.js");
var ROTATED_MOV_VIDEO = "tests/assets/iphone_rotated.mov";
var IMAGE_FILE = "tests/assets/logo.png";

@@ -11,2 +12,11 @@ test("ffprobe rotated mov", function() {

});
});
test("ffprobe image", function() {
stop();
ffmpeg.ffprobe(IMAGE_FILE).callback(function(error, value) {
QUnit.deepEqual(value.format.nb_streams, 1);
start();
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc