Permalink
Browse files

media info extraction

  • Loading branch information...
1 parent 0155f62 commit 8aefe415c28d265f3c73906c7c016e26f57cc285 @benvanik committed Nov 9, 2011
Showing with 129 additions and 43 deletions.
  1. +29 −2 lib/content.js
  2. +94 −0 lib/mediainfo.js
  3. +3 −12 lib/transcoder.js
  4. +0 −27 lib/transcoderlist.js
  5. +3 −2 package.json
View
@@ -1,9 +1,10 @@
var fs = require('fs');
var http = require('http');
+var mediainfo = require('./mediainfo');
var url = require('url');
var util = require('util');
-var transcoderList = require('./transcoderlist').transcoderList;
+var Transcoder = require('./transcoder').Transcoder;
var Content = function(id, source, target) {
this.id = id;
@@ -23,6 +24,12 @@ var Content = function(id, source, target) {
this.cached_ = false;
this.seekable_ = false;
this.readyToPlay_ = false;
+
+ var self = this;
+ this.extractMediaInfo_(function(info) {
+ console.log(util.inspect(info));
+ self.source.info = info;
+ });
};
exports.Content = Content;
@@ -38,6 +45,26 @@ Content.prototype.matches = function(source, target) {
return sourceMatches && targetMatches;
};
+Content.prototype.extractMediaInfo_ = function(callback) {
+ var sourceUrl = url.parse(this.source.content);
+ switch (sourceUrl.protocol) {
+ case 'file:':
+ var filename = decodeURI(sourceUrl.pathname);
+ mediainfo.extractInfo(filename, callback);
+ return;
+ case 'http:':
+ case 'https:':
+ // HEAD to get the content type
+ // TODO: head, grab the first bit, run mediainfo on it
+ callback(null);
+ return;
+ default:
+ util.puts('unsupported protocol: ' + sourceUrl.protocol);
+ callback(null);
+ return;
+ }
+};
+
Content.prototype.get = function(req, res) {
var sourceUrl = url.parse(this.source.content);
switch (sourceUrl.protocol) {
@@ -166,7 +193,7 @@ Content.prototype.remoteHttpGet = function(req, res, sourceUrl) {
} else {
util.puts('remote server returned bad content type: ' + contentType);
}
- var transcoder = transcoderList.createTranscoder(source, target);
+ var transcoder = new Transcoder(source, target);
remoteHeaders['content-type'] = 'video/mp4';
res.writeHead(remoteRes.statusCode, remoteHeaders);
View
@@ -0,0 +1,94 @@
+var child_process = require('child_process');
+var util = require('util');
+
+var DomJS = require('dom-js').DomJS;
+
+exports.extractInfo = function(filename, callback) {
+ var results = '';
+ var mediainfo = child_process.spawn('mediainfo', [
+ '--output=xml',
+ filename
+ ]);
+ mediainfo.stdout.on('data', function(data) {
+ results += data;
+ });
+ mediainfo.stderr.on('data', function(data) {
+ console.log('mediainfo stderr: ' + data);
+ });
+ mediainfo.on('exit', function(code) {
+ if (code == 0) {
+ var domjs = new DomJS();
+ domjs.parse(results, function(err, dom) {
+ function getProperty(el, name) {
+ for (var n = 0; n < el.children.length; n++) {
+ var child = el.children[n];
+ if (child.name == name) {
+ return child.children[0].text;
+ }
+ }
+ return null;
+ };
+ var info = {
+ format: null,
+ //duration: 0,
+ videoTracks: [],
+ audioTracks: []
+ };
+ for (var n = 0; n < dom.children.length; n++) {
+ var fileEl = dom.children[n];
+ if (fileEl.name == 'File') {
+ for (var m = 0; m < fileEl.children.length; m++) {
+ var trackEl = fileEl.children[m];
+ if (trackEl.name == 'track') {
+ switch (trackEl.attributes.type) {
+ case 'General':
+ // Format: 'Flash Video'
+ info.format = getProperty(trackEl, 'Format');
+ // Duration: '2mn 6s'
+ var duration = getProperty(trackEl, 'Duration');
+ // TODO: convert and store info.duration
+ break;
+ case 'Video':
+ var videoTrack = {
+ type: 'video',
+ // Format: AVC
+ format: getProperty(trackEl, 'Format'),
+ // Width: 640 pixels
+ width: parseInt(getProperty(trackEl, 'Width')
+ .replace(/ pixels/, '')),
+ // Height: 360 pixels
+ height: parseInt(getProperty(trackEl, 'Height')
+ .replace(/ pixels/, '')),
+ // Frame_rate: 29.970 fps
+ frameRate: parseFloat(
+ getProperty(trackEl, 'Frame_rate')
+ .replace(/ fps/, '')),
+ // Format_profile: Main@L3.0
+ profile: parseInt(
+ getProperty(trackEl, 'Format_profile')
+ .replace(/[^0-9]/g, '')),
+ // Format_settings__QPel: No
+ qpel: (getProperty(trackEl, 'Format_settings__QPel')
+ != 'No')
+ };
+ info.videoTracks.push(videoTrack);
+ break;
+ case 'Audio':
+ var audioTrack = {
+ // Format: AAC
+ format: getProperty(trackEl, 'Format')
+ };
+ info.audioTracks.push(audioTrack);
+ break;
+ }
+ }
+ }
+ }
+ }
+ callback(info);
+ });
+ } else {
+ console.log('child process exited with code ' + code);
+ }
+ });
+};
View
@@ -6,17 +6,8 @@ var Transcoder = function(source, target) {
this.target = target;
};
util.inherits(Transcoder, events.EventEmitter);
+exports.Transcoder = Transcoder;
-var NullTranscoder = function(source, target) {
- Transcoder.call(this, source, target);
+Transcoder.prototype.xx = function() {
+ //
};
-util.inherits(NullTranscoder, Transcoder);
-
-NullTranscoder.canTranscode = function(sourceMimeType, targetMimeType) {
- return false;
-};
-
-// Order is highest to lowest priority
-exports.transcoderTypes = [
- NullTranscoder
-];
View
@@ -1,27 +0,0 @@
-var transcoderTypes = require('./transcoder').transcoderTypes;
-
-var TranscoderList = function() {
- this.transcoderTypes_ = transcoderTypes.slice();
-};
-
-TranscoderList.prototype.find_ = function(sourceMimeType, targetMimeType) {
- for (var n = 0; n < this.transcoderTypes_.length; n++) {
- var transcoderType = this.transcoderTypes_[n];
- if (transcoderType.canTranscode(sourceMimeType, targetMimeType)) {
- return transcoderType;
- }
- }
- return null;
-};
-
-TranscoderList.prototype.createTranscoder = function(source, target) {
- var transcoderType = this.find_(source.mimeType, target.mimeType);
- if (!transcoderType) {
- return null;
- }
- var transcoder = new transcoderType(source, target);
- // TODO: verify?
- return transcoder;
-};
-
-exports.transcoderList = new TranscoderList();
View
@@ -23,8 +23,9 @@
"trampoline" : "./lib/server.js"
},
"dependencies": {
- "tav": ">=0.1.0",
- "node-uuid": ">=1.2.0",
+ "tav": "0.1.0",
+ "node-uuid": "1.2.0",
+ "dom-js": "0.0.6",
"airplay": ">=0.0.1"
},
"scripts": {

0 comments on commit 8aefe41

Please sign in to comment.