-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5a5be57
Showing
6 changed files
with
371 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/node_modules |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Copyright (c) 2014, CableLabs, Inc. | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# MPEG-TS Sections in JavaScript | ||
|
||
Author: Brendan Long <[email protected]> | ||
|
||
This library decodes [MPEG-TS program-specific information][mpegts-psi] into JSON. It's intended to be used with [HTML5 DataCues][datacue], but will work in any case where you have an `ArrayBuffer`. | ||
|
||
## Using this library | ||
|
||
To use, copy mpegtssections.js into your application's script directory, then add something like this to the `<head>` of your HTML page(s): | ||
|
||
<script src="your-script-directory/mpegtssections.js"></script> | ||
|
||
You can then use `MpegTs` methods in your JavaScript code. | ||
|
||
## API Documentation | ||
|
||
### Data Structures | ||
|
||
The following uses [Web IDL][webidl] syntax to describe the resulting data structures. The attribute names are taken directly from the MPEG-TS spec. | ||
|
||
#### Generic MPEG-TS Section | ||
|
||
interface MpegTsSyntaxSection { | ||
attribute unsigned short table_id_extension; | ||
attribute octet version_number; | ||
attribute boolean current_next_indicator; | ||
attribute octet section_number; | ||
attribute octet last_section_number; | ||
attribute unsigned long crc32; | ||
} | ||
|
||
interface MpegTsSection { | ||
attribute octet table_id; | ||
attribute unsigned short section_length; | ||
attribute MpegTsSyntaxSection? syntax_section; | ||
} | ||
|
||
interface MpegTsDescriptor { | ||
attribute octet tag; | ||
attribute octet length; // in bytes | ||
attribute ArrayBuffer data; | ||
} | ||
|
||
#### Program Association Section | ||
|
||
See Table 2-25 - Program association section | ||
|
||
interface MpegTsPatProgramInfo { | ||
attribute unsigned short program_number; | ||
|
||
attribute unsigned short? network_PID; // if program_number == 0 | ||
attribute unsigned short? program_map_PID; // if program_number != 0 | ||
} | ||
|
||
interface MpegTsPat implements MpegTsSection { | ||
attribute unsigned short transport_stream_id; | ||
attribute MpegTsPatProgramInfo[] program_info; | ||
} | ||
|
||
#### Conditional Access Table | ||
|
||
See Table 2-27 - Conditional access section. | ||
|
||
interface MpegTsCat implements MpegTsSection { | ||
attribute MpegTsDescriptor[] descriptors; | ||
} | ||
|
||
#### Program Map Table | ||
|
||
See Table 2-28 - Transport Stream program map section. | ||
|
||
interface MpegTsElementaryStream { | ||
attribute octet stream_type; | ||
attribute unsigned short elementary_PID; | ||
attribute unsigned short ES_info_length; | ||
attribute MpegTsDescriptor[] descriptors; | ||
} | ||
|
||
interface MpegTsPmt implements MpegTsSection { | ||
attribute unsigned short? PCR_PID; // 8191 maps to null | ||
attribute octet program_info_length; | ||
attribute MpegTsDescriptor[] descriptors; | ||
attribute MpegTsElementaryStreamData[] stream_info; | ||
} | ||
|
||
#### Private Section | ||
|
||
See Table 2-30 - Private Section | ||
|
||
interface MpegTsPrivateSection implements MpegTsSection { | ||
attribute boolean private_indicator; | ||
attribute unsigned short private_section_length; | ||
attribute MpegTsSyntaxSection? syntax_section; | ||
ArrayBuffer private_data; | ||
} | ||
|
||
#### Transport Stream Description | ||
|
||
See Table 2-30-1 - The Transport Stream Description Table | ||
|
||
interface MpegTsDescriptionSection implements MpegTsSection { | ||
attribute MpegTsDescriptor[] descriptors; | ||
} | ||
|
||
#### Functions | ||
|
||
`String MpegTs.decodeTable(ArrayBuffer buf, boolean checkReservedBits)` | ||
|
||
If `buf` is a PSI table (starting with the `table_id`), it will be decoded into the most appropriate type, using the following algorithm: | ||
|
||
1. If there are any serious problems with the data (lengths are wrong), throw an exception. | ||
2. If the `table_id` is 0, return an `MpegTsPat`. | ||
3. If the `table_id` is 1, return an `MpegTsCat`. | ||
4. If the `table_id` is 2, return an `MpegTsPmt`. | ||
5. If the `table_id` is 3, return an `MpegTsDescriptionSection`. | ||
6. If the `table_id` is >= 128, return an `MpegTsPrivateSection`. | ||
7. If the `sectionSyntaxIndicator` is `true`, return an `MpegTsTableWithSyntaxSection`. | ||
8. Return an `MpegTsTable`. | ||
|
||
[datacue]: http://www.w3.org/html/wg/drafts/html/CR/embedded-content-0.html#datacue | ||
[mpegts-psi]: http://en.wikipedia.org/wiki/Program-specific_information | ||
[webidl]: http://www.w3.org/TR/WebIDL/ |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* Copyright (c) 2014, CableLabs, Inc. | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright notice, | ||
* this list of conditions and the following disclaimer. | ||
* | ||
* 2. Redistributions in binary form must reproduce the above copyright notice, | ||
* this list of conditions and the following disclaimer in the documentation | ||
* and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
/*jslint browser: true, node: true, bitwise: true, plusplus: true, vars: true, | ||
indent: 4, maxlen: 80 */ | ||
(function (exports) { | ||
"use strict"; | ||
|
||
/* Constants */ | ||
var TableIds = { | ||
PROGRAM_ASSOCIATION_SECTION: 0, | ||
CONDITIONAL_ACCESS_SECTION: 1, | ||
TS_PROGRAM_MAP_SECTION: 2, | ||
TS_DESCRIPTION_SECTION: 3, | ||
ISO_IEC_14496_SCENE_DESCRIPTION_SECTION: 4, | ||
ISO_IEC_14496_OBJECT_DESCRIPTION_SECTION: 5 | ||
}; | ||
|
||
var ReservedPids = { | ||
PROGRAM_ASSOCIATION: 0, | ||
CONDITIONAL_ACCESS: 1, | ||
TRANSPORT_STREAM_DESCRIPTION: 2 | ||
}; | ||
|
||
/* Errors */ | ||
function defineError(name, defaultMessage) { | ||
function NewError(message) { | ||
this.name = name; | ||
this.message = message; | ||
} | ||
NewError.prototype = new Error(); | ||
NewError.prototype.constructor = NewError; | ||
return NewError; | ||
} | ||
var BadSizeError = defineError("BadSizeError"); | ||
var MissingSyntaxSectionError = defineError("MissingSyntaxSectionError"); | ||
|
||
/* Functions */ | ||
function decodeSection(buf) { | ||
if (!buf || !(buf instanceof ArrayBuffer)) { | ||
throw new TypeError("Expected an ArrayBuffer as the first " + | ||
"argument but got " + typeof buf + ": " + buf); | ||
} | ||
|
||
if (buf.byteLength < 3) { | ||
throw new BadSizeError("MPEG-TS sections must be at least 3 " + | ||
"bytes long, but got buffer with length " + buf.byteLength); | ||
} | ||
|
||
var view = new DataView(buf); | ||
// check CRC32? | ||
|
||
var section = { | ||
table_id: view.getUint8(0), | ||
section_length: view.getUint16(1) & 0xFFF | ||
}; | ||
|
||
// if section_syntax_indicator is set, parse the syntax section | ||
if ((view.getUint8(1) & 0x80) >> 7) { | ||
if (buf.byteLength < 7) { | ||
throw new BadSizeError("section_syntax_indicator is 1, but " + | ||
"the buffer is not long enough to contain a valid " + | ||
"syntax section"); | ||
} | ||
|
||
section.syntax_section = { | ||
table_id_extension: view.getUint16(3), | ||
version_number: (view.getUint8(5) & 0x3E) >> 1, | ||
current_next_indicator: view.getUint8(5) & 1, | ||
section_number: view.getUint8(6), | ||
last_section_number: view.getUint8(7), | ||
CRC: view.getUint32(buf.byteLength - 4) // check this | ||
}; | ||
} else { | ||
section.syntax_section = null; | ||
} | ||
|
||
switch (section.table_id) { | ||
case TableIds.PROGRAM_ASSOCIATION_SECTION: | ||
if (!section.syntax_section) { | ||
throw new MissingSyntaxSectionError("Program access section " + | ||
"requires a syntax section, but " + | ||
"section_syntax_indicator is 0"); | ||
} | ||
section.transport_stream_id = view.getUint16(3); | ||
// program info | ||
break; | ||
case TableIds.CONDITIONAL_ACCESS_SECTION: | ||
case TableIds.TS_DESCRIPTION_SECTION: | ||
// descriptors | ||
break; | ||
case TableIds.TS_PROGRAM_MAP_SECTION: | ||
section.program_number = view.getUint16(3); | ||
section.PCR_PID = view.getUint16(8) & 0x1FFF; | ||
section.program_info_length = view.getUint16(10) & 0xFFF; | ||
section.streams = []; | ||
|
||
var stream_start = 12 + section.program_info_length; | ||
var streams_end = buf.byteLength - 4 - 5; | ||
var i = 0; | ||
while (stream_start <= streams_end) { | ||
section.streams[i] = { | ||
stream_type: view.getUint8(stream_start), | ||
elementary_PID: view.getUint16(stream_start + 1) & 0x1FFF, | ||
ES_info_length: view.getUint16(stream_start + 3) & 0xFFF | ||
}; | ||
stream_start += 5 + section.streams[i].ES_info_length; | ||
++i; | ||
} | ||
break; | ||
default: | ||
if (section.table_id >= 128) { | ||
// private data | ||
} | ||
break; | ||
} | ||
return section; | ||
} | ||
|
||
exports.TableIds = TableIds; | ||
exports.ReservedPids = ReservedPids; | ||
|
||
exports.BadSizeError = BadSizeError; | ||
exports.MissingSyntaxSectionError = MissingSyntaxSectionError; | ||
|
||
exports.decodeSection = decodeSection; | ||
}(typeof exports === 'undefined' ? this.MpegTs = {} : exports)); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"author": { | ||
"name": "Brendan Long", | ||
"email": "[email protected]", | ||
"url": "https://www.brendanlong.com" | ||
}, | ||
"bugs": "https://github.com/cablelabs/mpegtssections-js/issues", | ||
"devDependencies": { | ||
"jshint": "2.5.x", | ||
"nodeunit": "0.8.x" | ||
}, | ||
"homepage": "https://github.com/cablelabs/mpegtssections-js", | ||
"license": "BSD-2-Clause", | ||
"main": "./lib/mpegtssections", | ||
"name": "mpegtssections", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/cablelabs/mpegtssections-js.git" | ||
}, | ||
"scripts": { | ||
"hint": "./node_modules/.bin/jshint --show-non-errors lib/mpegtssections.js test/tests.js", | ||
"test": "./node_modules/.bin/nodeunit test" | ||
}, | ||
"version": "1.0.0" | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* Copyright (c) 2014, CableLabs, Inc. | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright notice, | ||
* this list of conditions and the following disclaimer. | ||
* | ||
* 2. Redistributions in binary form must reproduce the above copyright notice, | ||
* this list of conditions and the following disclaimer in the documentation | ||
* and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
/*jslint browser: true, node: true, plusplus: true, vars: true, indent: 4 */ | ||
"use strict"; | ||
var MpegTs = require('../lib/mpegtssections'); | ||
|
||
exports.TestBufArgumentNull = function(test) { | ||
test.throws(function() { | ||
MpegTs.decodeSection(null); | ||
}, TypeError); | ||
test.done(); | ||
}; | ||
|
||
exports.TestBufArgumentUndefined = function(test) { | ||
test.throws(function() { | ||
MpegTs.decodeSection(); | ||
}, TypeError); | ||
test.done(); | ||
}; | ||
|
||
exports.testBufArgumentWrongType = function(test) { | ||
test.throws(function() { | ||
MpegTs.decodeSection([5]); | ||
}, TypeError); | ||
test.done(); | ||
}; | ||
|
||
exports.testBufArgumentTooSmall = function(test) { | ||
test.throws(function() { | ||
var data = new Uint8Array([1, 2]).buffer; | ||
MpegTs.decodeSection(data); | ||
}, MpegTs.BadSizeError); | ||
test.done(); | ||
}; | ||
|
||
exports.TestUserPrivateData = function(test) { | ||
var data = new Uint8Array([227, 64, 136, 251, 251, 0, 59, 176, 126, 0, 1, 193, 0, 0, 17, 3, 16, 2, 128, 0, 0, 1, 255, 0, 0, 105, 0, 0, 0, 1, 3, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 12, 1, 60, 59, 67, 97, 98, 108, 101, 108, 97, 98, 115, 95, 78, 97, 116, 105, 111, 110, 97, 108, 95, 101, 116, 118, 95, 115, 116, 114, 101, 97, 109, 95, 99, 111, 110, 102, 105, 103, 47, 109, 97, 105, 110, 97, 112, 112, 47, 49, 46, 48, 47, 109, 97, 105, 110, 95, 112, 114, 46, 112, 114, 0, 15, 14, 105, 98, 46, 116, 118, 119, 111, 114, 107, 115, 46, 99, 111, 109, 225, 54, 136, 221, 188, 252, 142, 137]).buffer; | ||
var section = MpegTs.decodeSection(data); | ||
test.ok(section, "Section should not be null"); | ||
test.done(); | ||
}; |