1
0
mirror of https://github.com/danog/plotframes.git synced 2024-11-26 20:04:39 +01:00

v2 update

This commit is contained in:
Rodrigo Polo MPW 2015-10-17 15:38:41 -06:00
parent 1090e28cc6
commit a3e01d063b
3 changed files with 201 additions and 254 deletions

View File

@ -46,7 +46,7 @@ options:
You can set many options to the `gnuplot` terminal argument: You can set many options to the `gnuplot` terminal argument:
``` ```
plotframes -i input.m4v -o plot.png -t "pngcairo transparent enhanced font 'arial,10' fontscale 1.0 ; set zeroaxis;;" plotframes -i input.m4v -o plot.png -t "set terminal png transparent enhanced size 7000,800"
``` ```
You can set `plotframes` to output the `gnuplot` script to `stdout` and then You can set `plotframes` to output the `gnuplot` script to `stdout` and then

1
cli.js
View File

@ -117,6 +117,7 @@ plotframes.plotScript(opts.input,
process.exit(1); process.exit(1);
}else{ }else{
if(opts.print){ if(opts.print){
log.clear();
console.log(res); console.log(res);
}else{ }else{
cutelog('All tasks done!',false); cutelog('All tasks done!',false);

340
main.js
View File

@ -104,21 +104,34 @@ function getDetails(input, cb){
}); });
} }
// Get frame bitrate // Get frame bitrate
function getBitrate(input, details, progress, cb){ function getBitrate(input, details, progress, cb){
var var
// for regex
r_frame = /(?:media_type\=(\w+)\r?\n)(?:stream_index\=(\w+)\r?\n)(?:pkt_pts_time\=(\d*.?\d*)\r?\n)(?:pkt_size\=(\d+)\r?\n)(?:pict_type\=(\w+))?/, r_frame = /(?:media_type\=(\w+)\r?\n)(?:stream_index\=(\w+)\r?\n)(?:pkt_pts_time\=(\d*.?\d*)\r?\n)(?:pkt_size\=(\d+)\r?\n)(?:pict_type\=(\w+))?/,
r, r,
current_track,
// For frame arrays
frame_count = 0, frame_count = 0,
frame_stream,
frame_type, frame_type,
frame_bitrate,
frame_size, frame_size,
frame_time, frame_time,
tracks = [],
fsizes = [], // Frame Arrays
times = [], frames = {
bitrates = [], count: [],
fr2br = []; stream: [],
type: [],
bitrate: [],
size: [],
time: []
},
// For loop
frame_size;
// Run ffprobe // Run ffprobe
var cli = child.spawn( var cli = child.spawn(
@ -134,65 +147,19 @@ function getBitrate(input, details, progress, cb){
if(r = r_frame.exec(data)){ if(r = r_frame.exec(data)){
current_track = r[2];
frame_count++; frame_count++;
frame_stream = parseInt(r[2]);
frame_type = r[5]?r[5]:'A'; frame_type = r[5]?r[5]:'A';
frame_size = ((r[4]*8)/1000); frame_size = ((r[4]*8)/1000);
frame_bitrate = frame_size * details.frame_rate; frame_bitrate = frame_size * details.frame_rate;
frame_time = parseFloat(r[3]); frame_time = parseFloat(r[3]);
frame_sec = parseInt(frame_time);
// Create track if doesn't exists frames.count.push(frame_count);
if(!tracks[current_track]){ frames.stream.push(frame_stream);
tracks[current_track] = { frames.type.push(frame_type);
type: r[1], frames.bitrate.push(frame_bitrate);
frames:{}, frames.size.push(frame_size);
fpos:[], frames.time.push(frame_time);
bitrates:[],
fsizes:[],
times:[]
};
}
// Create frame type obj if doesn't exists
if(!tracks[current_track].frames[frame_type]){
tracks[current_track].frames[frame_type] = {
pos: [],
sec: [],
siz: [],
btr: [],
};
}
// Add frame type data
tracks[current_track].frames[frame_type].pos.push(frame_count);
tracks[current_track].frames[frame_type].sec.push(frame_time);
tracks[current_track].frames[frame_type].siz.push(frame_size);
tracks[current_track].frames[frame_type].btr.push(frame_bitrate);
// Add frame data
tracks[current_track].fpos.push(frame_count);
tracks[current_track].fsizes.push(frame_bitrate);
tracks[current_track].times.push(frame_time);
// Add bitrates per track
if(tracks[current_track].bitrates[frame_sec]){
tracks[current_track].bitrates[frame_sec] += frame_size;
}else{
tracks[current_track].bitrates[frame_sec] = frame_size;
}
// Add overall frame info
fsizes.push(frame_bitrate);
times.push(frame_time);
// Add overall bitrate data
if(bitrates[frame_sec]){
bitrates[frame_sec] += frame_size;
}else{
fr2br[frame_sec] = frame_count;
bitrates[frame_sec] = frame_size;
}
// Show progress // Show progress
progress({ progress({
@ -209,13 +176,7 @@ function getBitrate(input, details, progress, cb){
if (code !== 0) { if (code !== 0) {
cb('Error trying to get the file bitrate.', null); cb('Error trying to get the file bitrate.', null);
} }
cb(null, { cb(null, frames);
tracks: tracks,
bitrates: bitrates,
fr2br: fr2br,
fsizes: fsizes,
times: times
});
}); });
@ -249,59 +210,114 @@ function getFrames(input, progress, cb){
} }
// Generate gnuplot script // Generate gnuplot script
function genScript(input, data, ops){ function genScript(input, frames, ops, cb){
var gs = '';
// Functional
var all_streams = (ops.stream=='all');
var is_frames = ops.frames;
var selected_stream = parseInt(ops.stream);
var graphs = []; var graphs = [];
var frame_types = [ var frame_types = [
'A',
'I', 'I',
'P', 'P',
'B', 'B',
'A',
]; ];
var label_sep = '\\n'; var label_sep = '\\n';
var brtsrc = (ops.stream=='all')?data:data.tracks[ops.stream]; // for loops
if(!brtsrc){ var frame_sec;
cb('That stream doesn\'t exists, it should be a number that exists.',null);
return false; // for storing
var bitrate = [];
var selected_stream_bitrate = [];
var selected_stream_bitrate_pos = [];
var selected_bitrate;
var gs = '';
var bitrate_max;
var bitrate_min;
var bitrate_avg;
var selected_frame_count = 0;
var selected_frame_types={};
var frame_start = frames.count[0];
var frame_end = frames.count[frames.count.length-1];
var time_start = frames.time[0];
var time_end = frames.time[frames.time.length-1];
// Create bitrate by sec for selected streams, count frames and save frame types
for (var i = 0; i < frames.size.length; i++) {
frame_sec = parseInt(frames.time[i]);
if(all_streams){
selected_frame_types[frames.type[i]] = []; // TODO: add stream number
selected_stream_bitrate.push(frames.size[i]);
selected_stream_bitrate_pos.push(frames.count[i]);
selected_frame_count++;
if(bitrate[frame_sec]){
bitrate[frame_sec] += frames.size[i];
}else{
bitrate[frame_sec] = frames.size[i];
}
}else{
if(frames.stream[i] == selected_stream){
selected_frame_types[frames.type[i]] = []; // TODO: add stream number
selected_stream_bitrate.push(frames.size[i]);
selected_stream_bitrate_pos.push(frames.count[i]);
selected_frame_count++;
if(bitrate[frame_sec]){
bitrate[frame_sec] += frames.size[i];
}else{
bitrate[frame_sec] = frames.size[i];
}
}
}
};
selected_bitrate = (is_frames)?frames.bitrate:bitrate;
if(bitrate.length == 0){
cb('There is no data in the selected stream.', null);
} }
var br_average = arrAvg(brtsrc.bitrates);
var fr_average = arrAvg(brtsrc.fsizes);
// Set font size // Set font size
gs+='set key font ",10"\n' gs+='set key font ",10"\n';
// Graph range // Graph range
if(ops.frames){ if(is_frames){
gs+='set xrange [1:'+(brtsrc.fsizes.length-1)+']\n'; gs+='set xrange ['+frame_start+':'+frame_end+']\n';
}else{ }else{
gs+='set xrange [0:'+(brtsrc.bitrates.length)+']\n'; gs+='set xrange ['+time_start+':'+time_end+']\n';
} }
// Title // Title
gs += 'set title "Frames Bitrates for \\"'+path.basename(input); gs += 'set title "Frames Bitrates for \\"'+path.basename(input);
if(ops.stream=='all'){ if(all_streams){
gs += '\\""\n'; gs += '\\""\n';
}else{ }else{
gs += ':'+ops.stream+'\\""\n'; gs += ':'+ops.stream+'\\""\n';
} }
// Measurement
bitrate_max = arrMax(selected_bitrate);
bitrate_min = arrMin(selected_bitrate);
bitrate_avg = arrAvg(selected_bitrate);
// Info label // Info label
gs+='set label "'; gs+='set label "';
if(ops.frames){ if(is_frames){
gs+='Frames: '+(brtsrc.fsizes.length-1)+' of '+(data.fsizes.length-1)+label_sep; gs+='Frames: '+selected_frame_count+' of '+frames.count[frames.count.length-1]+label_sep;
}else{ }else{
gs+='Seconds: '+(brtsrc.bitrates.length)+label_sep; gs+='Seconds: '+frames.time[frames.time.length-1]+label_sep;
} }
gs+= gs+=
'Max: '+bandWidth(arrMax(brtsrc.bitrates))+label_sep 'Max: '+bandWidth(bitrate_max)+label_sep
+'Min: '+bandWidth(arrMin(brtsrc.bitrates))+label_sep +'Min: '+bandWidth(bitrate_min)+label_sep
+'Avg: '+bandWidth(br_average); +'Avg: '+bandWidth(bitrate_avg);
gs+='" left at graph 0.005, graph .970 font ",10"\n'; gs+='" left at graph 0.005, graph .970 font ",10"\n';
// X Label // X Label
gs+='set xlabel "'+((ops.frames)?'Frames':'Seconds')+'" font ",10"\n'; gs+='set xlabel "'+((is_frames)?'Frames':'Seconds')+'" font ",10"\n';
// Y Label // Y Label
gs+='set ylabel "Kbps" font ",10"\n'; gs+='set ylabel "Kbps" font ",10"\n';
@ -318,128 +334,58 @@ function genScript(input, data, ops){
// Plotting // Plotting
gs += 'plot \\\n'; gs += 'plot \\\n';
// File streams graphs
if(ops.stream=='all'){
for (var i = 0; i < data.tracks.length; i++){
for (var j = 0; j < frame_types.length; j++){
if(data.tracks[i].frames[frame_types[j]]){
graphs.push('"-" title "'+frame_types[j]+'" with '+ops.styles[frame_types[j]]+' linecolor rgb "'+ops.colors[frame_types[j]]+'"')
}
};
};
}else{
for (var j = 0; j < frame_types.length; j++){
if(data.tracks[ops.stream].frames[frame_types[j]]){
graphs.push('"-" title "'+frame_types[j]+'" with '+ops.styles[frame_types[j]]+' linecolor rgb "'+ops.colors[frame_types[j]]+'"')
}
};
}
// Loop trough selected stream frames
for (var i = 0; i < frame_types.length; i++) {
if(selected_frame_types[frame_types[i]]){
graphs.push('"-" title "'+frame_types[i]+'" with '+ops.styles[frame_types[i]]+' linecolor rgb "'+ops.colors[frame_types[i]]+'"');
}
};
if(!is_frames){
// Average bitrate // Average bitrate
graphs.push('"-" title "Average" with lines lc rgb "'+ops.colors.average+'" lt 1 lw .5'); graphs.push('"-" title "Average" with lines lc rgb "'+ops.colors.average+'" lt 1 lw .5');
// Bitrate // Bitrate
graphs.push('"-" smooth bezier title "Bitrate" with lines lc rgb "'+ops.colors.bitrate+'" lt 1 lw 1.5'); graphs.push('"-" smooth bezier title "Bitrate" with lines lc rgb "'+ops.colors.bitrate+'" lt 1 lw 1.5');
}
// Add the graphs defs // Add the graphs defs
gs += graphs.join(', \\\n')+' \n'; gs += graphs.join(', \\\n')+' \n';
// Graph data // Add frames for selected streams
if(ops.stream=='all'){ for (var i = 0; i < frames.bitrate.length; i++) {
for (var i = 0; i < data.tracks.length; i++){ if(selected_frame_types[frames.type[i]]){
for (var j = 0; j < frame_types.length; j++){ if(is_frames){
if(data.tracks[i].frames[frame_types[j]]){ selected_frame_types[frames.type[i]].push(frames.count[i]+' '+frames.bitrate[i]);
for (var k = 0; ; k++) {
if(ops.frames){
gs += data.tracks[i].frames[frame_types[j]]['pos'][k];
}else{ }else{
gs += data.tracks[i].frames[frame_types[j]]['sec'][k]; selected_frame_types[frames.type[i]].push(frames.time[i]+' '+frames.bitrate[i]);
} }
gs += ' '
+ data.tracks[i].frames[frame_types[j]]['btr'][k]
+'\n';
if(k == data.tracks[i].frames[frame_types[j]]['btr'].length-1){
gs += ('e\n');
break;
} }
}; };
// Loop trough selected stream frames
for (var i = 0; i < frame_types.length; i++) {
if(selected_frame_types[frame_types[i]]){
gs += selected_frame_types[frame_types[i]].join('\n')+'\ne\n';
} }
}; };
// Add average bitrate line
if(!is_frames){
gs += time_start+' '+bitrate_avg+'\n';
gs += time_end+' '+bitrate_avg+'\ne\n';
}
// Add bitrate line
if(!is_frames){
for (var i = 0; i < bitrate.length; i++) {
gs += i+' '+bitrate[i]+'\n';
}; };
}else{ gs += 'e';
for (var j = 0; j < frame_types.length; j++){
if(data.tracks[ops.stream].frames[frame_types[j]]){
for (var k = 0; ; k++) {
if(ops.frames){
gs += data.tracks[ops.stream].frames[frame_types[j]]['pos'][k];
}else{
gs += data.tracks[ops.stream].frames[frame_types[j]]['sec'][k];
} }
gs += ' ' cb(null, gs);
+ data.tracks[ops.stream].frames[frame_types[j]]['btr'][k]
+'\n';;
if(k == data.tracks[ops.stream].frames[frame_types[j]]['btr'].length-1){
gs += ('e\n');
break;
}
};
}
};
}
// Bitrate average data
if(ops.stream=='all'){
if(ops.frames){
// frames all
gs += '1 '+ br_average+ '\n'
+ data.fsizes.length+ ' '+ br_average+ '\ne\n';
}else{
// bitrates all
gs += '0 ' + br_average + '\n'
+ data.times[data.times.length-1] + ' ' + br_average + '\ne\n';
}
}else{
if(ops.frames){
// frames single
gs += ('1 '+ br_average+ '\n'
+ data.tracks[ops.stream].fsizes.length+ ' '+ br_average+ '\ne\n');
}else{
// bitrate single
gs += ('0 ' + br_average + '\n'
+ data.tracks[ops.stream].times[data.tracks[ops.stream].times.length-1] + ' ' + br_average + '\ne\n');
}
}
// Bitrate data
if(ops.frames){
for (var i = 0; ; i++) {
gs += (ops.stream=='all') ? (i+1) : brtsrc.fpos[i];
gs += ' '+brtsrc.fsizes[i]+'\n';
if(i == brtsrc.fsizes.length-1){
gs += ('e\n');
break;
}
};
}else{
for (var i = 0; ; i++) {
gs += (i+' '+brtsrc.bitrates[i]+'\n');
if(i == brtsrc.bitrates.length-1){
gs += ('e\n');
break;
}
};
}
return gs;
} }
// Parse the options, gen the script and call gnuplot via stdin // Parse the options, gen the script and call gnuplot via stdin
@ -475,15 +421,15 @@ function plotScript(input, cb, op){
var script_str=''; var script_str='';
getFrames(input, options.progress, function(err, data){ getFrames(input, options.progress, function(err, data){
if(err){
cb(err, null);
}else{
// gnuplot script
genScript(input, data, options,function(err, gs){
if(err){ if(err){
cb(err, null); cb(err, null);
}else{ }else{
// gnuplot script
var gs = genScript(input, data, options);
if(options.as_string){ if(options.as_string){
cb(null, gs); cb(null, gs);
}else{ }else{
@ -531,9 +477,9 @@ function plotScript(input, cb, op){
script.push(gs); script.push(gs);
script.push(null); script.push(null);
} }
} }
});
}
}, options); }, options);
} }