Skip to content

Commit

Permalink
Started parser
Browse files Browse the repository at this point in the history
  • Loading branch information
cgiffard committed Oct 8, 2012
1 parent 397ed7f commit 187a39a
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 19 deletions.
7 changes: 7 additions & 0 deletions example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var NCoder = require("./");
myEnc = new NCoder();


var myFile = "/Users/cgiffard/Development/Projects/Vixen/30707792.mp4"

myEnc.metadata(myFile,console.log.bind(console));
195 changes: 181 additions & 14 deletions ffparse.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,201 @@
// Little parser for FFMpeg

var EventEmitter = require("events").EventEmitter;

const FF_UNINITIALISED = 0,
FF_BUILDINFO = 1,
FF_STREAMINFO = 2,
FF_STREAMMETA = 3;
FF_INFOWAITING = 2,
FF_STREAMWAITING = 3,
FF_STREAMINFO = 4,
FF_STREAMMETA = 5,
FF_STREAMDURATION = 6;

// My build of ffmpeg outputs two space tabs. Yours may differ.
const FF_INDENT_TOKEN = " ";


module.exports = function FFParser(ffchild) {
//
this.inputs = [];
this.outputs = [];
this.progress = 0;
var FFParser = function(ffchild) {
var self = this;

// Externally accessible properties
self.inputs = [];
self.outputs = [];
self.progress = 0;
self.status = 0;

// Managing the parser!
self._outputBuffer = "";
self._outputLines = [];
self._cleanLines = [];
self._lineIndex = 0;
self._status = FF_UNINITIALISED;
self._currentInput = null;
self._currentStream = null;
self._currentOutput = null;

this._outputData = "";
ffchild.stderr.on("data",self.parse.bind(self));
ffchild.stdout.on("data",self.parse.bind(self));

ffchild.stderr.on("data",this.parse.bind(this));
ffchild.stdout.on("data",this.parse.bind(this));
ffchild.on("exit",function() {
if (self._outputBuffer.length) {
self._lineIndex ++;
self._outputLines.push(self._outputBuffer);
self.parseLine(self._outputBuffer);
self._outputBuffer = "";
}

self.emit("parsecomplete",self);
});

self.emit("init",self);
};

module.exports.prototype.parse = function(data) {
this.outputData += data;
// Emit events!
FFParser.prototype = new EventEmitter;

// Split input, buffer by line.
// Then call parse on each line.
FFParser.prototype.parse = function(data) {
data = data.toString();

var self = this,
endsWithNewline = data.match(/[\r\n]$/),
lines = data.split(/[\r\n]/ig);

self.emit("chunkparse",data);

// If there's something in the output buffer, prepend it to the first line.
if (self._outputBuffer.length) {
lines[0] = self._outputBuffer + lines[0];
}

// The last chunk might be part of more data to come.
// Buffer it and remove it from the line list.

if (!endsWithNewline) {
self._outputBuffer = lines.pop();
}

// Now we have our lines from this chunk, concat them to the global store.
if (lines.length) {
self._outputLines = self._outputLines.concat(lines);
}

while (self._lineIndex < self._outputLines.length) {
self.parseLine(self._outputLines[self._lineIndex]);
self._lineIndex ++;
}

return self;
};

module.exports.prototype.parseLine = function() {
FFParser.prototype.parseLine = function(lineData) {
var self = this;

self.emit("lineparse",lineData);

// First we test how much indentaton we're dealing with.
var indentation = 0,
indentRE = new RegExp("^" + FF_INDENT_TOKEN);

while (indentRE.exec(lineData)) {
lineData = lineData.substr(FF_INDENT_TOKEN.length);
indentation ++
}

var procedureData, procedureName = "";
if ((procedureData = lineData.match(/^([a-z0-9\-_]+)\s*\:*/i)) &&
lineData.match(/\:/g)) {

procedureName = procedureData[1];
lineData = lineData.substr(procedureName.length);
}


switch (self.status) {

case FF_UNINITIALISED:

if (lineData.match(/^ffmpeg version/i))
self.status = FF_BUILDINFO;

break;

case FF_BUILDINFO:

if (lineData.length === 0 || lineData.match(/^\s+$/))
self.status = FF_INFOWAITING;

break;

case FF_INFOWAITING:

if (procedureName === "Input") {

self.inputs.push(
self._currentInput = new FFInput(lineData)
);

self.status = FF_STREAMWAITING;

} else {
throw new Error("Unrecognised procedure name.");
}

break;

case FF_STREAMWAITING:

console.log(procedureName,lineData);

default:
console.log(procedureName,lineData);
throw new Error("Unrecognised parser status!");
}

// lineData

// console.log(procedureName);
// console.log(lineData);

return self;
};


// FFINPUT
function FFInput(initData) {
var self = this;

if (!initData || !initData.length)
throw new Error("Input initialisation data must be provided.");

self.streams = [];
self.index = 0;
self.codecs = []; // codecs supported by this container
self.sourceFile = "";

var initParts = initData.split(/\s+from\s+'/i);

self.sourceFile = initParts[1].replace(/\s*'\s*:\s*$/,"");

initParts = initParts[0].split(/,\s+/i);

self.index = parseInt(initParts[0].replace(/\D/g,""),10);

self.codecs =
initParts[1]
.replace(/[^a-z0-9\,]/ig,"")
.split(/,/g)
.filter(function(item) {
return item && item.length;
});

console.log(initParts);
console.log(self.sourceFile);
console.log(self.codecs);

console.log("index was",self.index);
};


// FFINPUT
module.exports = FFParser;
11 changes: 6 additions & 5 deletions ncoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ NCoder.prototype.metadata = function(infile) {
// then read it back in...
var ffmpeg = spawn("ffmpeg",["-i",infile]);

var stdout = "", stderr = "",
parser = new FFParser(ffmpeg.stdout,ffmpeg.sterr);
var parser = new FFParser(ffmpeg);

ffmpeg.stderr.on("data",function(streamChunk) {
stderr += streamChunk
//stderr += streamChunk
});

ffmpeg.on("exit",function(arguments) {
parser.parse(stderr);
})
//parser.parse(stderr);
console.log("that's the end of that then.");
console.log(parser);
});
};

module.exports = NCoder;

0 comments on commit 187a39a

Please sign in to comment.