Simple script to parse ffprobe data with custom real-time markers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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