JavaScript library to process MP4 files in the browser, with support for progressive parsing. Inspired by the MP4Box tool from the GPAC project. It can be used to:
A demo is available here and the QUnit tests are here
###Getting Information###
Similar to MP4Box -info file.mp4, MP4Box.js can provide general information about the file (duration, number and types of tracks ...). Create an MP4Box object, set the onReady callback and provide data in the form of ArrayBuffer objects. MP4Box.js supports progressive parsing. You can provide small buffers at a time, the callback will be called when the 'moov' box is parsed.
var mp4box = new MP4Box();
mp4box.onError = function(e) {};
mp4box.onReady = function(info) {};
mp4box.appendBuffer(data);
mp4box.appendBuffer(data);
mp4box.appendBuffer(data);
...
mp4box.flush();
####onMoovStart()####
The onMoovStart callback is called when the 'moov' box is starting to be parsed, i.e. when the metadata about the file is parsed. Depending on the download speed, it may take a while to download the whole 'moov' box. The end of parsing is signaled by the onReady callback.
mp4box.onMoovStart = function (info) {
console.log("Starting to receive File Information");
}
####onReady(info)####
The onReady callback is called when the the 'moov' box has been parsed, i.e. when the metadata about the file is parsed.
mp4box.onReady = function (info) {
console.log("Received File Information");
}
The info argument is an object with the following structure.
{
"duration":360002,
"timescale":600,
"isFragmented":false,
"isProgressive":true,
"hasIOD":true,
"brands":["isom"],
"created":"2014-04-15T18:24:40.000Z",
"modified":"2014-04-15T18:24:40.000Z",
"tracks":[
{
"id":2,
"created":"2012-02-13T23:07:31.000Z",
"modified":"2014-04-16T12:22:56.000Z",
"movie_duration":360000,
"layer":0,
"alternate_group":0,
"volume":0,
"track_width":320,
"track_height":180,
"timescale":25000,
"duration":15000000,
"bitrate":120000,
"codec":"avc1.42c00d",
"video":{
"width":320,"height":180
},
"language":"und",
"nb_samples":15000
},
{
"id":3,
"created":"2012-09-12T11:14:57.000Z",
"modified":"2014-04-16T12:22:56.000Z",
"movie_duration":360002,
"layer":0,
"alternate_group":0,
"volume":1,
"track_width":0,
"track_height":0,
"timescale":44100,
"duration":26460160,
"bitrate":60000,
"codec":"mp4a.40.2",
"audio":{
"sample_rate":44100,
"channel_count":1,
"sample_size":16
},
"language":"und",
"nb_samples":25840
}
]
}
Track information object:
Video-specific information object:
Audio-specific information object:
####onError(e)####
Indicates that an error has occured during the processing. e is a String.
mp4box.onError = function (e) {
console.log("Received Error Message "+e);
}
####appendBuffer(data)####
Provides an ArrayBuffer to parse from. The ArrayBuffer must have a fileStart (Number) property indicating the 0-based position of first byte of the ArrayBuffer in the original file. Returns the offset (in the original file) that is expected to be the fileStart value of the next buffer.
var ab = getArrayBuffer();
ab.fileStart = 0;
mp4box.appendBuffer(ab);
####flush()#### Indicates that no more data will be received and that all remaining samples should be flushed in the segmentation or extraction process.
###Segmentation###
var mp4box = new MP4Box();
mp4box.onReady = function(info) {
...
mp4box.onSegment = function (id, user, buffer) {}
mp4box.setSegmentOptions(info.tracks[0].id, sb, options);
var initSegs = mp4box.initializeSegmentation();
...
};
####setSegmentOptions(track_id, user, options)####
Indicates that the track with the given track_id should be segmented, with the given options. When segments are ready, the callback onSegment is called with the user parameter. The options argument is an object with the following properties:
mp4box.setSegmentOptions(1, sb, { nbSamples: 1000 });
####unsetSegmentOptions(track_id)####
Indicates that the track with the given track_id should not be segmented.
mp4box.unsetSegmentOptions(1);
####onSegment(id, user, buffer)####
Callback called when a segment is ready, according to the options passed in setSegmentOptions. user is the caller of the segmentation, for this track, and buffer is an ArrayBuffer containing the Movie Fragments for this segment.
mp4box.onSegment = function (id, user, buffer) {
console.log("Received segment on track "+id+" for object "+user+" with a length of "+buffer.byteLength);
}
####initializeSegmentation()#### Indicates that the application is ready to receive segments. Returns an array of objects containing the following properties:
[
{
"id":2,
"buffer":"[ArrayBuffer]",
"user":"[SourceBuffer]"
},
{
"id":3,
"buffer":"[ArrayBuffer]",
"user":"[SourceBuffer]"
}
]
###Extraction### It is possible to extract the samples of a track, in a similar manner to the segmentation process.
var mp4box = new MP4Box();
mp4box.onReady = function(info) {
...
/* create a texttrack */
var texttrack = v.addTextTrack("metadata", "Text track for extraction of track "+info.tracks[0].id);
mp4box.onSamples = function (id, user, samples) {}
mp4box.setExtractionsOptions(info.tracks[0].id, texttrack, options);
...
};
####setExtractionOptions(track_id, user, options)####
Indicates that the track with the given track_id for which samples should be extracted, with the given options. When samples are ready, the callback onSamples is called with the user parameter. The options argument is an object with the following properties:
mp4box.setExtractionOptions(1, texttrack, { nbSamples: 1000 });
####unsetExtractionOptions(track_id)####
Indicates that the samples for the track with the given track_id should not be extracted.
mp4box.unsetExtractionOptions(1);
####onSamples(id, user, samples)####
Callback called when a set of samples is ready, according to the options passed in setExtractionOptions. user is the caller of the segmentation, for this track, and samples is an Array of samples.
mp4box.onSamples = function (id, user, samples) {
console.log("Received "+samples.length+" samples on track "+id+" for object "+user);
}
Each sample has the following structure:
{
"track_id":4,
"description": [Box],
"is_rap":true,
"timescale":1000,
"dts":0,
"cts":0,
"duration":1000,
"size":41,
"data": [ArrayBuffer]
}
####seek(time, useRap)#### Indicates that the next samples to process (for extraction or segmentation) start at the given time (Number, in seconds) or at the time of the previous Random Access Point (if useRap is true, default is false). Returns the offset in the file of the next bytes to be provided via appendBuffer .
mp4box.seek(10, true);
This code uses DataStream.js, with some modifications for Uint24 and Uint64 types.
There is currently no build system. In order to use the MP4Box.js in a browser, you need to include all files as follows.
<html>
<head>
<meta charset="utf-8">
<title>MP4Box.js in the browser</title>
<script src="log.js"></script>
<script src="DataStream.js"></script>
<script src="descriptor.js"></script>
<script src="box.js"></script>
<script src="text-mp4.js"></script>
<script src="isofile.js"></script>
<script src="mp4box.js"></script>
</head>
<body>
...
</body>
</html>