UNPKG

4.24 kBJavaScriptView Raw
1var fs = require("fs"),
2 path = require("path"),
3 defaults = require("./options"),
4 ffmpeg = require('fluent-ffmpeg'),
5 os = require("os"),
6 utils = require("./utils");
7//
8
9var Video = function( options ){
10
11 this.options = options;
12
13};
14
15Video.prototype = {
16
17 compile: function(source, callback){
18
19 var self = this;
20 // gather data
21 var data = {
22 source: source,
23 name: this.options.name || utils.filename( this.options.files ),
24 dir: utils.tmpDir(),
25 ext: path.extname( source )
26 }
27 var ratio = this.options.ratio || "auto"; // dynamically read media dimensions instead?
28 var sizes = this.options.video.sizes[ratio] || this.options.video.sizes['auto'];
29 // never upscale a video (option?)
30 sizes = this._noUpscale( sizes );
31 var original = data.dir + data.name + data.ext;
32 // update poster value if set as a general option
33 if( this.options.video.poster ){
34 for(var i in sizes){
35 sizes[i].poster = true;
36 }
37 }
38 // copy original file to temp dir
39 fs.createReadStream( source ).pipe(fs.createWriteStream( original ))
40 .on("finish", function(){
41 // start grunt
42 var options = {
43 gruntfile : path.normalize( __dirname+'/../gruntfile.js'),
44 responsive_videos: {
45 encode:{
46 options: {
47 sizes: sizes,
48
49 encodes: [{
50 mp4: [
51 {'-vcodec': 'libx264'},
52 //{'-acodec': 'libfaac'},
53 {'-acodec': 'aac'},
54 {'-strict': '-2'},
55 //{'-b:v': '1200k'},
56 {'-b:v': '1M'},
57 {'-b:a': '192k'},
58 {'-crf': '22.5'},
59 {'-movflags': 'faststart'},
60 {'-threads': '0'}
61 ],
62 webm: [
63 {'-vcodec': 'libvpx'},
64 {'-acodec': 'libvorbis'},
65 {'-b:v': '1M'},
66 {'-q:a': '100'},
67 {'-crf': '22.5'},
68 {'-movflags': 'faststart'},
69 {'-threads': '0'}
70 ],
71 ogv: [
72 {'-vcodec': 'libtheora'},
73 {'-acodec': 'libvorbis'},
74 //{'-b:v': '500k'},
75 {'-b:v': '1M'},
76 {'-q:a': '100'},
77 {'-crf': '22.5'},
78 {'-quality': 'good'},
79 {'-cpu-used': '0'},
80 {'-qmax': '42'},
81 {'-maxrate': '500k'},
82 {'-bufsize': '1000k'},
83 {'-movflags': 'faststart'},
84 {'-threads': '0'}
85 ]
86 }]
87 },
88 files: [{
89 //expand: true,
90 src: [ original ],
91 cwd: data.dir,
92 dest: original // destination path is used to get the file extension, why?
93 }]
94 }
95 }
96 };
97
98 // new instance of grunt...
99 var grunt = require("grunt");
100
101 grunt.initConfig( options );
102
103 // execute tasks...
104 grunt.tasks(["responsive_videos"], options, function(){
105 //console.log("Grunt.js Tasks Completed!");
106 callback( data );
107 });
108
109 });
110
111 },
112
113 // get video metadata
114 info: function( file, callback ){
115 var self = this;
116
117 ffmpeg.ffprobe(file, function(err, metadata) {
118 if (err) {
119 console.error(err);
120 // fallback?
121 callback({});
122 } else {
123 // metadata should contain 'width', 'height' and 'display_aspect_ratio'
124 // save for future access
125 self.metadata = metadata;
126 callback(metadata);
127 }
128 });
129 },
130
131 // Internal
132 _noUpscale: function( sizes ){
133 var metadata = this.metadata.streams[0];
134 var filtered = [];
135 // loop through selected sizes
136 for(var i in sizes){
137 if( metadata.width < sizes[i].width || metadata.height < sizes[i].height ) continue;
138 filtered.push( sizes[i] );
139 }
140 console.log(sizes, filtered);
141 return filtered;
142 }
143
144
145}
146
147// Hidden
148function aspectRatio( metadata ){
149 var ratio = metadata.display_aspect_ratio;
150 // FIX: for no valid aspect ratio
151 if( ratio == "0:1" ){
152 if( metadata.width/metadata.height == 16/9 ) ratio = "16:9";
153 if( metadata.width/metadata.height == 4/3 ) ratio = "4:3";
154 }
155 return ratio;
156}
157
158module.exports = function( file, callback ){
159 var options = this.options;
160 var self = this;
161 // new instance of the video class
162 var video = new Video( options );
163 // get info
164 video.info( file, function( info ){
165 // set aspect ratio
166 if( info.streams ) video.options.ratio = aspectRatio( info.streams[0] );
167 // encode sizes
168 video.compile( file, function( data ){
169 // back to the main lib to store the files...
170 self.onCompileComplete( data, callback );
171 });
172 });
173};