Skip to content

Instantly share code, notes, and snippets.

@WoZ WoZ/ffprobe_analyzer.js
Last active Jan 4, 2018

Embed
What would you like to do?
Simple script to parse ffprobe data with custom real-time markers
const readline = require('readline');
const fs = require('fs');
const argv = process.argv.slice(2);
if (argv.length !== 1) {
console.error('Invalid list of arguments');
process.exit(1);
}
const filename = argv[0];
const lineReader = readline.createInterface({
input: fs.createReadStream(filename)
});
const FRAME_START_MARKER = '[FRAME]';
const FRAME_END_MARKER = '[/FRAME]';
const REAL_TIME_START_MARKER = '---';
const REAL_TIME_END_MARKER = '--- ';
const AGGREGATION_TIME_SEC = 5;
function cutRealTime(line) {
let trimmedLine = line;
let startOfRealTime;
let lastRealTime;
while ((startOfRealTime = trimmedLine.indexOf(REAL_TIME_START_MARKER)) >= 0) {
endOfRealTime = trimmedLine.indexOf('--- ', startOfRealTime + 3);
lastRealTime = trimmedLine.substr(
startOfRealTime + REAL_TIME_START_MARKER.length,
endOfRealTime - REAL_TIME_START_MARKER.length
);
trimmedLine = trimmedLine.substr(endOfRealTime + REAL_TIME_END_MARKER.length);
}
return [trimmedLine, lastRealTime];
}
let isFrameStarted = false;
let frame;
let lineNumber = 0;
let lastRealTime;
let endOfRealTime;
let prevCodedPictureNumber = -1;
let buffers = {
pkt_dts_time: {},
real_time: {},
};
lineReader.on('line', line => {
lineNumber++;
[line, realTime] = cutRealTime(line);
if (realTime) lastRealTime = realTime;
if (line === FRAME_START_MARKER) {
if (isFrameStarted) {
process.stderr.write(`Intersection of ${FRAME_START_MARKER} blocks was found on line ${lineNumber}\n`);
process.exit(1);
}
frame = {};
isFrameStarted = true;
} else if (line === FRAME_END_MARKER) {
if (!isFrameStarted) {
process.stderr.write(`${FRAME_END_MARKER} was found before ${FRAME_START_MARKER} at line ${lineNumber}\n`);
process.exit(1);
}
isFrameStarted = false;
if (frame['media_type'] === 'video') {
if (!lastRealTime) {
return;
}
const realTimeFloored = Math.floor(Date.parse(lastRealTime) / 1000);
const realTimeNormalized = realTimeFloored - (realTimeFloored % AGGREGATION_TIME_SEC);
if (!buffers.real_time[realTimeNormalized]) {
buffers.real_time[realTimeNormalized] = 1;
} else {
buffers.real_time[realTimeNormalized]++;
}
const flooredpktDtsTime = Math.floor(parseFloat(frame['pkt_dts_time']));
const pktDtsTimeNormalized = flooredpktDtsTime - (flooredpktDtsTime % AGGREGATION_TIME_SEC);
if (!buffers.pkt_dts_time[pktDtsTimeNormalized]) {
buffers.pkt_dts_time[pktDtsTimeNormalized] = 1;
} else {
buffers.pkt_dts_time[pktDtsTimeNormalized]++;
}
const codedPictureNumber = parseInt(frame['coded_picture_number']);
if (prevCodedPictureNumber >= 0) {
if (codedPictureNumber > prevCodedPictureNumber + 1) {
process.stderr.write(`coded_picture_number: ${prevCodedPictureNumber} -> ${codedPictureNumber}`);
}
}
prevCodedPictureNumber = codedPictureNumber;
}
} else {
if (isFrameStarted) {
const keyAndValue = line.split('=');
frame[keyAndValue[0]] = keyAndValue[1];
}
}
});
lineReader.on('close', () => {
const realTimeKeys = Object.keys(buffers.real_time);
const realTimeStart = parseInt(realTimeKeys[0]);
const realTimeEnd = parseInt(realTimeKeys[realTimeKeys.length - 1]);
for (let time = realTimeStart; time < realTimeEnd; time += AGGREGATION_TIME_SEC) {
let realTimeVal = (buffers.real_time[time] !== undefined) ? buffers.real_time[time] : 0;
let normalizedPktDtsTime = time - realTimeStart;
let pktDtsTimeVal = (buffers.pkt_dts_time[normalizedPktDtsTime] !== undefined) ?
buffers.pkt_dts_time[normalizedPktDtsTime] : 0;
process.stdout.write(`${time} ${realTimeVal} ${pktDtsTimeVal}\n`);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.