Bump @justinribeiro/lite-youtube from 0.9.0 to 0.9.1 in /build/javascript (#273)
* Commit updated Javascript packages * Bump preact from 10.5.4 to 10.5.5 in /build/javascript (#265) * Trying a new github workflow to install javascript packages * Bump tailwindcss from 1.9.2 to 1.9.4 in /build/javascript (#266) Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss) from 1.9.2 to 1.9.4. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/master/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/compare/v1.9.2...v1.9.4) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Commit updated Javascript packages * Bump preact from 10.5.4 to 10.5.5 in /build/javascript Bumps [preact](https://github.com/preactjs/preact) from 10.5.4 to 10.5.5. - [Release notes](https://github.com/preactjs/preact/releases) - [Commits](https://github.com/preactjs/preact/compare/10.5.4...10.5.5) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Gabe Kangas <gabek@real-ity.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Owncast <owncast@owncast.online> * Bump @justinribeiro/lite-youtube in /build/javascript Bumps [@justinribeiro/lite-youtube](https://github.com/justinribeiro/lite-youtube) from 0.9.0 to 0.9.1. - [Release notes](https://github.com/justinribeiro/lite-youtube/releases) - [Commits](https://github.com/justinribeiro/lite-youtube/commits) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Owncast <owncast@owncast.online> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
79
build/javascript/node_modules/@videojs/vhs-utils/CHANGELOG.md
generated
vendored
Normal file
79
build/javascript/node_modules/@videojs/vhs-utils/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<a name="2.2.1"></a>
|
||||
## [2.2.1](https://github.com/videojs/stream/compare/v2.2.0...v2.2.1) (2020-10-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check for multiple id3 sections in a file (#21) ([759a039](https://github.com/videojs/stream/commit/759a039)), closes [#21](https://github.com/videojs/stream/issues/21)
|
||||
* parse unknown codecs as audio or video (#15) ([cd2c9bb](https://github.com/videojs/stream/commit/cd2c9bb)), closes [#15](https://github.com/videojs/stream/issues/15)
|
||||
|
||||
### Reverts
|
||||
|
||||
* "fix: parse unknown codecs as audio or video (#15)" (#18) ([9983be8](https://github.com/videojs/stream/commit/9983be8)), closes [#15](https://github.com/videojs/stream/issues/15) [#18](https://github.com/videojs/stream/issues/18)
|
||||
|
||||
<a name="2.2.0"></a>
|
||||
# [2.2.0](https://github.com/videojs/stream/compare/v2.1.0...v2.2.0) (2020-05-01)
|
||||
|
||||
### Features
|
||||
|
||||
* Add a function to concat typed arrays into one Uint8Array (#13) ([e733509](https://github.com/videojs/stream/commit/e733509)), closes [#13](https://github.com/videojs/stream/issues/13)
|
||||
|
||||
<a name="2.1.0"></a>
|
||||
# [2.1.0](https://github.com/videojs/stream/compare/v2.0.0...v2.1.0) (2020-04-27)
|
||||
|
||||
### Features
|
||||
|
||||
* Add functions for byte manipulation and segment container detection (#12) ([325f677](https://github.com/videojs/stream/commit/325f677)), closes [#12](https://github.com/videojs/stream/issues/12)
|
||||
|
||||
<a name="2.0.0"></a>
|
||||
# [2.0.0](https://github.com/videojs/stream/compare/v1.3.0...v2.0.0) (2020-04-07)
|
||||
|
||||
### Features
|
||||
|
||||
* **codec:** changes to handle muxer/browser/video/audio support separately (#10) ([1f92865](https://github.com/videojs/stream/commit/1f92865)), closes [#10](https://github.com/videojs/stream/issues/10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Allow VP9 and AV1 codecs through in VHS ([b32e35b](https://github.com/videojs/stream/commit/b32e35b))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **codec:** parseCodecs output has been changed. It now returns an object that can have an audio or video property, depending on the codecs found. Those properties are object that contain type. and details. Type being the codec name and details being codec specific information usually with a leading period.
|
||||
* **codec:** `audioProfileFromDefault` has been renamed to `codecsFromDefault` and now returns all output from `parseCodecs` not just audio or audio profile.
|
||||
|
||||
<a name="1.3.0"></a>
|
||||
# [1.3.0](https://github.com/videojs/vhs-utils/compare/v1.2.1...v1.3.0) (2020-02-05)
|
||||
|
||||
### Features
|
||||
|
||||
* add forEachMediaGroup in media-groups module (#8) ([a1eacf4](https://github.com/videojs/vhs-utils/commit/a1eacf4)), closes [#8](https://github.com/videojs/vhs-utils/issues/8)
|
||||
|
||||
<a name="1.2.1"></a>
|
||||
## [1.2.1](https://github.com/videojs/vhs-utils/compare/v1.2.0...v1.2.1) (2020-01-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* include videojs in VHS JSON media type (#7) ([da072f0](https://github.com/videojs/vhs-utils/commit/da072f0)), closes [#7](https://github.com/videojs/vhs-utils/issues/7)
|
||||
|
||||
<a name="1.2.0"></a>
|
||||
# [1.2.0](https://github.com/videojs/vhs-utils/compare/v1.1.0...v1.2.0) (2019-12-06)
|
||||
|
||||
### Features
|
||||
|
||||
* add media-types module with simpleTypeFromSourceType function (#4) ([d3ebd3f](https://github.com/videojs/vhs-utils/commit/d3ebd3f)), closes [#4](https://github.com/videojs/vhs-utils/issues/4)
|
||||
* add VHS codec parsing and translation functions (#5) ([4fe0e22](https://github.com/videojs/vhs-utils/commit/4fe0e22)), closes [#5](https://github.com/videojs/vhs-utils/issues/5)
|
||||
|
||||
<a name="1.1.0"></a>
|
||||
# [1.1.0](https://github.com/videojs/stream/compare/v1.0.0...v1.1.0) (2019-08-30)
|
||||
|
||||
### Features
|
||||
|
||||
* node support and more stream tests ([315ab8d](https://github.com/videojs/stream/commit/315ab8d))
|
||||
|
||||
<a name="1.0.0"></a>
|
||||
# 1.0.0 (2019-08-21)
|
||||
|
||||
### Features
|
||||
|
||||
* clones from mpd-parser, m3u8-parser, mux.js, aes-decrypter, and vhs ([5e89042](https://github.com/videojs/stream/commit/5e89042))
|
||||
|
||||
30
build/javascript/node_modules/@videojs/vhs-utils/CONTRIBUTING.md
generated
vendored
Normal file
30
build/javascript/node_modules/@videojs/vhs-utils/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# CONTRIBUTING
|
||||
|
||||
We welcome contributions from everyone!
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have Node.js 8 or higher and npm installed.
|
||||
|
||||
1. Fork this repository and clone your fork
|
||||
1. Install dependencies: `npm install`
|
||||
1. Run a development server: `npm start`
|
||||
|
||||
### Making Changes
|
||||
|
||||
Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship.
|
||||
|
||||
When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository.
|
||||
|
||||
### Running Tests
|
||||
|
||||
Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma].
|
||||
|
||||
- In all available and supported browsers: `npm test`
|
||||
- In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc.
|
||||
- While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local]
|
||||
|
||||
|
||||
[karma]: http://karma-runner.github.io/
|
||||
[local]: http://localhost:9999/test/
|
||||
[conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md
|
||||
19
build/javascript/node_modules/@videojs/vhs-utils/LICENSE
generated
vendored
Normal file
19
build/javascript/node_modules/@videojs/vhs-utils/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) brandonocasey <brandonocasey@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
29
build/javascript/node_modules/@videojs/vhs-utils/README.md
generated
vendored
Normal file
29
build/javascript/node_modules/@videojs/vhs-utils/README.md
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
|
||||
- [@videojs/vhs-utils](#videojsvhs-utils)
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# @videojs/vhs-utils
|
||||
|
||||
vhs-utils serves two purposes:
|
||||
|
||||
1. It extracts objects and functions shared throughout @videojs/http-streaming code to save on package size. See [the original @videojs/http-streaming PR](https://github.com/videojs/http-streaming/pull/637) for details.
|
||||
2. It exports generic functions from VHS that may be useful to plugin authors.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install --save @videojs/vhs-utils
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
All utility functions are published under dist and can be required/imported like so:
|
||||
|
||||
`import resolveUrl from '@videojs/vhs-utils/dist/resolve-url';`
|
||||
`const resolveUrl = require('@videojs/vhs-utils/dist/resolve-url');`
|
||||
27
build/javascript/node_modules/@videojs/vhs-utils/index.html
generated
vendored
Normal file
27
build/javascript/node_modules/@videojs/vhs-utils/index.html
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>videojs-stream Demo</title>
|
||||
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<video id="videojs-stream-player" class="video-js vjs-default-skin" controls>
|
||||
<source src="//vjs.zencdn.net/v/oceans.mp4" type='video/mp4'>
|
||||
<source src="//vjs.zencdn.net/v/oceans.webm" type='video/webm'>
|
||||
</video>
|
||||
<ul>
|
||||
<li><a href="/test/debug.html">Run unit tests in browser.</a></li>
|
||||
|
||||
</ul>
|
||||
<script src="node_modules/video.js/dist/video.js"></script>
|
||||
<script src="dist/videojs-stream.js"></script>
|
||||
<script>
|
||||
(function(window, videojs) {
|
||||
var examplePlayer = window.examplePlayer = videojs('videojs-stream-player');
|
||||
var stream = window.stream = examplePlayer.stream();
|
||||
}(window, window.videojs));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
120
build/javascript/node_modules/@videojs/vhs-utils/package.json
generated
vendored
Normal file
120
build/javascript/node_modules/@videojs/vhs-utils/package.json
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"@videojs/vhs-utils@2.2.1",
|
||||
"/home/runner/work/owncast/owncast/build/javascript"
|
||||
]
|
||||
],
|
||||
"_from": "@videojs/vhs-utils@2.2.1",
|
||||
"_id": "@videojs/vhs-utils@2.2.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-9Qbwx3LAdkG1jh2HKfninjXDxVZCeaoPcmct/bUcDRmLej68Z9XhLe5d2a9fy1qB+UuQwWg7YySASesWavYNjQ==",
|
||||
"_location": "/@videojs/vhs-utils",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "@videojs/vhs-utils@2.2.1",
|
||||
"name": "@videojs/vhs-utils",
|
||||
"escapedName": "@videojs%2fvhs-utils",
|
||||
"scope": "@videojs",
|
||||
"rawSpec": "2.2.1",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "2.2.1"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@videojs/http-streaming"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-2.2.1.tgz",
|
||||
"_spec": "2.2.1",
|
||||
"_where": "/home/runner/work/owncast/owncast/build/javascript",
|
||||
"author": {
|
||||
"name": "brandonocasey",
|
||||
"email": "brandonocasey@gmail.com"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults",
|
||||
"ie 11"
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"global": "^4.3.2",
|
||||
"url-toolkit": "^2.1.6"
|
||||
},
|
||||
"description": "Objects and functions shared throughtout @videojs/http-streaming code",
|
||||
"devDependencies": {
|
||||
"@videojs/generator-helpers": "~1.2.0",
|
||||
"karma": "^4.0.0",
|
||||
"rollup": "^1.12.0",
|
||||
"videojs-generate-karma-config": "~5.3.0",
|
||||
"videojs-generate-rollup-config": "~5.0.0",
|
||||
"videojs-generator-verify": "~1.2.0",
|
||||
"videojs-standard": "^8.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"files": [
|
||||
"CONTRIBUTING.md",
|
||||
"dist/",
|
||||
"docs/",
|
||||
"index.html",
|
||||
"scripts/",
|
||||
"src/",
|
||||
"test/"
|
||||
],
|
||||
"generator-videojs-plugin": {
|
||||
"version": "7.7.1"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"videojs",
|
||||
"videojs-plugin"
|
||||
],
|
||||
"license": "MIT",
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"vjsstandard --fix",
|
||||
"git add"
|
||||
],
|
||||
"README.md": [
|
||||
"doctoc --notitle",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"name": "@videojs/vhs-utils",
|
||||
"scripts": {
|
||||
"build": "npm-run-all -s clean -p build:*",
|
||||
"build-prod": "cross-env-shell NO_TEST_BUNDLE=1 'npm run build'",
|
||||
"build-test": "cross-env-shell TEST_BUNDLE_ONLY=1 'npm run build'",
|
||||
"build:js": "rollup -c scripts/rollup.config.js",
|
||||
"clean": "shx rm -rf ./dist ./test/dist && shx mkdir -p ./dist ./test/dist",
|
||||
"lint": "vjsstandard",
|
||||
"posttest": "shx cat test/dist/coverage/text.txt",
|
||||
"prepublishOnly": "npm-run-all build-prod && vjsverify --verbose --skip-es-check",
|
||||
"preversion": "npm test",
|
||||
"server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch",
|
||||
"start": "npm-run-all -p server watch",
|
||||
"test": "npm-run-all lint build-test && npm-run-all test:*",
|
||||
"test:browser": "karma start scripts/karma.conf.js",
|
||||
"test:node": "qunit test/dist/bundle.js",
|
||||
"update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s",
|
||||
"version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md",
|
||||
"watch": "npm-run-all -p watch:*",
|
||||
"watch:js": "npm run build:js -- -w",
|
||||
"watch:node": "npm run test:node -- --watch"
|
||||
},
|
||||
"version": "2.2.1",
|
||||
"vjsstandard": {
|
||||
"ignore": [
|
||||
"dist",
|
||||
"docs",
|
||||
"test/dist"
|
||||
]
|
||||
}
|
||||
}
|
||||
12
build/javascript/node_modules/@videojs/vhs-utils/scripts/karma.conf.js
generated
vendored
Normal file
12
build/javascript/node_modules/@videojs/vhs-utils/scripts/karma.conf.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
const generate = require('videojs-generate-karma-config');
|
||||
|
||||
module.exports = function(config) {
|
||||
|
||||
// see https://github.com/videojs/videojs-generate-karma-config
|
||||
// for options
|
||||
const options = {};
|
||||
|
||||
config = generate(config, options);
|
||||
|
||||
// any other custom stuff not supported by options here!
|
||||
};
|
||||
41
build/javascript/node_modules/@videojs/vhs-utils/scripts/rollup.config.js
generated
vendored
Normal file
41
build/javascript/node_modules/@videojs/vhs-utils/scripts/rollup.config.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
const generate = require('videojs-generate-rollup-config');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const BASE_DIR = path.join(__dirname, '..');
|
||||
const SRC_DIR = path.join(BASE_DIR, 'src');
|
||||
|
||||
const files = fs.readdirSync(SRC_DIR);
|
||||
|
||||
const shared = {
|
||||
externals(defaults) {
|
||||
defaults.module.push('url-toolkit');
|
||||
return defaults;
|
||||
}
|
||||
};
|
||||
const builds = [];
|
||||
|
||||
files.forEach(function(file, i) {
|
||||
const config = generate(Object.assign({}, shared, {
|
||||
input: path.relative(BASE_DIR, path.join(SRC_DIR, file)),
|
||||
distName: path.basename(file, path.extname(file))
|
||||
}));
|
||||
|
||||
// gaurd against test only builds
|
||||
if (config.builds.module) {
|
||||
const module = config.builds.module;
|
||||
|
||||
module.output = module.output.filter((o) => o.format === 'cjs');
|
||||
module.output[0].file = module.output[0].file.replace('.cjs.js', '.js');
|
||||
builds.push(module);
|
||||
}
|
||||
|
||||
// gaurd against production only builds
|
||||
// only add the last test bundle we generate as they are all the same
|
||||
if (i === (files.length - 1) && config.builds.test) {
|
||||
builds.push(config.builds.test);
|
||||
}
|
||||
});
|
||||
|
||||
// export the builds to rollup
|
||||
export default builds;
|
||||
69
build/javascript/node_modules/@videojs/vhs-utils/src/byte-helpers.js
generated
vendored
Normal file
69
build/javascript/node_modules/@videojs/vhs-utils/src/byte-helpers.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
export const isTypedArray = (obj) => ArrayBuffer.isView(obj);
|
||||
export const toUint8 = (bytes) => (bytes instanceof Uint8Array) ?
|
||||
bytes :
|
||||
new Uint8Array(
|
||||
bytes && bytes.buffer || bytes,
|
||||
bytes && bytes.byteOffset || 0,
|
||||
bytes && bytes.byteLength || 0
|
||||
);
|
||||
|
||||
export const bytesToString = (bytes) => {
|
||||
if (!bytes) {
|
||||
return '';
|
||||
}
|
||||
|
||||
bytes = Array.prototype.slice.call(bytes);
|
||||
|
||||
const string = String.fromCharCode.apply(null, toUint8(bytes));
|
||||
|
||||
try {
|
||||
return decodeURIComponent(escape(string));
|
||||
} catch (e) {
|
||||
// if decodeURIComponent/escape fails, we are dealing with partial
|
||||
// or full non string data. Just return the potentially garbled string.
|
||||
}
|
||||
|
||||
return string;
|
||||
};
|
||||
|
||||
export const stringToBytes = (string, stringIsBytes = false) => {
|
||||
const bytes = [];
|
||||
|
||||
if (typeof string !== 'string' && string && typeof string.toString === 'function') {
|
||||
string = string.toString();
|
||||
}
|
||||
|
||||
if (typeof string !== 'string') {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// If the string already is bytes, we don't have to do this
|
||||
if (!stringIsBytes) {
|
||||
string = unescape(encodeURIComponent(string));
|
||||
}
|
||||
|
||||
return string.split('').map((s) => s.charCodeAt(0) & 0xFF);
|
||||
};
|
||||
|
||||
export const concatTypedArrays = (...buffers) => {
|
||||
const totalLength = buffers.reduce((total, buf) => {
|
||||
const len = buf && (buf.byteLength || buf.length);
|
||||
|
||||
total += len || 0;
|
||||
|
||||
return total;
|
||||
}, 0);
|
||||
|
||||
const tempBuffer = new Uint8Array(totalLength);
|
||||
|
||||
let offset = 0;
|
||||
|
||||
buffers.forEach(function(buf) {
|
||||
buf = toUint8(buf);
|
||||
|
||||
tempBuffer.set(buf, offset);
|
||||
offset += buf.byteLength;
|
||||
});
|
||||
|
||||
return tempBuffer;
|
||||
};
|
||||
198
build/javascript/node_modules/@videojs/vhs-utils/src/codecs.js
generated
vendored
Normal file
198
build/javascript/node_modules/@videojs/vhs-utils/src/codecs.js
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
import window from 'global/window';
|
||||
|
||||
const regexs = {
|
||||
// to determine mime types
|
||||
mp4: /^(av0?1|avc0?[1234]|vp0?9|flac|opus|mp3|mp4a|mp4v)/,
|
||||
webm: /^(vp0?[89]|av0?1|opus|vorbis)/,
|
||||
ogg: /^(vp0?[89]|theora|flac|opus|vorbis)/,
|
||||
|
||||
// to determine if a codec is audio or video
|
||||
video: /^(av0?1|avc0?[1234]|vp0?[89]|hvc1|hev1|theora|mp4v)/,
|
||||
audio: /^(mp4a|flac|vorbis|opus|ac-[34]|ec-3|alac|mp3)/,
|
||||
|
||||
// mux.js support regex
|
||||
muxerVideo: /^(avc0?1)/,
|
||||
muxerAudio: /^(mp4a)/
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace the old apple-style `avc1.<dd>.<dd>` codec string with the standard
|
||||
* `avc1.<hhhhhh>`
|
||||
*
|
||||
* @param {string} codec
|
||||
* Codec string to translate
|
||||
* @return {string}
|
||||
* The translated codec string
|
||||
*/
|
||||
export const translateLegacyCodec = function(codec) {
|
||||
if (!codec) {
|
||||
return codec;
|
||||
}
|
||||
|
||||
return codec.replace(/avc1\.(\d+)\.(\d+)/i, function(orig, profile, avcLevel) {
|
||||
const profileHex = ('00' + Number(profile).toString(16)).slice(-2);
|
||||
const avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2);
|
||||
|
||||
return 'avc1.' + profileHex + '00' + avcLevelHex;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace the old apple-style `avc1.<dd>.<dd>` codec strings with the standard
|
||||
* `avc1.<hhhhhh>`
|
||||
*
|
||||
* @param {string[]} codecs
|
||||
* An array of codec strings to translate
|
||||
* @return {string[]}
|
||||
* The translated array of codec strings
|
||||
*/
|
||||
export const translateLegacyCodecs = function(codecs) {
|
||||
return codecs.map(translateLegacyCodec);
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace codecs in the codec string with the old apple-style `avc1.<dd>.<dd>` to the
|
||||
* standard `avc1.<hhhhhh>`.
|
||||
*
|
||||
* @param {string} codecString
|
||||
* The codec string
|
||||
* @return {string}
|
||||
* The codec string with old apple-style codecs replaced
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export const mapLegacyAvcCodecs = function(codecString) {
|
||||
return codecString.replace(/avc1\.(\d+)\.(\d+)/i, (match) => {
|
||||
return translateLegacyCodecs([match])[0];
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} ParsedCodecInfo
|
||||
* @property {number} codecCount
|
||||
* Number of codecs parsed
|
||||
* @property {string} [videoCodec]
|
||||
* Parsed video codec (if found)
|
||||
* @property {string} [videoObjectTypeIndicator]
|
||||
* Video object type indicator (if found)
|
||||
* @property {string|null} audioProfile
|
||||
* Audio profile
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parses a codec string to retrieve the number of codecs specified, the video codec and
|
||||
* object type indicator, and the audio profile.
|
||||
*
|
||||
* @param {string} [codecString]
|
||||
* The codec string to parse
|
||||
* @return {ParsedCodecInfo}
|
||||
* Parsed codec info
|
||||
*/
|
||||
export const parseCodecs = function(codecString = '') {
|
||||
const codecs = codecString.split(',');
|
||||
const result = {};
|
||||
|
||||
codecs.forEach(function(codec) {
|
||||
codec = codec.trim();
|
||||
|
||||
['video', 'audio'].forEach(function(name) {
|
||||
const match = regexs[name].exec(codec.toLowerCase());
|
||||
|
||||
if (!match || match.length <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// maintain codec case
|
||||
const type = codec.substring(0, match[1].length);
|
||||
const details = codec.replace(type, '');
|
||||
|
||||
result[name] = {type, details};
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a ParsedCodecInfo object for the default alternate audio playlist if there is
|
||||
* a default alternate audio playlist for the provided audio group.
|
||||
*
|
||||
* @param {Object} master
|
||||
* The master playlist
|
||||
* @param {string} audioGroupId
|
||||
* ID of the audio group for which to find the default codec info
|
||||
* @return {ParsedCodecInfo}
|
||||
* Parsed codec info
|
||||
*/
|
||||
export const codecsFromDefault = (master, audioGroupId) => {
|
||||
if (!master.mediaGroups.AUDIO || !audioGroupId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const audioGroup = master.mediaGroups.AUDIO[audioGroupId];
|
||||
|
||||
if (!audioGroup) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const name in audioGroup) {
|
||||
const audioType = audioGroup[name];
|
||||
|
||||
if (audioType.default && audioType.playlists) {
|
||||
// codec should be the same for all playlists within the audio type
|
||||
return parseCodecs(audioType.playlists[0].attributes.CODECS);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const isVideoCodec = (codec = '') => regexs.video.test(codec.trim().toLowerCase());
|
||||
export const isAudioCodec = (codec = '') => regexs.audio.test(codec.trim().toLowerCase());
|
||||
|
||||
export const getMimeForCodec = (codecString) => {
|
||||
if (!codecString || typeof codecString !== 'string') {
|
||||
return;
|
||||
}
|
||||
const codecs = codecString
|
||||
.toLowerCase()
|
||||
.split(',')
|
||||
.map((c) => translateLegacyCodec(c.trim()));
|
||||
|
||||
// default to video type
|
||||
let type = 'video';
|
||||
|
||||
// only change to audio type if the only codec we have is
|
||||
// audio
|
||||
if (codecs.length === 1 && isAudioCodec(codecs[0])) {
|
||||
type = 'audio';
|
||||
}
|
||||
|
||||
// default the container to mp4
|
||||
let container = 'mp4';
|
||||
|
||||
// every codec must be able to go into the container
|
||||
// for that container to be the correct one
|
||||
if (codecs.every((c) => regexs.mp4.test(c))) {
|
||||
container = 'mp4';
|
||||
} else if (codecs.every((c) => regexs.webm.test(c))) {
|
||||
container = 'webm';
|
||||
} else if (codecs.every((c) => regexs.ogg.test(c))) {
|
||||
container = 'ogg';
|
||||
}
|
||||
|
||||
return `${type}/${container};codecs="${codecString}"`;
|
||||
};
|
||||
|
||||
export const browserSupportsCodec = (codecString = '') => window.MediaSource &&
|
||||
window.MediaSource.isTypeSupported &&
|
||||
window.MediaSource.isTypeSupported(getMimeForCodec(codecString)) || false;
|
||||
|
||||
export const muxerSupportsCodec = (codecString = '') => codecString.toLowerCase().split(',').every((codec) => {
|
||||
codec = codec.trim();
|
||||
|
||||
return regexs.muxerVideo.test(codec) || regexs.muxerAudio.test(codec);
|
||||
});
|
||||
|
||||
export const DEFAULT_AUDIO_CODEC = 'mp4a.40.2';
|
||||
export const DEFAULT_VIDEO_CODEC = 'avc1.4d400d';
|
||||
154
build/javascript/node_modules/@videojs/vhs-utils/src/containers.js
generated
vendored
Normal file
154
build/javascript/node_modules/@videojs/vhs-utils/src/containers.js
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
import {bytesToString, toUint8} from './byte-helpers.js';
|
||||
|
||||
export const id3Size = function(bytes, offset = 0) {
|
||||
bytes = toUint8(bytes);
|
||||
|
||||
const returnSize = (bytes[offset + 6] << 21) |
|
||||
(bytes[offset + 7] << 14) |
|
||||
(bytes[offset + 8] << 7) |
|
||||
(bytes[offset + 9]);
|
||||
const flags = bytes[offset + 5];
|
||||
const footerPresent = (flags & 16) >> 4;
|
||||
|
||||
if (footerPresent) {
|
||||
return returnSize + 20;
|
||||
}
|
||||
|
||||
return returnSize + 10;
|
||||
};
|
||||
|
||||
export const getId3Offset = function(bytes, offset = 0) {
|
||||
bytes = toUint8(bytes);
|
||||
|
||||
if ((bytes.length - offset) < 10 || bytesToString(bytes.subarray(offset, offset + 3)) !== 'ID3') {
|
||||
return offset;
|
||||
}
|
||||
|
||||
offset += id3Size(bytes, offset);
|
||||
|
||||
// recursive check for id3 tags as some files
|
||||
// have multiple ID3 tag sections even though
|
||||
// they should not.
|
||||
return getId3Offset(bytes, offset);
|
||||
};
|
||||
|
||||
export const isLikely = {
|
||||
aac(bytes) {
|
||||
const offset = getId3Offset(bytes);
|
||||
|
||||
return bytes.length >= offset + 2 &&
|
||||
(bytes[offset] & 0xFF) === 0xFF &&
|
||||
(bytes[offset + 1] & 0xE0) === 0xE0 &&
|
||||
(bytes[offset + 1] & 0x16) === 0x10;
|
||||
},
|
||||
|
||||
mp3(bytes) {
|
||||
const offset = getId3Offset(bytes);
|
||||
|
||||
return bytes.length >= offset + 2 &&
|
||||
(bytes[offset] & 0xFF) === 0xFF &&
|
||||
(bytes[offset + 1] & 0xE0) === 0xE0 &&
|
||||
(bytes[offset + 1] & 0x06) === 0x02;
|
||||
},
|
||||
|
||||
webm(bytes) {
|
||||
return bytes.length >= 4 &&
|
||||
(bytes[0] & 0xFF) === 0x1A &&
|
||||
(bytes[1] & 0xFF) === 0x45 &&
|
||||
(bytes[2] & 0xFF) === 0xDF &&
|
||||
(bytes[3] & 0xFF) === 0xA3;
|
||||
},
|
||||
|
||||
mp4(bytes) {
|
||||
return bytes.length >= 8 &&
|
||||
(/^(f|s)typ$/).test(bytesToString(bytes.subarray(4, 8))) &&
|
||||
// not 3gp data
|
||||
!(/^ftyp3g$/).test(bytesToString(bytes.subarray(4, 10)));
|
||||
},
|
||||
|
||||
'3gp'(bytes) {
|
||||
return bytes.length >= 10 &&
|
||||
(/^ftyp3g$/).test(bytesToString(bytes.subarray(4, 10)));
|
||||
},
|
||||
|
||||
ts(bytes) {
|
||||
if (bytes.length < 189 && bytes.length >= 1) {
|
||||
return bytes[0] === 0x47;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
|
||||
// check the first 376 bytes for two matching sync bytes
|
||||
while (i + 188 < bytes.length && i < 188) {
|
||||
if (bytes[i] === 0x47 && bytes[i + 188] === 0x47) {
|
||||
return true;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
flac(bytes) {
|
||||
return bytes.length >= 4 &&
|
||||
(/^fLaC$/).test(bytesToString(bytes.subarray(0, 4)));
|
||||
},
|
||||
ogg(bytes) {
|
||||
return bytes.length >= 4 &&
|
||||
(/^OggS$/).test(bytesToString(bytes.subarray(0, 4)));
|
||||
}
|
||||
};
|
||||
|
||||
// get all the isLikely functions
|
||||
// but make sure 'ts' is at the bottom
|
||||
// as it is the least specific
|
||||
const isLikelyTypes = Object.keys(isLikely)
|
||||
// remove ts
|
||||
.filter((t) => t !== 'ts')
|
||||
// add it back to the bottom
|
||||
.concat('ts');
|
||||
|
||||
// make sure we are dealing with uint8 data.
|
||||
isLikelyTypes.forEach(function(type) {
|
||||
const isLikelyFn = isLikely[type];
|
||||
|
||||
isLikely[type] = (bytes) => isLikelyFn(toUint8(bytes));
|
||||
});
|
||||
|
||||
// A useful list of file signatures can be found here
|
||||
// https://en.wikipedia.org/wiki/List_of_file_signatures
|
||||
export const detectContainerForBytes = (bytes) => {
|
||||
bytes = toUint8(bytes);
|
||||
|
||||
for (let i = 0; i < isLikelyTypes.length; i++) {
|
||||
const type = isLikelyTypes[i];
|
||||
|
||||
if (isLikely[type](bytes)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
// fmp4 is not a container
|
||||
export const isLikelyFmp4MediaSegment = (bytes) => {
|
||||
bytes = toUint8(bytes);
|
||||
let i = 0;
|
||||
|
||||
while (i < bytes.length) {
|
||||
const size = (bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]) >>> 0;
|
||||
const type = bytesToString(bytes.subarray(i + 4, i + 8));
|
||||
|
||||
if (type === 'moof') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (size === 0 || (size + i) > bytes.length) {
|
||||
i = bytes.length;
|
||||
} else {
|
||||
i += size;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
13
build/javascript/node_modules/@videojs/vhs-utils/src/decode-b64-to-uint8-array.js
generated
vendored
Normal file
13
build/javascript/node_modules/@videojs/vhs-utils/src/decode-b64-to-uint8-array.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import window from 'global/window';
|
||||
|
||||
const atob = (s) => window.atob ? window.atob(s) : Buffer.from(s, 'base64').toString('binary');
|
||||
|
||||
export default function decodeB64ToUint8Array(b64Text) {
|
||||
const decodedString = atob(b64Text);
|
||||
const array = new Uint8Array(decodedString.length);
|
||||
|
||||
for (let i = 0; i < decodedString.length; i++) {
|
||||
array[i] = decodedString.charCodeAt(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
22
build/javascript/node_modules/@videojs/vhs-utils/src/media-groups.js
generated
vendored
Normal file
22
build/javascript/node_modules/@videojs/vhs-utils/src/media-groups.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Loops through all supported media groups in master and calls the provided
|
||||
* callback for each group
|
||||
*
|
||||
* @param {Object} master
|
||||
* The parsed master manifest object
|
||||
* @param {string[]} groups
|
||||
* The media groups to call the callback for
|
||||
* @param {Function} callback
|
||||
* Callback to call for each media group
|
||||
*/
|
||||
export const forEachMediaGroup = (master, groups, callback) => {
|
||||
groups.forEach((mediaType) => {
|
||||
for (const groupKey in master.mediaGroups[mediaType]) {
|
||||
for (const labelKey in master.mediaGroups[mediaType][groupKey]) {
|
||||
const mediaProperties = master.mediaGroups[mediaType][groupKey][labelKey];
|
||||
|
||||
callback(mediaProperties, mediaType, groupKey, labelKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
36
build/javascript/node_modules/@videojs/vhs-utils/src/media-types.js
generated
vendored
Normal file
36
build/javascript/node_modules/@videojs/vhs-utils/src/media-types.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
const MPEGURL_REGEX = /^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i;
|
||||
const DASH_REGEX = /^application\/dash\+xml/i;
|
||||
|
||||
/**
|
||||
* Returns a string that describes the type of source based on a video source object's
|
||||
* media type.
|
||||
*
|
||||
* @see {@link https://dev.w3.org/html5/pf-summary/video.html#dom-source-type|Source Type}
|
||||
*
|
||||
* @param {string} type
|
||||
* Video source object media type
|
||||
* @return {('hls'|'dash'|'vhs-json'|null)}
|
||||
* VHS source type string
|
||||
*/
|
||||
export const simpleTypeFromSourceType = (type) => {
|
||||
if (MPEGURL_REGEX.test(type)) {
|
||||
return 'hls';
|
||||
}
|
||||
|
||||
if (DASH_REGEX.test(type)) {
|
||||
return 'dash';
|
||||
}
|
||||
|
||||
// Denotes the special case of a manifest object passed to http-streaming instead of a
|
||||
// source URL.
|
||||
//
|
||||
// See https://en.wikipedia.org/wiki/Media_type for details on specifying media types.
|
||||
//
|
||||
// In this case, vnd stands for vendor, video.js for the organization, VHS for this
|
||||
// project, and the +json suffix identifies the structure of the media type.
|
||||
if (type === 'application/vnd.videojs.vhs+json') {
|
||||
return 'vhs-json';
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
18
build/javascript/node_modules/@videojs/vhs-utils/src/resolve-url.js
generated
vendored
Normal file
18
build/javascript/node_modules/@videojs/vhs-utils/src/resolve-url.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import URLToolkit from 'url-toolkit';
|
||||
import window from 'global/window';
|
||||
|
||||
const resolveUrl = (baseUrl, relativeUrl) => {
|
||||
// return early if we don't need to resolve
|
||||
if ((/^[a-z]+:/i).test(relativeUrl)) {
|
||||
return relativeUrl;
|
||||
}
|
||||
|
||||
// if the base URL is relative then combine with the current location
|
||||
if (!(/\/\//i).test(baseUrl)) {
|
||||
baseUrl = URLToolkit.buildAbsoluteURL(window.location && window.location.href || '', baseUrl);
|
||||
}
|
||||
|
||||
return URLToolkit.buildAbsoluteURL(baseUrl, relativeUrl);
|
||||
};
|
||||
|
||||
export default resolveUrl;
|
||||
108
build/javascript/node_modules/@videojs/vhs-utils/src/stream.js
generated
vendored
Normal file
108
build/javascript/node_modules/@videojs/vhs-utils/src/stream.js
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @file stream.js
|
||||
*/
|
||||
/**
|
||||
* A lightweight readable stream implemention that handles event dispatching.
|
||||
*
|
||||
* @class Stream
|
||||
*/
|
||||
export default class Stream {
|
||||
constructor() {
|
||||
this.listeners = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for a specified event type.
|
||||
*
|
||||
* @param {string} type the event name
|
||||
* @param {Function} listener the callback to be invoked when an event of
|
||||
* the specified type occurs
|
||||
*/
|
||||
on(type, listener) {
|
||||
if (!this.listeners[type]) {
|
||||
this.listeners[type] = [];
|
||||
}
|
||||
this.listeners[type].push(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener for a specified event type.
|
||||
*
|
||||
* @param {string} type the event name
|
||||
* @param {Function} listener a function previously registered for this
|
||||
* type of event through `on`
|
||||
* @return {boolean} if we could turn it off or not
|
||||
*/
|
||||
off(type, listener) {
|
||||
if (!this.listeners[type]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const index = this.listeners[type].indexOf(listener);
|
||||
|
||||
// TODO: which is better?
|
||||
// In Video.js we slice listener functions
|
||||
// on trigger so that it does not mess up the order
|
||||
// while we loop through.
|
||||
//
|
||||
// Here we slice on off so that the loop in trigger
|
||||
// can continue using it's old reference to loop without
|
||||
// messing up the order.
|
||||
this.listeners[type] = this.listeners[type].slice(0);
|
||||
this.listeners[type].splice(index, 1);
|
||||
return index > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an event of the specified type on this stream. Any additional
|
||||
* arguments to this function are passed as parameters to event listeners.
|
||||
*
|
||||
* @param {string} type the event name
|
||||
*/
|
||||
trigger(type) {
|
||||
const callbacks = this.listeners[type];
|
||||
|
||||
if (!callbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Slicing the arguments on every invocation of this method
|
||||
// can add a significant amount of overhead. Avoid the
|
||||
// intermediate object creation for the common case of a
|
||||
// single callback argument
|
||||
if (arguments.length === 2) {
|
||||
const length = callbacks.length;
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
callbacks[i].call(this, arguments[1]);
|
||||
}
|
||||
} else {
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const length = callbacks.length;
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
callbacks[i].apply(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the stream and cleans up.
|
||||
*/
|
||||
dispose() {
|
||||
this.listeners = {};
|
||||
}
|
||||
/**
|
||||
* Forwards all `data` events on this stream to the destination stream. The
|
||||
* destination stream should provide a method `push` to receive the data
|
||||
* events as they arrive.
|
||||
*
|
||||
* @param {Stream} destination the stream that will receive all `data` events
|
||||
* @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
|
||||
*/
|
||||
pipe(destination) {
|
||||
this.on('data', function(data) {
|
||||
destination.push(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
138
build/javascript/node_modules/@videojs/vhs-utils/test/byte-helpers.test.js
generated
vendored
Normal file
138
build/javascript/node_modules/@videojs/vhs-utils/test/byte-helpers.test.js
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
import QUnit from 'qunit';
|
||||
import {
|
||||
bytesToString,
|
||||
stringToBytes,
|
||||
toUint8,
|
||||
concatTypedArrays
|
||||
} from '../src/byte-helpers.js';
|
||||
import window from 'global/window';
|
||||
|
||||
const arrayNames = [];
|
||||
|
||||
[
|
||||
'Array',
|
||||
'Int8Array',
|
||||
'Uint8Array',
|
||||
'Uint8ClampedArray',
|
||||
'Int16Array',
|
||||
'Uint16Array',
|
||||
'Int32Array',
|
||||
'Uint32Array',
|
||||
'Float32Array',
|
||||
'Float64Array'
|
||||
].forEach(function(name) {
|
||||
if (window[name]) {
|
||||
arrayNames.push(name);
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.module('bytesToString');
|
||||
|
||||
const testString = 'hello竜';
|
||||
const testBytes = [
|
||||
// h
|
||||
0x68,
|
||||
// e
|
||||
0x65,
|
||||
// l
|
||||
0x6c,
|
||||
// l
|
||||
0x6c,
|
||||
// o
|
||||
0x6f,
|
||||
// 竜
|
||||
0xe7, 0xab, 0x9c
|
||||
];
|
||||
|
||||
const rawBytes = [0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x01];
|
||||
|
||||
QUnit.test('should function as expected', function(assert) {
|
||||
arrayNames.forEach(function(name) {
|
||||
const testObj = name === 'Array' ? testBytes : new window[name](testBytes);
|
||||
|
||||
assert.equal(bytesToString(testObj), testString, `testString work as a string arg with ${name}`);
|
||||
assert.equal(bytesToString(new window[name]()), '', `empty ${name} returns empty string`);
|
||||
});
|
||||
|
||||
assert.equal(bytesToString(), '', 'undefined returns empty string');
|
||||
assert.equal(bytesToString(null), '', 'null returns empty string');
|
||||
assert.equal(bytesToString(stringToBytes(testString)), testString, 'stringToBytes -> bytesToString works');
|
||||
});
|
||||
|
||||
QUnit.module('stringToBytes');
|
||||
|
||||
QUnit.test('should function as expected', function(assert) {
|
||||
assert.deepEqual(stringToBytes(testString), testBytes, 'returns an array of bytes');
|
||||
assert.deepEqual(stringToBytes(), [], 'empty array for undefined');
|
||||
assert.deepEqual(stringToBytes(null), [], 'empty array for null');
|
||||
assert.deepEqual(stringToBytes(''), [], 'empty array for empty string');
|
||||
assert.deepEqual(stringToBytes(10), [0x31, 0x30], 'converts numbers to strings');
|
||||
assert.deepEqual(stringToBytes(bytesToString(testBytes)), testBytes, 'bytesToString -> stringToBytes works');
|
||||
assert.deepEqual(stringToBytes(bytesToString(rawBytes), true), rawBytes, 'equal to original with raw bytes mode');
|
||||
assert.notDeepEqual(stringToBytes(bytesToString(rawBytes)), rawBytes, 'without raw byte mode works, not equal');
|
||||
});
|
||||
|
||||
QUnit.module('toUint8');
|
||||
|
||||
QUnit.test('should function as expected', function(assert) {
|
||||
const undef = toUint8();
|
||||
|
||||
assert.ok(undef instanceof Uint8Array && undef.length === 0, 'undef is a blank Uint8Array');
|
||||
|
||||
const nul = toUint8(null);
|
||||
|
||||
assert.ok(nul instanceof Uint8Array && nul.length === 0, 'undef is a blank Uint8Array');
|
||||
|
||||
arrayNames.forEach(function(name) {
|
||||
const testObj = name === 'Array' ? testBytes : new window[name](testBytes);
|
||||
const uint = toUint8(testObj);
|
||||
|
||||
assert.ok(uint instanceof Uint8Array && uint.length > 0, `converted ${name} to Uint8Array`);
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.module('concatTypedArrays');
|
||||
|
||||
QUnit.test('should function as expected', function(assert) {
|
||||
const tests = {
|
||||
undef: {
|
||||
data: concatTypedArrays(),
|
||||
expected: toUint8([])
|
||||
},
|
||||
empty: {
|
||||
data: concatTypedArrays(toUint8([])),
|
||||
expected: toUint8([])
|
||||
},
|
||||
single: {
|
||||
data: concatTypedArrays([0x01]),
|
||||
expected: toUint8([0x01])
|
||||
},
|
||||
array: {
|
||||
data: concatTypedArrays([0x01], [0x02]),
|
||||
expected: toUint8([0x01, 0x02])
|
||||
},
|
||||
uint: {
|
||||
data: concatTypedArrays(toUint8([0x01]), toUint8([0x02])),
|
||||
expected: toUint8([0x01, 0x02])
|
||||
},
|
||||
buffer: {
|
||||
data: concatTypedArrays(toUint8([0x01]).buffer, toUint8([0x02]).buffer),
|
||||
expected: toUint8([0x01, 0x02])
|
||||
},
|
||||
manyarray: {
|
||||
data: concatTypedArrays([0x01], [0x02], [0x03], [0x04]),
|
||||
expected: toUint8([0x01, 0x02, 0x03, 0x04])
|
||||
},
|
||||
manyuint: {
|
||||
data: concatTypedArrays(toUint8([0x01]), toUint8([0x02]), toUint8([0x03]), toUint8([0x04])),
|
||||
expected: toUint8([0x01, 0x02, 0x03, 0x04])
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(tests).forEach(function(name) {
|
||||
const {data, expected} = tests[name];
|
||||
|
||||
assert.ok(data instanceof Uint8Array, `obj is a Uint8Array for ${name}`);
|
||||
assert.deepEqual(data, expected, `data is as expected for ${name}`);
|
||||
});
|
||||
});
|
||||
398
build/javascript/node_modules/@videojs/vhs-utils/test/codecs.test.js
generated
vendored
Normal file
398
build/javascript/node_modules/@videojs/vhs-utils/test/codecs.test.js
generated
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
import window from 'global/window';
|
||||
import QUnit from 'qunit';
|
||||
import {
|
||||
mapLegacyAvcCodecs,
|
||||
translateLegacyCodecs,
|
||||
parseCodecs,
|
||||
codecsFromDefault,
|
||||
isVideoCodec,
|
||||
isAudioCodec,
|
||||
muxerSupportsCodec,
|
||||
browserSupportsCodec,
|
||||
getMimeForCodec
|
||||
} from '../src/codecs';
|
||||
|
||||
const supportedMuxerCodecs = [
|
||||
'mp4a',
|
||||
'avc1'
|
||||
];
|
||||
|
||||
const unsupportedMuxerCodecs = [
|
||||
'hvc1',
|
||||
'ac-3',
|
||||
'ec-3',
|
||||
'mp3'
|
||||
];
|
||||
|
||||
QUnit.module('Legacy Codecs');
|
||||
|
||||
QUnit.test('maps legacy AVC codecs', function(assert) {
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('avc1.deadbeef'),
|
||||
'avc1.deadbeef',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('avc1.dead.beef, mp4a.something'),
|
||||
'avc1.dead.beef, mp4a.something',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('avc1.dead.beef,mp4a.something'),
|
||||
'avc1.dead.beef,mp4a.something',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('mp4a.something,avc1.dead.beef'),
|
||||
'mp4a.something,avc1.dead.beef',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('mp4a.something, avc1.dead.beef'),
|
||||
'mp4a.something, avc1.dead.beef',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('avc1.42001e'),
|
||||
'avc1.42001e',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('avc1.4d0020,mp4a.40.2'),
|
||||
'avc1.4d0020,mp4a.40.2',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('mp4a.40.2,avc1.4d0020'),
|
||||
'mp4a.40.2,avc1.4d0020',
|
||||
'does nothing for non legacy pattern'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('mp4a.40.40'),
|
||||
'mp4a.40.40',
|
||||
'does nothing for non video codecs'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('avc1.66.30'),
|
||||
'avc1.42001e',
|
||||
'translates legacy video codec alone'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('avc1.66.30, mp4a.40.2'),
|
||||
'avc1.42001e, mp4a.40.2',
|
||||
'translates legacy video codec when paired with audio'
|
||||
);
|
||||
assert.equal(
|
||||
mapLegacyAvcCodecs('mp4a.40.2, avc1.66.30'),
|
||||
'mp4a.40.2, avc1.42001e',
|
||||
'translates video codec when specified second'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('translates legacy codecs', function(assert) {
|
||||
assert.deepEqual(
|
||||
translateLegacyCodecs(['avc1.66.30', 'avc1.66.30']),
|
||||
['avc1.42001e', 'avc1.42001e'],
|
||||
'translates legacy avc1.66.30 codec'
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
translateLegacyCodecs(['avc1.42C01E', 'avc1.42C01E']),
|
||||
['avc1.42C01E', 'avc1.42C01E'],
|
||||
'does not translate modern codecs'
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
translateLegacyCodecs(['avc1.42C01E', 'avc1.66.30']),
|
||||
['avc1.42C01E', 'avc1.42001e'],
|
||||
'only translates legacy codecs when mixed'
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
translateLegacyCodecs(['avc1.4d0020', 'avc1.100.41', 'avc1.77.41',
|
||||
'avc1.77.32', 'avc1.77.31', 'avc1.77.30',
|
||||
'avc1.66.30', 'avc1.66.21', 'avc1.42C01e']),
|
||||
['avc1.4d0020', 'avc1.640029', 'avc1.4d0029',
|
||||
'avc1.4d0020', 'avc1.4d001f', 'avc1.4d001e',
|
||||
'avc1.42001e', 'avc1.420015', 'avc1.42C01e'],
|
||||
'translates a whole bunch'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.module('parseCodecs');
|
||||
|
||||
QUnit.test('parses video only codec string', function(assert) {
|
||||
assert.deepEqual(
|
||||
parseCodecs('avc1.42001e'),
|
||||
{video: {type: 'avc1', details: '.42001e'}},
|
||||
'parsed video only codec string'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('parses audio only codec string', function(assert) {
|
||||
assert.deepEqual(
|
||||
parseCodecs('mp4a.40.2'),
|
||||
{audio: {type: 'mp4a', details: '.40.2'}},
|
||||
'parsed audio only codec string'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('parses video and audio codec string', function(assert) {
|
||||
assert.deepEqual(
|
||||
parseCodecs('avc1.42001e, mp4a.40.2'),
|
||||
{
|
||||
video: {type: 'avc1', details: '.42001e'},
|
||||
audio: {type: 'mp4a', details: '.40.2'}
|
||||
},
|
||||
'parsed video and audio codec string'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('parses video and audio codec with mixed case', function(assert) {
|
||||
assert.deepEqual(
|
||||
parseCodecs('AvC1.42001E, Mp4A.40.E'),
|
||||
{
|
||||
video: {type: 'AvC1', details: '.42001E'},
|
||||
audio: {type: 'Mp4A', details: '.40.E'}
|
||||
},
|
||||
'parsed video and audio codec string'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.module('codecsFromDefault');
|
||||
|
||||
QUnit.test('returns falsey when no audio group ID', function(assert) {
|
||||
assert.notOk(
|
||||
codecsFromDefault(
|
||||
{ mediaGroups: { AUDIO: {} } },
|
||||
'',
|
||||
),
|
||||
'returns falsey when no audio group ID'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('returns falsey when no matching audio group', function(assert) {
|
||||
assert.notOk(
|
||||
codecsFromDefault(
|
||||
{
|
||||
mediaGroups: {
|
||||
AUDIO: {
|
||||
au1: {
|
||||
en: {
|
||||
default: false,
|
||||
playlists: [{
|
||||
attributes: { CODECS: 'mp4a.40.2' }
|
||||
}]
|
||||
},
|
||||
es: {
|
||||
default: true,
|
||||
playlists: [{
|
||||
attributes: { CODECS: 'mp4a.40.5' }
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'au2'
|
||||
),
|
||||
'returned falsey when no matching audio group'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('returns falsey when no default for audio group', function(assert) {
|
||||
assert.notOk(
|
||||
codecsFromDefault(
|
||||
{
|
||||
mediaGroups: {
|
||||
AUDIO: {
|
||||
au1: {
|
||||
en: {
|
||||
default: false,
|
||||
playlists: [{
|
||||
attributes: { CODECS: 'mp4a.40.2' }
|
||||
}]
|
||||
},
|
||||
es: {
|
||||
default: false,
|
||||
playlists: [{
|
||||
attributes: { CODECS: 'mp4a.40.5' }
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'au1'
|
||||
),
|
||||
'returned falsey when no default for audio group'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('returns audio profile for default in audio group', function(assert) {
|
||||
assert.deepEqual(
|
||||
codecsFromDefault(
|
||||
{
|
||||
mediaGroups: {
|
||||
AUDIO: {
|
||||
au1: {
|
||||
en: {
|
||||
default: false,
|
||||
playlists: [{
|
||||
attributes: { CODECS: 'mp4a.40.2' }
|
||||
}]
|
||||
},
|
||||
es: {
|
||||
default: true,
|
||||
playlists: [{
|
||||
attributes: { CODECS: 'mp4a.40.5' }
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'au1'
|
||||
),
|
||||
{audio: {type: 'mp4a', details: '.40.5'}},
|
||||
'returned parsed codec audio profile'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.module('isVideoCodec');
|
||||
QUnit.test('works as expected', function(assert) {
|
||||
[
|
||||
'av1',
|
||||
'avc01',
|
||||
'avc1',
|
||||
'avc02',
|
||||
'avc2',
|
||||
'vp09',
|
||||
'vp9',
|
||||
'vp8',
|
||||
'vp08',
|
||||
'hvc1',
|
||||
'hev1',
|
||||
'theora',
|
||||
'mp4v'
|
||||
].forEach(function(codec) {
|
||||
assert.ok(isVideoCodec(codec), `"${codec}" is seen as a video codec`);
|
||||
assert.ok(isVideoCodec(` ${codec} `), `" ${codec} " is seen as video codec`);
|
||||
assert.ok(isVideoCodec(codec.toUpperCase()), `"${codec.toUpperCase()}" is seen as video codec`);
|
||||
});
|
||||
|
||||
['invalid', 'foo', 'mp4a', 'opus', 'vorbis'].forEach(function(codec) {
|
||||
assert.notOk(isVideoCodec(codec), `${codec} is not a video codec`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
QUnit.module('isAudioCodec');
|
||||
QUnit.test('works as expected', function(assert) {
|
||||
[
|
||||
'mp4a',
|
||||
'flac',
|
||||
'vorbis',
|
||||
'opus',
|
||||
'ac-3',
|
||||
'ac-4',
|
||||
'ec-3',
|
||||
'alac'
|
||||
].forEach(function(codec) {
|
||||
assert.ok(isAudioCodec(codec), `"${codec}" is seen as an audio codec`);
|
||||
assert.ok(isAudioCodec(` ${codec} `), `" ${codec} " is seen as an audio codec`);
|
||||
assert.ok(isAudioCodec(codec.toUpperCase()), `"${codec.toUpperCase()}" is seen as an audio codec`);
|
||||
});
|
||||
|
||||
['invalid', 'foo', 'bar', 'avc1', 'av1'].forEach(function(codec) {
|
||||
assert.notOk(isAudioCodec(codec), `${codec} is not an audio codec`);
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.module('muxerSupportsCodec');
|
||||
QUnit.test('works as expected', function(assert) {
|
||||
const validMuxerCodecs = [];
|
||||
const invalidMuxerCodecs = [];
|
||||
|
||||
unsupportedMuxerCodecs.forEach(function(badCodec) {
|
||||
invalidMuxerCodecs.push(badCodec);
|
||||
supportedMuxerCodecs.forEach(function(goodCodec) {
|
||||
invalidMuxerCodecs.push(`${goodCodec}, ${badCodec}`);
|
||||
});
|
||||
});
|
||||
|
||||
// generate all combinations of valid codecs
|
||||
supportedMuxerCodecs.forEach(function(codec, i) {
|
||||
validMuxerCodecs.push(codec);
|
||||
|
||||
supportedMuxerCodecs.forEach(function(_codec, z) {
|
||||
if (z === i) {
|
||||
return;
|
||||
}
|
||||
validMuxerCodecs.push(`${codec}, ${_codec}`);
|
||||
validMuxerCodecs.push(`${codec},${_codec}`);
|
||||
});
|
||||
});
|
||||
|
||||
validMuxerCodecs.forEach(function(codec) {
|
||||
assert.ok(muxerSupportsCodec(codec), `"${codec}" is supported`);
|
||||
assert.ok(muxerSupportsCodec(` ${codec} `), `" ${codec} " is supported`);
|
||||
assert.ok(muxerSupportsCodec(codec.toUpperCase()), `"${codec.toUpperCase()}" is supported`);
|
||||
});
|
||||
|
||||
invalidMuxerCodecs.forEach(function(codec) {
|
||||
assert.notOk(muxerSupportsCodec(codec), `${codec} not supported`);
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.module('browserSupportsCodec', {
|
||||
beforeEach() {
|
||||
this.oldMediaSource = window.MediaSource;
|
||||
},
|
||||
afterEach() {
|
||||
window.MediaSource = this.oldMediaSource;
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('works as expected', function(assert) {
|
||||
window.MediaSource = {isTypeSupported: () => true};
|
||||
assert.ok(browserSupportsCodec('test'), 'isTypeSupported true, browser does support codec');
|
||||
|
||||
window.MediaSource = {isTypeSupported: () => false};
|
||||
assert.notOk(browserSupportsCodec('test'), 'isTypeSupported false, browser does not support codec');
|
||||
|
||||
window.MediaSource = null;
|
||||
assert.notOk(browserSupportsCodec('test'), 'no MediaSource, browser does not support codec');
|
||||
|
||||
window.MediaSource = {isTypeSupported: null};
|
||||
assert.notOk(browserSupportsCodec('test'), 'no isTypeSupported, browser does not support codec');
|
||||
});
|
||||
|
||||
QUnit.module('getMimeForCodec');
|
||||
|
||||
QUnit.test('works as expected', function(assert) {
|
||||
// mp4
|
||||
assert.equal(getMimeForCodec('vp9,mp4a'), 'video/mp4;codecs="vp9,mp4a"', 'mp4 video/audio works');
|
||||
assert.equal(getMimeForCodec('vp9'), 'video/mp4;codecs="vp9"', 'mp4 video works');
|
||||
assert.equal(getMimeForCodec('mp4a'), 'audio/mp4;codecs="mp4a"', 'mp4 audio works');
|
||||
|
||||
// webm
|
||||
assert.equal(getMimeForCodec('vp8,opus'), 'video/webm;codecs="vp8,opus"', 'webm video/audio works');
|
||||
assert.equal(getMimeForCodec('vp8'), 'video/webm;codecs="vp8"', 'webm video works');
|
||||
assert.equal(getMimeForCodec('vorbis'), 'audio/webm;codecs="vorbis"', 'webm audio works');
|
||||
|
||||
// ogg
|
||||
assert.equal(getMimeForCodec('theora,vorbis'), 'video/ogg;codecs="theora,vorbis"', 'ogg video/audio works');
|
||||
assert.equal(getMimeForCodec('theora'), 'video/ogg;codecs="theora"', 'ogg video works');
|
||||
// ogg will never be selected for audio only
|
||||
|
||||
// mixed
|
||||
assert.equal(getMimeForCodec('opus'), 'audio/mp4;codecs="opus"', 'mp4 takes priority over everything');
|
||||
assert.equal(getMimeForCodec('vorbis'), 'audio/webm;codecs="vorbis"', 'webm takes priority over ogg');
|
||||
assert.equal(getMimeForCodec('foo'), 'video/mp4;codecs="foo"', 'mp4 is the default');
|
||||
|
||||
assert.notOk(getMimeForCodec(), 'invalid codec returns undefined');
|
||||
|
||||
assert.equal(getMimeForCodec('Mp4A.40.2,AvC1.42001E'), 'video/mp4;codecs="Mp4A.40.2,AvC1.42001E"', 'case is preserved');
|
||||
});
|
||||
146
build/javascript/node_modules/@videojs/vhs-utils/test/container.test.js
generated
vendored
Normal file
146
build/javascript/node_modules/@videojs/vhs-utils/test/container.test.js
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
import QUnit from 'qunit';
|
||||
import {detectContainerForBytes, isLikelyFmp4MediaSegment} from '../src/containers.js';
|
||||
import {stringToBytes} from '../src/byte-helpers.js';
|
||||
|
||||
const fillerArray = (size) => Array.apply(null, Array(size)).map(() => 0x00);
|
||||
const otherMp4Data = [0x00, 0x00, 0x00, 0x00].concat(stringToBytes('stypiso'));
|
||||
const id3Data = []
|
||||
// id3 header is 10 bytes without footer
|
||||
// 10th byte is length 0x23 or 35 in decimal
|
||||
// so a total length of 45
|
||||
.concat(stringToBytes('ID3').concat([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23]))
|
||||
// add in the id3 content
|
||||
.concat(Array.apply(null, Array(35)).map(() => 0x00));
|
||||
|
||||
const id3DataWithFooter = []
|
||||
// id3 header is 20 bytes with footer
|
||||
// "we have a footer" is the sixth byte
|
||||
// 10th byte is length of 0x23 or 35 in decimal
|
||||
// so a total length of 55
|
||||
.concat(stringToBytes('ID3').concat([0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x23]))
|
||||
// add in the id3 content
|
||||
.concat(Array.apply(null, Array(45)).map(() => 0x00));
|
||||
|
||||
const testData = {
|
||||
'webm': [0x1A, 0x45, 0xDf, 0xA3],
|
||||
'flac': stringToBytes('fLaC'),
|
||||
'ogg': stringToBytes('OggS'),
|
||||
'aac': [0xFF, 0xF1],
|
||||
'mp3': [0xFF, 0xFB],
|
||||
'3gp': [0x00, 0x00, 0x00, 0x00].concat(stringToBytes('ftyp3g')),
|
||||
'mp4': [0x00, 0x00, 0x00, 0x00].concat(stringToBytes('ftypiso')),
|
||||
'ts': [0x47]
|
||||
};
|
||||
|
||||
QUnit.module('detectContainerForBytes');
|
||||
|
||||
QUnit.test('should identify known types', function(assert) {
|
||||
Object.keys(testData).forEach(function(key) {
|
||||
const data = new Uint8Array(testData[key]);
|
||||
|
||||
assert.equal(detectContainerForBytes(testData[key]), key, `found ${key} with Array`);
|
||||
assert.equal(detectContainerForBytes(data.buffer), key, `found ${key} with ArrayBuffer`);
|
||||
assert.equal(detectContainerForBytes(data), key, `found ${key} with Uint8Array`);
|
||||
});
|
||||
|
||||
const mp4Bytes = new Uint8Array([0x00, 0x00, 0x00, 0x00].concat(stringToBytes('styp')));
|
||||
|
||||
assert.equal(detectContainerForBytes(mp4Bytes), 'mp4', 'styp mp4 detected as mp4');
|
||||
|
||||
// mp3 and aac audio can have id3 data before the
|
||||
// signature for the file, so we need to handle that.
|
||||
['mp3', 'aac'].forEach(function(type) {
|
||||
const dataWithId3 = new Uint8Array([].concat(id3Data).concat(testData[type]));
|
||||
const dataWithId3Footer = new Uint8Array([].concat(id3DataWithFooter).concat(testData[type]));
|
||||
|
||||
const recursiveDataWithId3 = new Uint8Array([]
|
||||
.concat(id3Data)
|
||||
.concat(id3Data)
|
||||
.concat(id3Data)
|
||||
.concat(testData[type]));
|
||||
const recursiveDataWithId3Footer = new Uint8Array([]
|
||||
.concat(id3DataWithFooter)
|
||||
.concat(id3DataWithFooter)
|
||||
.concat(id3DataWithFooter)
|
||||
.concat(testData[type]));
|
||||
|
||||
const differentId3Sections = new Uint8Array([]
|
||||
.concat(id3DataWithFooter)
|
||||
.concat(id3Data)
|
||||
.concat(id3DataWithFooter)
|
||||
.concat(id3Data)
|
||||
.concat(testData[type]));
|
||||
|
||||
assert.equal(detectContainerForBytes(dataWithId3), type, `id3 skipped and ${type} detected`);
|
||||
assert.equal(detectContainerForBytes(dataWithId3Footer), type, `id3 + footer skipped and ${type} detected`);
|
||||
assert.equal(detectContainerForBytes(recursiveDataWithId3), type, `id3 x3 skipped and ${type} detected`);
|
||||
assert.equal(detectContainerForBytes(recursiveDataWithId3Footer), type, `id3 + footer x3 skipped and ${type} detected`);
|
||||
assert.equal(detectContainerForBytes(differentId3Sections), type, `id3 with/without footer skipped and ${type} detected`);
|
||||
});
|
||||
|
||||
const notTs = []
|
||||
.concat(testData.ts)
|
||||
.concat(fillerArray(188));
|
||||
const longTs = []
|
||||
.concat(testData.ts)
|
||||
.concat(fillerArray(187))
|
||||
.concat(testData.ts);
|
||||
|
||||
const unsyncTs = []
|
||||
.concat(fillerArray(187))
|
||||
.concat(testData.ts)
|
||||
.concat(fillerArray(187))
|
||||
.concat(testData.ts);
|
||||
|
||||
const badTs = []
|
||||
.concat(fillerArray(188))
|
||||
.concat(testData.ts)
|
||||
.concat(fillerArray(187))
|
||||
.concat(testData.ts);
|
||||
|
||||
assert.equal(detectContainerForBytes(longTs), 'ts', 'long ts data is detected');
|
||||
assert.equal(detectContainerForBytes(unsyncTs), 'ts', 'unsynced ts is detected');
|
||||
assert.equal(detectContainerForBytes(badTs), '', 'ts without a sync byte in 188 bytes is not detected');
|
||||
assert.equal(detectContainerForBytes(notTs), '', 'ts missing 0x47 at 188 is not ts at all');
|
||||
assert.equal(detectContainerForBytes(otherMp4Data), 'mp4', 'fmp4 detected as mp4');
|
||||
assert.equal(detectContainerForBytes(new Uint8Array()), '', 'no type');
|
||||
assert.equal(detectContainerForBytes(), '', 'no type');
|
||||
});
|
||||
|
||||
const createBox = function(type) {
|
||||
const size = 0x20;
|
||||
|
||||
// size bytes
|
||||
return [0x00, 0x00, 0x00, size]
|
||||
// box identfier styp
|
||||
.concat(stringToBytes(type))
|
||||
// filler data for size minus identfier and size bytes
|
||||
.concat(fillerArray(size - 8));
|
||||
};
|
||||
|
||||
QUnit.module('isLikelyFmp4MediaSegment');
|
||||
QUnit.test('works as expected', function(assert) {
|
||||
const fmp4Data = []
|
||||
.concat(createBox('styp'))
|
||||
.concat(createBox('sidx'))
|
||||
.concat(createBox('moof'));
|
||||
|
||||
const mp4Data = []
|
||||
.concat(createBox('ftyp'))
|
||||
.concat(createBox('sidx'))
|
||||
.concat(createBox('moov'));
|
||||
|
||||
const fmp4Fake = []
|
||||
.concat(createBox('test'))
|
||||
.concat(createBox('moof'))
|
||||
.concat(createBox('fooo'))
|
||||
.concat(createBox('bar'));
|
||||
|
||||
assert.ok(isLikelyFmp4MediaSegment(fmp4Data), 'fmp4 is recognized as fmp4');
|
||||
assert.ok(isLikelyFmp4MediaSegment(fmp4Fake), 'fmp4 with moof and unknown boxes is still fmp4');
|
||||
assert.ok(isLikelyFmp4MediaSegment(createBox('moof')), 'moof alone is recognized as fmp4');
|
||||
assert.notOk(isLikelyFmp4MediaSegment(mp4Data), 'mp4 is not recognized');
|
||||
assert.notOk(isLikelyFmp4MediaSegment([].concat(id3DataWithFooter).concat(testData.mp3)), 'bad data is not recognized');
|
||||
assert.notOk(isLikelyFmp4MediaSegment(new Uint8Array()), 'no errors on empty data');
|
||||
assert.notOk(isLikelyFmp4MediaSegment(), 'no errors on empty data');
|
||||
});
|
||||
13
build/javascript/node_modules/@videojs/vhs-utils/test/decode-b64-to-uint8-array.test.js
generated
vendored
Normal file
13
build/javascript/node_modules/@videojs/vhs-utils/test/decode-b64-to-uint8-array.test.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import QUnit from 'qunit';
|
||||
import decodeB64ToUint8Array from '../src/decode-b64-to-uint8-array.js';
|
||||
|
||||
QUnit.module('decodeB64ToUint8Array');
|
||||
|
||||
// slightly modified version of m3u8 test
|
||||
// 'parses Widevine #EXT-X-KEY attributes and attaches to manifest'
|
||||
QUnit.test('can decode', function(assert) {
|
||||
const b64 = 'AAAAPnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAB4iFnNoYWthX2NlYzJmNjRhYTc4OTBhMTFI49yVmwY';
|
||||
const result = decodeB64ToUint8Array(b64);
|
||||
|
||||
assert.deepEqual(result.byteLength, 62, 'decoded');
|
||||
});
|
||||
171
build/javascript/node_modules/@videojs/vhs-utils/test/media-groups.test.js
generated
vendored
Normal file
171
build/javascript/node_modules/@videojs/vhs-utils/test/media-groups.test.js
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
import QUnit from 'qunit';
|
||||
import { forEachMediaGroup } from '../src/media-groups';
|
||||
|
||||
QUnit.module('forEachMediaGroup');
|
||||
|
||||
QUnit.test('runs callback for each audio media group', function(assert) {
|
||||
const master = {
|
||||
mediaGroups: {
|
||||
AUDIO: {
|
||||
au1: {
|
||||
en: { en: 'en' },
|
||||
es: { es: 'es' }
|
||||
},
|
||||
au2: {
|
||||
de: { de: 'de' },
|
||||
fr: { fr: 'fr' }
|
||||
}
|
||||
},
|
||||
OTHER: {
|
||||
other1: {
|
||||
other11: { other11: 'other11' },
|
||||
other12: { other12: 'other12' }
|
||||
},
|
||||
other2: {
|
||||
other21: { other21: 'other21' },
|
||||
other22: { other22: 'other22' }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const iteratedMediaGroups = [];
|
||||
|
||||
forEachMediaGroup(
|
||||
master,
|
||||
['AUDIO'],
|
||||
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
iteratedMediaGroups,
|
||||
[
|
||||
{ en: 'en' },
|
||||
{ es: 'es' },
|
||||
{ de: 'de' },
|
||||
{ fr: 'fr' }
|
||||
],
|
||||
'iterated audio media groups'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('runs callback for each subtitle media group', function(assert) {
|
||||
const master = {
|
||||
mediaGroups: {
|
||||
SUBTITLES: {
|
||||
sub1: {
|
||||
en: { en: 'en' },
|
||||
es: { es: 'es' }
|
||||
},
|
||||
sub2: {
|
||||
de: { de: 'de' },
|
||||
fr: { fr: 'fr' }
|
||||
}
|
||||
},
|
||||
OTHER: {
|
||||
other1: {
|
||||
other11: { other11: 'other11' },
|
||||
other12: { other12: 'other12' }
|
||||
},
|
||||
other2: {
|
||||
other21: { other21: 'other21' },
|
||||
other22: { other22: 'other22' }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const iteratedMediaGroups = [];
|
||||
|
||||
forEachMediaGroup(
|
||||
master,
|
||||
['SUBTITLES'],
|
||||
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
iteratedMediaGroups,
|
||||
[
|
||||
{ en: 'en' },
|
||||
{ es: 'es' },
|
||||
{ de: 'de' },
|
||||
{ fr: 'fr' }
|
||||
],
|
||||
'iterated subtitles media groups'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('runs callback for each audio and subtitles media group', function(assert) {
|
||||
const master = {
|
||||
mediaGroups: {
|
||||
AUDIO: {
|
||||
au1: {
|
||||
en: { en: 'en' },
|
||||
es: { es: 'es' }
|
||||
},
|
||||
au2: {
|
||||
de: { de: 'de' },
|
||||
fr: { fr: 'fr' }
|
||||
}
|
||||
},
|
||||
SUBTITLES: {
|
||||
sub1: {
|
||||
enS: { enS: 'enS' },
|
||||
esS: { esS: 'esS' }
|
||||
},
|
||||
sub2: {
|
||||
deS: { deS: 'deS' },
|
||||
frS: { frS: 'frS' }
|
||||
}
|
||||
},
|
||||
OTHER: {
|
||||
other1: {
|
||||
other11: { other11: 'other11' },
|
||||
other12: { other12: 'other12' }
|
||||
},
|
||||
other2: {
|
||||
other21: { other21: 'other21' },
|
||||
other22: { other22: 'other22' }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const iteratedMediaGroups = [];
|
||||
|
||||
forEachMediaGroup(
|
||||
master,
|
||||
['AUDIO', 'SUBTITLES'],
|
||||
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
iteratedMediaGroups,
|
||||
[
|
||||
{ en: 'en' },
|
||||
{ es: 'es' },
|
||||
{ de: 'de' },
|
||||
{ fr: 'fr' },
|
||||
{ enS: 'enS' },
|
||||
{ esS: 'esS' },
|
||||
{ deS: 'deS' },
|
||||
{ frS: 'frS' }
|
||||
],
|
||||
'iterated audio and subtitles media groups'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('does not run callback for non specified media groups', function(assert) {
|
||||
const master = {
|
||||
mediaGroups: {
|
||||
'VIDEO': { v1: { en: { en: 'en' } } },
|
||||
'CLOSED-CAPTIONS': { cc1: { en: { en: 'en' } } }
|
||||
}
|
||||
};
|
||||
const iteratedMediaGroups = [];
|
||||
|
||||
forEachMediaGroup(
|
||||
master,
|
||||
['AUDIO', 'SUBTITLES'],
|
||||
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
|
||||
);
|
||||
|
||||
assert.deepEqual(iteratedMediaGroups, [], 'did not iterate non specified media groups');
|
||||
});
|
||||
41
build/javascript/node_modules/@videojs/vhs-utils/test/media-types.test.js
generated
vendored
Normal file
41
build/javascript/node_modules/@videojs/vhs-utils/test/media-types.test.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import QUnit from 'qunit';
|
||||
import { simpleTypeFromSourceType } from '../src/media-types';
|
||||
|
||||
QUnit.module('simpleTypeFromSourceType');
|
||||
|
||||
QUnit.test('simpleTypeFromSourceType converts HLS mime types to hls', function(assert) {
|
||||
assert.equal(
|
||||
simpleTypeFromSourceType('aPplicatiOn/x-MPegUrl'),
|
||||
'hls',
|
||||
'supports application/x-mpegurl'
|
||||
);
|
||||
assert.equal(
|
||||
simpleTypeFromSourceType('aPplicatiOn/VnD.aPPle.MpEgUrL'),
|
||||
'hls',
|
||||
'supports application/vnd.apple.mpegurl'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('simpleTypeFromSourceType converts DASH mime type to dash', function(assert) {
|
||||
assert.equal(
|
||||
simpleTypeFromSourceType('aPplication/dAsh+xMl'),
|
||||
'dash',
|
||||
'supports application/dash+xml'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
'simpleTypeFromSourceType does not convert non HLS/DASH mime types',
|
||||
function(assert) {
|
||||
assert.notOk(simpleTypeFromSourceType('video/mp4'), 'does not support video/mp4');
|
||||
assert.notOk(simpleTypeFromSourceType('video/x-flv'), 'does not support video/x-flv');
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test('simpleTypeFromSourceType converts VHS media type to vhs-json', function(assert) {
|
||||
assert.equal(
|
||||
simpleTypeFromSourceType('application/vnd.videojs.vhs+json'),
|
||||
'vhs-json',
|
||||
'supports application/vnd.videojs.vhs+json'
|
||||
);
|
||||
});
|
||||
28
build/javascript/node_modules/@videojs/vhs-utils/test/resolve-url.test.js
generated
vendored
Normal file
28
build/javascript/node_modules/@videojs/vhs-utils/test/resolve-url.test.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import QUnit from 'qunit';
|
||||
import window from 'global/window';
|
||||
import resolveUrl from '../src/resolve-url';
|
||||
|
||||
// A modified subset of tests from https://github.com/tjenkinson/url-toolkit
|
||||
|
||||
QUnit.module('URL resolver');
|
||||
|
||||
QUnit.test('works with a selection of valid urls', function(assert) {
|
||||
let currentLocation = '';
|
||||
|
||||
if (window.location && window.location.protocol) {
|
||||
currentLocation = window.location.protocol + '//' + window.location.host;
|
||||
}
|
||||
|
||||
assert.equal(
|
||||
resolveUrl('http://a.com/b/cd/e.m3u8', 'https://example.com/z.ts'),
|
||||
'https://example.com/z.ts'
|
||||
);
|
||||
assert.equal(resolveUrl('http://a.com/b/cd/e.m3u8', 'z.ts'), 'http://a.com/b/cd/z.ts');
|
||||
assert.equal(resolveUrl('//a.com/b/cd/e.m3u8', 'z.ts'), '//a.com/b/cd/z.ts');
|
||||
assert.equal(
|
||||
resolveUrl('/a/b/cd/e.m3u8', 'https://example.com:8080/z.ts'),
|
||||
'https://example.com:8080/z.ts'
|
||||
);
|
||||
assert.equal(resolveUrl('/a/b/cd/e.m3u8', 'z.ts'), currentLocation + '/a/b/cd/z.ts');
|
||||
assert.equal(resolveUrl('/a/b/cd/e.m3u8', '../../../z.ts'), currentLocation + '/z.ts');
|
||||
});
|
||||
51
build/javascript/node_modules/@videojs/vhs-utils/test/stream.test.js
generated
vendored
Normal file
51
build/javascript/node_modules/@videojs/vhs-utils/test/stream.test.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import QUnit from 'qunit';
|
||||
import Stream from '../src/stream';
|
||||
|
||||
QUnit.module('stream', {
|
||||
|
||||
beforeEach() {
|
||||
this.stream = new Stream();
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
this.stream.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('trigger calls listeners', function(assert) {
|
||||
const args = [];
|
||||
|
||||
this.stream.on('test', function(data) {
|
||||
args.push(data);
|
||||
});
|
||||
|
||||
this.stream.trigger('test', 1);
|
||||
this.stream.trigger('test', 2);
|
||||
|
||||
assert.deepEqual(args, [1, 2]);
|
||||
});
|
||||
|
||||
QUnit.test('callbacks can remove themselves', function(assert) {
|
||||
const args1 = [];
|
||||
const args2 = [];
|
||||
const args3 = [];
|
||||
const arg2Fn = (event) => {
|
||||
args2.push(event);
|
||||
this.stream.off('test', arg2Fn);
|
||||
};
|
||||
|
||||
this.stream.on('test', (event) => {
|
||||
args1.push(event);
|
||||
});
|
||||
this.stream.on('test', arg2Fn);
|
||||
this.stream.on('test', (event) => {
|
||||
args3.push(event);
|
||||
});
|
||||
|
||||
this.stream.trigger('test', 1);
|
||||
this.stream.trigger('test', 2);
|
||||
|
||||
assert.deepEqual(args1, [1, 2], 'first callback ran all times');
|
||||
assert.deepEqual(args2, [1], 'second callback removed after first run');
|
||||
assert.deepEqual(args3, [1, 2], 'third callback ran all times');
|
||||
});
|
||||
Reference in New Issue
Block a user