control-freak-ide/server/nodejs/vlc-ffi/lib/media.js
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

292 lines
7.1 KiB
JavaScript

var ref = require('ref');
var lib = require('./libvlc');
var util = require('./util');
var TrackInfo = require('./libvlc_types').TrackInfo;
var MediaStats = require('./libvlc_types').MediaStats;
var EventPtr = require('./libvlc_types').EventPtr;
var metaName = require('./media_enum').metaName;
var metaEnum = require('./media_enum').metaEnum;
var state = require('./media_enum').state;
var EventEmitter = require('events').EventEmitter;
var trackType = {
unknown: -1,
'-1': 'unknown',
audio: 0,
'0': 'audio',
video: 1,
'1': 'video',
text: 2,
'2': 'text'
};
var ffi = require('ffi');
var libc = ffi.Library(null, {
//'free': ['void', [ 'pointer' ]]
});
var VALID_EVENTS = {
MetaChanged: 0,
SubItemAdded: 1,
DurationChanged: 2,
ParsedChanged: 3,
Freed: 4,
StateChanged: 5,
0: 'MetaChanged',
1: 'SubItemAdded',
2: 'DurationChanged',
3: 'ParsedChanged',
4: 'Freed',
5: 'StateChanged'
};
var event_handler = function(e, d) {
var event = e.deref();
var obj = d.deref();
var union = event.u;
var name, arg;
if (obj.instance.address() != event.p_obj.address())
return;
switch (event.type) {
case 0:
name = 'MetaChanged';
arg = metaEnum[union.media_meta_changed.meta_type];
break;
case 1:
name = 'SubItemAdded';
arg = new Media(obj.parent, union.media_subitem_added.new_child);
break;
case 2:
name = 'DurationChanged';
arg = union.media_duration_changed.new_duration;
break;
case 3:
name = 'ParsedChanged';
arg = union.media_parsed_changed.new_status;
break;
case 4:
name = 'Freed';
arg = new Media(obj.parent, union.media_freed.md);
break;
case 5:
name = 'StateChanged';
arg = state[union.media_state_changed.new_state];
break;
}
console.log('event type ' + name,arg);
if (name) {
obj.emit(name, arg);
}
};
var eventcb = ffi.Callback(ref.types.void, [
EventPtr,
ref.refType(ref.types.Object)
], event_handler);
var Media = module.exports = function (parent, reinit, opts) {
var self = this;
var released = false;
var eventmgr;
this.parent = parent;
this._path = null;
var selfref = ref.alloc(ref.types.Object, self);
if (reinit) {
self.instance = reinit;
} else if (opts.path) {
self.instance = lib.libvlc_media_new_path(parent, opts.path);
self._path = opts.path;
} else if (opts.url) {
self.instance = lib.libvlc_media_new_location(parent, opts.url);
self._path = opts.url;
} else if (opts.fd) {
self.instance = lib.libvlc_media_new_fd(parent, opts.fd);
self._path = opts.fd;
} else {
self.instance = lib.libvlc_media_new_as_node(parent,"1");
}
if(opts && opts.path){
self._path = opts.path;
}
this.release = function () {
if (!released) {
lib.libvlc_media_release(self.instance);
released = true;
}
};
this.parseSync = function () {
lib.libvlc_media_parse(self.instance);
};
this.position = function () {
return lib.libvlc_vlm_get_media_instance_position(self.parent,"",self.instance);
};
this.saveSync = function () {
lib.libvlc_media_save_meta(self.instance);
};
Object.defineProperty(this, 'path', {
get: function () {
return self._path
},
set: function (path) {
console.error('set path ' + path);
self._path = path
}
});
this.getPath =function(){
return self._path;
};
Object.defineProperty(this, 'mrl', {
get: function () {
return lib.libvlc_media_get_mrl(self.instance);
}
});
Object.defineProperty(this, 'is_parsed', {
get: function () {
return lib.libvlc_media_is_parsed(self.instance);
}
});
Object.defineProperty(this, 'duration', {
get: function () {
return lib.libvlc_media_get_duration(self.instance);
}
});
Object.defineProperty(this, 'track_info', {
get: function () {
var i, ptr, tmp;
var results = [];
var info = new Buffer(ref.sizeof.pointer);
var tracks = lib.libvlc_media_get_tracks_info(self.instance, info);
info = info.readPointer(0, TrackInfo.size * tracks);
for (i = 0; i < tracks; i++) {
ptr = ref.get(info, i * TrackInfo.size, TrackInfo);
tmp = {
codec: ptr.i_codec,
id: ptr.i_id,
type: trackType[ptr.i_type],
profile: ptr.i_profile,
level: ptr.i_level
};
switch (tmp.type) {
case 'audio':
tmp.channels = ptr.union1;
tmp.rate = ptr.union2;
break;
case 'video':
tmp.height = ptr.union1;
tmp.width = ptr.union2;
break;
}
results.push(tmp);
}
//libc.free(info);
info = undefined;
return results;
}
});
Object.defineProperty(this, 'stats', {
get: function () {
var ret, stats, tmp;
stats = ref.alloc(MediaStats);
ret = lib.libvlc_media_get_stats(self.instance, stats);
stats = stats.deref();
tmp = {
read_bytes: stats.i_read_bytes,
input_bitrate: stats.f_input_bitrate,
demux_read_bytes: stats.i_demux_read_bytes,
demux_bitrate: stats.f_demux_bitrate,
demux_corrupted: stats.i_demux_corrupted,
demux_discontinuity: stats.i_demux_discontinuity,
decoded_video: stats.i_decoded_video,
decoded_audio: stats.i_decoded_audio,
displayed_pictures: stats.i_displayed_pictures,
lost_pictures: stats.i_lost_pictures,
played_abuffers: stats.i_played_abuffers,
lost_abuffers: stats.i_lost_abuffers,
sent_packets: stats.i_sent_packets,
sent_bytes: stats.i_sent_bytes,
send_bitrate: stats.f_send_bitrate
};
return ret === 0 ? util.throw() : tmp;
}
});
Object.keys(metaName).forEach(function (meta) {
Object.defineProperty(self, meta, {
get: function () {
return lib.libvlc_media_get_meta(self.instance, metaName[meta]);
},
set: function (val) {
lib.libvlc_media_set_meta(self.instance, metaName[meta], val);
},
enumerable: true,
configurable: true
});
});
var _on = this.on;
this.on = function (e, cb) {
var tmp;
if (!eventmgr) {
eventmgr = lib.libvlc_media_event_manager(self.instance);
}
if (VALID_EVENTS[e] !== undefined) {
if (!self._events || !self._events[e]) {
tmp = lib.libvlc_event_attach(eventmgr, VALID_EVENTS[e], eventcb, selfref);
if (tmp != 0) util.throw();
}
_on.call(self, e, cb);
} else {
throw new Error("Not a valid event type: " + e + " not in " + Object.keys(VALID_EVENTS));
}
};
var _rl = this.removeListener;
this.removeListener = function (e, cb) {
if (!eventmgr)
return;
if (VALID_EVENTS[e] !== undefined) {
if (self._events && ((self._events[e] instanceof Function) || self._events[e].length === 1)) {
lib.libvlc_event_detach(eventmgr, VALID_EVENTS[e], eventcb, selfref);
}
_rl.call(self, e, cb);
} else {
throw new Error("Not a valid event type: " + e + " not in " + Object.keys(VALID_EVENTS));
}
};
};
require('util').inherits(Media, EventEmitter);