├── .nvmrc ├── .npmignore ├── .editorconfig ├── .gitignore ├── test ├── globals.test.js ├── integration.test.js ├── build.test.js └── dashjs.test.js ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE.md └── workflows │ └── ci.yml ├── scripts ├── rollup.config.js └── karma.conf.js ├── CONTRIBUTING.md ├── package.json ├── index.html ├── src └── js │ ├── setup-audio-tracks.js │ ├── setup-text-tracks.js │ ├── ttml-text-track-display.js │ └── videojs-dash.js ├── CHANGELOG.md ├── README.md └── LICENSE /.nvmrc: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Intentionally left blank, so that npm does not ignore anything by default, 2 | # but relies on the package.json "files" array to explicitly define what ends 3 | # up in the package. 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | Thumbs.db 3 | ehthumbs.db 4 | Desktop.ini 5 | .DS_Store 6 | ._* 7 | 8 | # Editors 9 | *~ 10 | *.swp 11 | *.tmproj 12 | *.tmproject 13 | *.sublime-* 14 | .idea/ 15 | .project/ 16 | .settings/ 17 | .vscode/ 18 | 19 | # Logs 20 | logs 21 | *.log 22 | npm-debug.log* 23 | 24 | # Dependency directories 25 | bower_components/ 26 | node_modules/ 27 | 28 | # Build-related directories 29 | dist/ 30 | docs/api/ 31 | test/dist/ 32 | .eslintcache 33 | .yo-rc.json 34 | -------------------------------------------------------------------------------- /test/globals.test.js: -------------------------------------------------------------------------------- 1 | import videojs from 'video.js'; 2 | import QUnit from 'qunit'; 3 | import window from 'global/window'; 4 | import '../src/js/videojs-dash.js'; 5 | 6 | QUnit.module('videojs-dash globals'); 7 | 8 | QUnit.test('has expected globals', function(assert) { 9 | assert.ok(videojs.Html5DashJS, 'videojs has "Html5Dash" property'); 10 | assert.ok(window.dashjs, 'global has "dashjs" property'); 11 | assert.ok(window.dashjs.MediaPlayer, 'global has "dashjs.MediaPlayer" property'); 12 | }); 13 | 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Please describe the change as necessary. 3 | If it's a feature or enhancement please be as detailed as possible. 4 | If it's a bug fix, please link the issue that it fixes or describe the bug in as much detail. 5 | 6 | ## Specific Changes proposed 7 | Please list the specific changes involved in this pull request. 8 | 9 | ## Requirements Checklist 10 | - [ ] Feature implemented / Bug fixed 11 | - [ ] If necessary, more likely in a feature request than a bug fix 12 | - [ ] Unit Tests updated or fixed 13 | - [ ] Docs/guides updated 14 | - [ ] Reviewed by Two Core Contributors 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Briefly describe the issue. 3 | Include a [reduced test case](https://css-tricks.com/reduced-test-cases/). 4 | 5 | ## Steps to reproduce 6 | Explain in detail the exact steps necessary to reproduce the issue. 7 | 8 | 1. 9 | 2. 10 | 3. 11 | 12 | ## Results 13 | ### Expected 14 | Please describe what you expected to see. 15 | 16 | ### Actual 17 | Please describe what actually happened. 18 | 19 | ### Error output 20 | If there are any errors at all, please include them here. 21 | 22 | ## Additional Information 23 | Please include any additional information necessary here. Including the following: 24 | 25 | ### versions 26 | #### videojs 27 | what version of videojs does this occur with? 28 | 29 | #### browsers 30 | what browser are affected? 31 | 32 | #### OSes 33 | what platforms (operating systems and devices) are affected? 34 | 35 | ### plugins 36 | are any videojs plugins being used on the page? If so, please list them below. 37 | -------------------------------------------------------------------------------- /scripts/rollup.config.js: -------------------------------------------------------------------------------- 1 | const generate = require('videojs-generate-rollup-config'); 2 | const nodeBuiltinsPlugin = require('@gkatsev/rollup-plugin-node-builtins'); 3 | const nodeGlobalsPlugin = require('rollup-plugin-node-globals'); 4 | 5 | // see https://github.com/videojs/videojs-generate-rollup-config 6 | // for options 7 | const options = { 8 | input: 'src/js/videojs-dash.js', 9 | distName: 'videojs-dash', 10 | exportName: 'videojsDash', 11 | // stream and string_decoder are used by some modules 12 | plugins(defaults) { 13 | return { 14 | browser: defaults.browser.concat([ 15 | nodeBuiltinsPlugin(), 16 | nodeGlobalsPlugin() 17 | ]), 18 | module: defaults.module.concat([ 19 | nodeBuiltinsPlugin(), 20 | nodeGlobalsPlugin() 21 | ]), 22 | test: defaults.test.concat([ 23 | nodeBuiltinsPlugin(), 24 | nodeGlobalsPlugin() 25 | ]) 26 | }; 27 | } 28 | }; 29 | const config = generate(options); 30 | 31 | // Add additonal builds/customization here! 32 | 33 | // export the builds to rollup 34 | export default Object.values(config.builds); 35 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | We welcome contributions from everyone! 4 | 5 | ## Getting Started 6 | 7 | Make sure you have Node.js 4.8 or higher and npm installed. 8 | 9 | 1. Fork this repository and clone your fork 10 | 1. Install dependencies: `npm install` 11 | 1. Run a development server: `npm start` 12 | 13 | ### Making Changes 14 | 15 | Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship. 16 | 17 | When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository. 18 | 19 | ### Running Tests 20 | 21 | 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]. 22 | 23 | - In all available and supported browsers: `npm test` 24 | - In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc. 25 | - While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local] 26 | 27 | 28 | [karma]: http://karma-runner.github.io/ 29 | [local]: http://localhost:9999/test/ 30 | [conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md 31 | -------------------------------------------------------------------------------- /scripts/karma.conf.js: -------------------------------------------------------------------------------- 1 | const generate = require('videojs-generate-karma-config'); 2 | const isCI = require('is-ci'); 3 | 4 | module.exports = function(config) { 5 | const options = { 6 | serverBrowsers(defaults) { 7 | // run our special chrome in server mode so we get instant test feedback 8 | return ['ChromeHeadlessWithFlags']; 9 | }, 10 | files(defaults) { 11 | // add in dashjs global 12 | defaults.unshift('node_modules/dashjs/dist/dash.all.debug.js'); 13 | 14 | return defaults; 15 | }, 16 | browsers(_browsers) { 17 | // only run on chrome 18 | const browsers = ['ChromeHeadlessWithFlags']; 19 | 20 | if (!isCI) { 21 | browsers.push('FirefoxHeadless'); 22 | } 23 | 24 | return browsers; 25 | }, 26 | customLaunchers(defaults) { 27 | // add no-user-gesture-require variant of chrome 28 | return Object.assign(defaults, { 29 | ChromeHeadlessWithFlags: { 30 | base: 'ChromeHeadless', 31 | flags: ['--no-sandbox', '--autoplay-policy=no-user-gesture-required'] 32 | } 33 | }); 34 | } 35 | }; 36 | 37 | config = generate(config, options); 38 | 39 | // ignore any console logs except for errors 40 | config.browserConsoleLogOptions = { 41 | level: 'error', 42 | terminal: false 43 | }; 44 | }; 45 | -------------------------------------------------------------------------------- /test/integration.test.js: -------------------------------------------------------------------------------- 1 | import videojs from 'video.js'; 2 | import QUnit from 'qunit'; 3 | import document from 'global/document'; 4 | 5 | const when = function(element, type, fn, condition) { 6 | const func = function() { 7 | if (condition()) { 8 | element.off(type, func); 9 | fn.apply(this, arguments); 10 | } 11 | }; 12 | 13 | element.on(type, func); 14 | }; 15 | 16 | QUnit.module('Integration', { 17 | beforeEach(assert) { 18 | const done = assert.async(); 19 | 20 | this.fixture = document.createElement('div'); 21 | document.body.appendChild(this.fixture); 22 | 23 | const videoEl = document.createElement('video'); 24 | 25 | videoEl.id = 'vid'; 26 | videoEl.setAttribute('controls', ''); 27 | videoEl.setAttribute('width', '600'); 28 | videoEl.setAttribute('height', '300'); 29 | videoEl.setAttribute('muted', 'true'); 30 | videoEl.className = 'video-js vjs-default-skin'; 31 | this.fixture.appendChild(videoEl); 32 | 33 | const player = videojs('vid'); 34 | 35 | this.player = player; 36 | 37 | player.ready(function() { 38 | player.one('loadstart', done); 39 | 40 | player.src({ 41 | src: 'http://dash.edgesuite.net/akamai/bbb_30fps/bbb_30fps.mpd', 42 | type: 'application/dash+xml' 43 | }); 44 | }); 45 | }, 46 | afterEach() { 47 | this.player.dispose(); 48 | } 49 | }); 50 | 51 | QUnit.test('should play', function(assert) { 52 | const done = assert.async(); 53 | 54 | const player = this.player; 55 | 56 | assert.expect(2); 57 | 58 | when(player, 'timeupdate', function() { 59 | assert.ok(true, 'played for at least two seconds'); 60 | assert.equal(player.error(), null, 'has no player errors'); 61 | 62 | done(); 63 | }, function() { 64 | return player.currentTime() >= 2; 65 | }); 66 | 67 | player.play(); 68 | }); 69 | -------------------------------------------------------------------------------- /test/build.test.js: -------------------------------------------------------------------------------- 1 | import QUnit from 'qunit'; 2 | import videojs from 'video.js'; 3 | import document from 'global/document'; 4 | 5 | const when = function(element, type, fn, condition) { 6 | const func = function() { 7 | if (condition()) { 8 | element.off(type, func); 9 | fn.apply(this, arguments); 10 | } 11 | }; 12 | 13 | element.on(type, func); 14 | }; 15 | 16 | QUnit.module('Webpack/Browserify Integration', { 17 | beforeEach(assert) { 18 | const done = assert.async(); 19 | 20 | this.fixture = document.createElement('div'); 21 | document.body.appendChild(this.fixture); 22 | 23 | const videoEl = document.createElement('video'); 24 | 25 | videoEl.id = 'vid'; 26 | videoEl.setAttribute('controls', ''); 27 | videoEl.setAttribute('width', '600'); 28 | videoEl.setAttribute('height', '300'); 29 | videoEl.setAttribute('muted', 'true'); 30 | videoEl.className = 'video-js vjs-default-skin'; 31 | this.fixture.appendChild(videoEl); 32 | 33 | const player = videojs('vid'); 34 | 35 | this.player = player; 36 | 37 | player.ready(function() { 38 | player.one('loadstart', done); 39 | 40 | player.src({ 41 | src: 'http://dash.edgesuite.net/akamai/bbb_30fps/bbb_30fps.mpd', 42 | type: 'application/dash+xml' 43 | }); 44 | }); 45 | }, 46 | afterEach() { 47 | this.player.dispose(); 48 | this.fixture.innerHTML = ''; 49 | } 50 | }); 51 | 52 | QUnit.test('should play', function(assert) { 53 | const 54 | done = assert.async(); 55 | 56 | const player = this.player; 57 | 58 | assert.expect(2); 59 | 60 | when(player, 'timeupdate', function() { 61 | assert.ok(true, 'played for at least two seconds'); 62 | assert.equal(player.error(), null, 'has no player errors'); 63 | 64 | done(); 65 | }, function() { 66 | return player.currentTime() >= 2; 67 | }); 68 | 69 | player.play(); 70 | }); 71 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | should-skip: 7 | continue-on-error: true 8 | runs-on: ubuntu-latest 9 | # Map a step output to a job output 10 | outputs: 11 | should-skip-job: ${{steps.skip-check.outputs.should_skip}} 12 | steps: 13 | - id: skip-check 14 | uses: fkirc/skip-duplicate-actions@v5.3.0 15 | with: 16 | github_token: ${{github.token}} 17 | 18 | ci: 19 | needs: should-skip 20 | if: ${{needs.should-skip.outputs.should-skip-job != 'true'}} 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | os: [ubuntu-latest] 25 | env: 26 | BROWSER_STACK_USERNAME: ${{secrets.BROWSER_STACK_USERNAME}} 27 | BROWSER_STACK_ACCESS_KEY: ${{secrets.BROWSER_STACK_ACCESS_KEY}} 28 | runs-on: ${{matrix.os}} 29 | steps: 30 | - name: checkout code 31 | uses: actions/checkout@v3 32 | 33 | - name: Cache dependencies 34 | uses: actions/cache@v3 35 | with: 36 | path: | 37 | ~/.npm 38 | **/node_modules 39 | key: ${{runner.os}}-npm-${{hashFiles('**/package-lock.json')}} 40 | restore-keys: | 41 | ${{runner.os}}-npm- 42 | ${{runner.os}}- 43 | 44 | - name: read node version from .nvmrc 45 | run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_OUTPUT 46 | shell: bash 47 | id: nvm 48 | 49 | - name: update apt cache on linux w/o browserstack 50 | run: sudo apt-get update 51 | if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}} 52 | 53 | - name: install ffmpeg/pulseaudio for firefox on linux w/o browserstack 54 | run: sudo apt-get install ffmpeg pulseaudio 55 | if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}} 56 | 57 | - name: start pulseaudio for firefox on linux w/o browserstack 58 | run: pulseaudio -D 59 | if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}} 60 | 61 | - name: setup node 62 | uses: actions/setup-node@v3 63 | with: 64 | node-version: '${{steps.nvm.outputs.NVMRC}}' 65 | 66 | # turn off the default setup-node problem watchers... 67 | - run: echo "::remove-matcher owner=eslint-compact::" 68 | - run: echo "::remove-matcher owner=eslint-stylish::" 69 | - run: echo "::remove-matcher owner=tsc::" 70 | 71 | - name: npm install 72 | run: npm i --prefer-offline --no-audit 73 | 74 | - name: run npm test 75 | uses: coactions/setup-xvfb@v1 76 | with: 77 | run: npm run test 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-contrib-dash", 3 | "description": "A Video.js source-handler providing MPEG-DASH playback.", 4 | "main": "dist/videojs-dash.cjs.js", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/videojs/videojs-contrib-dash.git" 8 | }, 9 | "version": "5.1.1", 10 | "author": "Brightcove, Inc", 11 | "license": "Apache-2.0", 12 | "scripts": { 13 | "prebuild": "npm run clean", 14 | "build": "npm-run-all -p build:*", 15 | "build:js": "rollup -c scripts/rollup.config.js", 16 | "clean": "shx rm -rf ./dist ./test/dist", 17 | "postclean": "shx mkdir -p ./dist ./test/dist", 18 | "docs": "npm-run-all docs:*", 19 | "docs:api": "jsdoc src -r -d docs/api", 20 | "docs:toc": "doctoc README.md", 21 | "lint": "vjsstandard", 22 | "server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch", 23 | "start": "npm-run-all -p server watch", 24 | "pretest": "npm-run-all lint build", 25 | "test": "karma start scripts/karma.conf.js", 26 | "posttest": "shx cat test/dist/coverage/text.txt", 27 | "update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s", 28 | "version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md", 29 | "watch": "npm-run-all -p watch:*", 30 | "watch:js": "npm run build:js -- -w", 31 | "prepublishOnly": "npm run build && vjsverify --skip-require" 32 | }, 33 | "keywords": [ 34 | "MPEG-DASH", 35 | "dash", 36 | "dash.js", 37 | "dashjs", 38 | "playready", 39 | "video.js", 40 | "videojs", 41 | "videojs-plugin", 42 | "widevine" 43 | ], 44 | "browserify-shim": { 45 | "video.js": "global:videojs" 46 | }, 47 | "files": [ 48 | "CONTRIBUTING.md", 49 | "dist/", 50 | "docs/", 51 | "index.html", 52 | "scripts/", 53 | "src/", 54 | "test/" 55 | ], 56 | "dependencies": { 57 | "dashjs": "^4.2.0", 58 | "global": "^4.3.2", 59 | "video.js": "^5.18.0 || ^6 || ^7" 60 | }, 61 | "devDependencies": { 62 | "@gkatsev/rollup-plugin-node-builtins": "^2.1.4", 63 | "conventional-changelog-cli": "^2.0.1", 64 | "conventional-changelog-videojs": "^3.0.1", 65 | "doctoc": "^1.3.1", 66 | "husky": "^1.0.0-rc.13", 67 | "is-ci": "^3.0.0", 68 | "jsdoc": "3.6.6", 69 | "karma": "^6.1.1", 70 | "lint-staged": "^7.2.2", 71 | "not-prerelease": "^1.0.1", 72 | "npm-merge-driver-install": "^2.0.1", 73 | "npm-run-all": "^4.1.5", 74 | "rollup": "^0.66.0", 75 | "rollup-plugin-node-globals": "^1.4.0", 76 | "shx": "^0.3.2", 77 | "sinon": "^6.1.5", 78 | "videojs-generate-karma-config": "^5.0.1", 79 | "videojs-generate-rollup-config": "~2.3.0", 80 | "videojs-generator-verify": "^3.0.1", 81 | "videojs-standard": "~7.1.0" 82 | }, 83 | "module": "dist/videojs-dash.es.js", 84 | "generator-videojs-plugin": { 85 | "version": "7.3.2" 86 | }, 87 | "browserslist": [ 88 | "defaults", 89 | "ie 11" 90 | ], 91 | "vjsstandard": { 92 | "ignore": [ 93 | "dist", 94 | "docs", 95 | "test/dist" 96 | ] 97 | }, 98 | "husky": { 99 | "hooks": { 100 | "pre-commit": "lint-staged" 101 | } 102 | }, 103 | "lint-staged": { 104 | "*.js": [ 105 | "vjsstandard --fix", 106 | "git add" 107 | ], 108 | "README.md": [ 109 | "npm run docs:toc", 110 | "git add" 111 | ] 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |BBB
15 | 16 |BBB - oceans track
17 | 20 |Angel One - broken subs
21 | 22 |Angel One - DRM
23 | 24 |Livesim
25 | 26 |Livesim - multi-subs
27 | 28 | 29 | 30 | 31 | 32 | 103 | 104 | 105 |