12
node_modules/videojs-ima/node_modules/.bin/mpd-to-m3u8-json
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../mpd-parser/bin/parse.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../mpd-parser/bin/parse.js" "$@"
|
||||
fi
|
17
node_modules/videojs-ima/node_modules/.bin/mpd-to-m3u8-json.cmd
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mpd-parser\bin\parse.js" %*
|
28
node_modules/videojs-ima/node_modules/.bin/mpd-to-m3u8-json.ps1
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../mpd-parser/bin/parse.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../mpd-parser/bin/parse.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../mpd-parser/bin/parse.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../mpd-parser/bin/parse.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
12
node_modules/videojs-ima/node_modules/.bin/muxjs-transmux
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../mux.js/bin/transmux.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../mux.js/bin/transmux.js" "$@"
|
||||
fi
|
17
node_modules/videojs-ima/node_modules/.bin/muxjs-transmux.cmd
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mux.js\bin\transmux.js" %*
|
28
node_modules/videojs-ima/node_modules/.bin/muxjs-transmux.ps1
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../mux.js/bin/transmux.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../mux.js/bin/transmux.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../mux.js/bin/transmux.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../mux.js/bin/transmux.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
1091
node_modules/videojs-ima/node_modules/@videojs/http-streaming/CHANGELOG.md
generated
vendored
Normal file
30
node_modules/videojs-ima/node_modules/@videojs/http-streaming/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
|
49
node_modules/videojs-ima/node_modules/@videojs/http-streaming/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
Copyright Brightcove, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
The AES decryption implementation in this project is derived from the
|
||||
Stanford Javascript Cryptography Library
|
||||
(http://bitwiseshiftleft.github.io/sjcl/). That work is covered by the
|
||||
following copyright and permission notice:
|
||||
|
||||
Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation
|
||||
are those of the authors and should not be interpreted as representing
|
||||
official policies, either expressed or implied, of the authors.
|
1016
node_modules/videojs-ima/node_modules/@videojs/http-streaming/README.md
generated
vendored
Normal file
32699
node_modules/videojs-ima/node_modules/@videojs/http-streaming/dist/videojs-http-streaming-sync-workers.js
generated
vendored
Normal file
26657
node_modules/videojs-ima/node_modules/@videojs/http-streaming/dist/videojs-http-streaming.cjs.js
generated
vendored
Normal file
26630
node_modules/videojs-ima/node_modules/@videojs/http-streaming/dist/videojs-http-streaming.es.js
generated
vendored
Normal file
32646
node_modules/videojs-ima/node_modules/@videojs/http-streaming/dist/videojs-http-streaming.js
generated
vendored
Normal file
6
node_modules/videojs-ima/node_modules/@videojs/http-streaming/dist/videojs-http-streaming.min.js
generated
vendored
Normal file
51
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/README.md
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Overview
|
||||
This project supports both [HLS][hls] and [MPEG-DASH][dash] playback in the video.js player. This document is intended as a primer for anyone interested in contributing or just better understanding how bits from a server get turned into video on their display.
|
||||
|
||||
## HTTP Live Streaming
|
||||
[HLS][apple-hls-intro] has two primary characteristics that distinguish it from other video formats:
|
||||
|
||||
- Delivered over HTTP(S): it uses the standard application protocol of the web to deliver all its data
|
||||
- Segmented: longer videos are broken up into smaller chunks which can be downloaded independently and switched between at runtime
|
||||
|
||||
A standard HLS stream consists of a *Master Playlist* which references one or more *Media Playlists*. Each Media Playlist contains one or more sequential video segments. All these components form a logical hierarchy that informs the player of the different quality levels of the video available and how to address the individual segments of video at each of those levels:
|
||||
|
||||

|
||||
|
||||
HLS streams can be delivered in two different modes: a "static" mode for videos that can be played back from any point, often referred to as video-on-demand (VOD); or a "live" mode where later portions of the video become available as time goes by. In the static mode, the Master and Media playlists are fixed. The player is guaranteed that the set of video segments referenced by those playlists will not change over time.
|
||||
|
||||
Live mode can work in one of two ways. For truly live events, the most common configuration is for each individual Media Playlist to only include the latest video segment and a small number of consecutive previous segments. In this mode, the player may be able to seek backwards a short time in the video but probably not all the way back to the beginning. In the other live configuration, new video segments can be appended to the Media Playlists but older segments are never removed. This configuration allows the player to seek back to the beginning of the stream at any time during the broadcast and transitions seamlessly to the static stream type when the event finishes.
|
||||
|
||||
If you're interested in a more in-depth treatment of the HLS format, check out [Apple's documentation][apple-hls-intro] and the IETF [Draft Specification][hls-spec].
|
||||
|
||||
## Dynamic Adaptive Streaming over HTTP
|
||||
Similar to HLS, [DASH][dash-wiki] content is segmented and is delivered over HTTP(s).
|
||||
|
||||
A DASH stream consits of a *Media Presentation Description*(MPD) that describes segment metadata such as timing information, URLs, resolution and bitrate. Each segment can contain either ISO base media file format(e.g MP4) or MPEG-2 TS data. Typically, the MPD will describe the various *Representations* that map to collections of segments at different bitrates to allow bitrate selection. These Representations can be organized as a SegmentList, SegmentTemplate, SegmentBase, or SegmentTimeline.
|
||||
|
||||
DASH streams can be delivered in both video-on-demand(VOD) and live streaming modes. In the VOD case, the MPD describes all the segments and representations available and the player can chose which representation to play based on it's capabilities.
|
||||
|
||||
Live mode is accomplished using the ISOBMFF Live profile if the segments are in ISOBMFF. There are a few different ways to setup the MPD including but not limited to updating the MPD after an interval of time, using *Periods*, or using the *availabilityTimeOffset* field. A few examples of this are provided by the [DASH Reference Client][dash-if-reference-client]. The MPD will provide enough information for the player to playback the live stream and seek back as far as is specified in the MPD.
|
||||
|
||||
If you're interested in a more in-depth description of MPEG-DASH, check out [MDN's tutorial on setting up DASH][mdn-dash-tut] or the [DASHIF Guidelines][dash-if-guide].
|
||||
|
||||
# Further Documentation
|
||||
|
||||
- [Architechture](arch.md)
|
||||
- [Glossary](glossary.md)
|
||||
- [Adaptive Bitrate Switching](bitrate-switching.md)
|
||||
- [Multiple Alternative Audio Tracks](multiple-alternative-audio-tracks.md)
|
||||
- [reloadSourceOnError](reload-source-on-error.md)
|
||||
- [A Walk Through VHS](a-walk-through-vhs.md)
|
||||
|
||||
# Helpful Tools
|
||||
- [FFmpeg](http://trac.ffmpeg.org/wiki/CompilationGuide)
|
||||
- [Thumbcoil](http://thumb.co.il/): web based video inspector
|
||||
|
||||
[hls]: /docs/intro.md#http-live-streaming
|
||||
[dash]: /docs/intro.md#dynamic-adaptive-streaming-over-http
|
||||
[apple-hls-intro]: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/Introduction/Introduction.html
|
||||
[hls-spec]: https://datatracker.ietf.org/doc/draft-pantos-http-live-streaming/
|
||||
[dash-wiki]: https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP
|
||||
[dash-if-reference-client]: https://reference.dashif.org/dash.js/
|
||||
[mdn-dash-tut]: https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery/Setting_up_adaptive_streaming_media_sources
|
||||
[dash-if-guide]: http://dashif.org/guidelines/
|
250
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/a-walk-through-vhs.md
generated
vendored
Normal file
|
@ -0,0 +1,250 @@
|
|||
# A Walk Through VHS
|
||||
|
||||
Today we're going to take a walk through VHS. We'll start from a manifest URL and end with video playback.
|
||||
|
||||
The purpose of this walk is not to see every piece of code, or define every module. Instead it's about seeing the most important parts of VHS. The goal is to make VHS more approachable.
|
||||
|
||||
Lets start with a video tag:
|
||||
|
||||
```html
|
||||
<video>
|
||||
<source src="http://example.com/manifest.m3u8" type="application/x-mpegURL">
|
||||
</video>
|
||||
```
|
||||
|
||||
The source, `manifest.m3u8`, is an HLS manifest. You can tell from the `.m3u8` extension and the `type`.
|
||||
|
||||
Safari (and a few other browsers) will play that video natively, because Safari supports HLS content. However, other browsers don't support native playback of HLS and will fail to play the video.
|
||||
|
||||
VHS provides the ability to play HLS (and DASH) content in browsers that don't support native HLS (and DASH) playback.
|
||||
|
||||
Since VHS is a part of Video.js, let's set up a Video.js player for the `<video>`:
|
||||
|
||||
```html
|
||||
<link href="//vjs.zencdn.net/7.10.2/video-js.min.css" rel="stylesheet">
|
||||
<script src="//vjs.zencdn.net/7.10.2/video.min.js"></script>
|
||||
|
||||
<video-js id="myPlayer" class="video-js" data-setup='{}'>
|
||||
<source src="http://example.com/manifest.m3u8" type="application/x-mpegURL">
|
||||
</video-js>
|
||||
```
|
||||
|
||||
Video.js does a lot of things, but in the context of VHS, the important feature is a way to let VHS handle playback of the source. To do this, VHS is registered as a Video.js Source Handler. When a Video.js player is created and provided a `<source>`, Video.js goes through its list of registered Source Handlers, including VHS, to see if they're able to play that source.
|
||||
|
||||
In this case, because it's an HLS source, VHS will tell Video.js "I can handle that!" From there, VHS is given the URL and it begins its process.
|
||||
|
||||
## videojs-http-streaming.js
|
||||
|
||||
`VhsSourceHandler` is defined at the [bottom of src/videojs-http-streaming.js](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/videojs-http-streaming.js#L1226-L1233).
|
||||
|
||||
The function which Video.js calls to see if the `VhsSourceHandler` can handle the source is aptly named `canHandleSource`.
|
||||
|
||||
Inside `canHandleSource`, VHS checks the source's `type`. In our case, it sees `application/x-mpegURL`, and, if we're running in a browser with MSE, then it says "I can handle it!" (It actually says "maybe," because in life there are few guarantees, and because the spec says to use "maybe.")
|
||||
|
||||
### VhsSourceHandler
|
||||
|
||||
Since VHS told Video.js that it can handle the source, Video.js passes the source to `VhsSourceHandler`'s `handleSource` function. That's where VHS really gets going. It creates a new `VhsHandler` object, merges some options, and performs initial setup. For instance, it creates listeners on some `tech` events.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
```
|
||||
|
||||
> :information_source: **What should be put in VhsHandler?**
|
||||
>
|
||||
> videojs-http-streaming.js is a good place for interfacing with Video.js and other plugins, isolating integrations from the rest of the code.
|
||||
>
|
||||
> Here are a couple of examples of what's done within videojs-http-streaming.js:
|
||||
> * most EME handling for DRM and setup of the [videojs-contrib-eme plugin](https://github.com/videojs/videojs-contrib-eme)
|
||||
> * mapping/handling of options passed down via Video.js
|
||||
|
||||
## MasterPlaylistController
|
||||
|
||||
One critical object that `VhsHandler`'s constructor creates is a new `MasterPlaylistController`.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
VhsHandler --> MasterPlaylistController
|
||||
```
|
||||
|
||||
`MasterPlaylistController` is not a great name, and has grown in size to be a bit unwieldy, but it's the hub of VHS. Eventually, it should be broken into smaller pieces, but for now, it handles the creation and management of most of the other VHS modules. Its code can be found in [src/master-playlist-controller.js](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js).
|
||||
|
||||
The best way to think of `MasterPlaylistController` is as Tron's Master Control Program, though hopefully it isn't as evil.
|
||||
|
||||
`MasterPlaylistController` is a lot to say. So we often refer to it as MPC.
|
||||
|
||||
If you need to find a place where different modules communicate, you will probably end up in MPC. Just about all of `VhsHandler` that doesn't interface with Video.js or other plugins, interfaces with MPC.
|
||||
|
||||
MPC's [constructor](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js#L148) does a lot. Instead of listing all of the things it does, let's go step-by-step through the main ones, passing the source we had above.
|
||||
|
||||
```html
|
||||
<video-js id="myPlayer" class="video-js" data-setup='{}'>
|
||||
<source src="http://example.com/manifest.m3u8" type="application/x-mpegURL">
|
||||
</video-js>
|
||||
```
|
||||
|
||||
Looking at the `<source>` tag, `VhsSourceHandler` already used the "type" to tell Video.js that it could handle the source. `VhsHandler` took the manifest URL, in this case "manifest.m3u8" and provided it to the constructor of MPC.
|
||||
|
||||
The first thing that MPC must do is download that source, but it doesn't make the request itself. Instead, it creates [this.masterPlaylistLoader_](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js#L264-L266).
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
VhsHandler --> MasterPlaylistController
|
||||
MasterPlaylistController --> PlaylistLoader
|
||||
```
|
||||
|
||||
`masterPlaylistLoader_` is an instance of either the [HLS PlaylistLoader](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/playlist-loader.js#L379) or the [DashPlaylistLoader](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/dash-playlist-loader.js#L259).
|
||||
|
||||
The names betray their use. They load the playlist. The URL ("manifest.m3u8" here) is given, and the manifest/playlist is downloaded and parsed. If the content is live, the playlist loader also handles refreshing the manifest. For HLS, where manifests point to other manifests, the playlist loader requests those as well.
|
||||
|
||||
As for parsing, for HLS, the manifest responses are parsed using [m3u8-parser](https://github.com/videojs/m3u8-parser). For DASH, the manifest response is parsed using [mpd-parser](https://github.com/videojs/mpd-parser). The output of these parsers is a JSON object that VHS understands. The main structure can be seen in the READMEs, e.g., [here](https://github.com/videojs/m3u8-parser#parsed-output).
|
||||
|
||||
So what was once a URL in a `<source>` tag was requested and parsed into a JSON object like the following:
|
||||
|
||||
```
|
||||
Manifest {
|
||||
playlists: [
|
||||
{
|
||||
attributes: {},
|
||||
Manifest
|
||||
}
|
||||
],
|
||||
mediaGroups: { ... },
|
||||
segments: [ ... ],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Many properties are removed for simplicity. This is a top level manifest (often referred to as a master or main manifest), and within it there are playlists, each playlist being a Manifest itself. Since the JSON "schema" for main and media playlists is the same, you will see irrelevant properties within any given manifest object. For instance, you might see a `targetDuration` property on the main manifest object, though a main manifest doesn't have a target duration. You can ignore irrelevant properties. Eventually they should be cleaned up, and a proper schema defined for manifest objects.
|
||||
|
||||
MPC will also use `masterPlaylistLoader_` to select which media playlist is active (e.g., the 720p rendition or the 480p rendition), so that `masterPlaylistLoader_` will only need to refresh that individual playlist if the stream is live.
|
||||
|
||||
> :information_source: **Future Work**
|
||||
>
|
||||
> The playlist loaders are not the clearest modules. Work has been started on improvements to the loaders and how we use them: https://github.com/videojs/http-streaming/pull/1208
|
||||
>
|
||||
> That work makes them much easier to read, but will require changes throughout the rest of the code before the old PlaylistLoader and DashPlaylistLoader code can be removed.
|
||||
|
||||
### Media Source Extensions
|
||||
|
||||
The next thing MPC needs to do is set up a media source for [Media Source Extensions](https://www.w3.org/TR/media-source/). Specifically, it needs to create [this.mediaSource](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js#L210) and its associated [source buffers](https://github.com/videojs/http-streaming/blob/main/src/master-playlist-controller.js#L1818). These are where audio and video data will be appended, so that the browser has content to play. But those aren't used directly. Because source buffers can only handle one operation at a time, [this.sourceUpdater_](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js#L234) is created. `sourceUpdater_` is a queue for operations performed on the source buffers. That's pretty much it. So all of the MSE pieces for appending get wrapped up in `sourceUpdater_`.
|
||||
|
||||
## Segment Loaders
|
||||
|
||||
The SourceUpdater created for MSE above is passed to the segment loaders.
|
||||
|
||||
[this.mainSegmentLoader_](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js#L271-L275) is used for muxed content (audio and video in one segment) and for audio or video only streams.
|
||||
|
||||
[this.audioSegmentLoader_](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js#L278-L281) is used when the content is demuxed (audio and video in separate playlists).
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
VhsHandler --> MasterPlaylistController
|
||||
MasterPlaylistController --> PlaylistLoader
|
||||
MasterPlaylistController --> SourceUpdater
|
||||
MasterPlaylistController --> SegmentLoader
|
||||
```
|
||||
|
||||
Besides options and the `sourceUpdater_` from MPC, the segment loaders are given a [playlist](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/segment-loader.js#L988). This playlist is a media playlist from the `masterPlaylistLoader_`. So looking back at our parsed manifest object:
|
||||
|
||||
```
|
||||
Manifest {
|
||||
playlists: [
|
||||
{
|
||||
attributes: {},
|
||||
Manifest
|
||||
}
|
||||
],
|
||||
mediaGroups: { ... },
|
||||
segments: [ ... ],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The media playlists were those objects found in the `playlists` array. Each segment loader is given one of those.
|
||||
|
||||
Segment Loader uses the provided media playlist to determine which segment to download next. It performs this check when [monitorBuffer_](https://github.com/videojs/http-streaming/blob/main/src/segment-loader.js#L1300) is called, which ultimately runs [chooseNextRequest_](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/segment-loader.js#L1399). `chooseNextRequest_` looks at the buffer, the current time, and a few other properties to choose what segment to download from the `playlist`'s `segments` array.
|
||||
|
||||
### Choosing Segments to Download
|
||||
|
||||
VHS uses a strategy called `mediaIndex++` for choosing the next segment, see [here](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/segment-loader.js#L1442). This means that, if segment 3 was previously requested, segment 4 should be requested next, and segment 5 after that. Those segment numbers are determined by the HLS [#EXT-X-MEDIA-SEQUENCE tag](https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-10#section-4.4.3.2).
|
||||
|
||||
If there are no seeks or rendition changes, `chooseNextRequest_` will rely on the `mediaIndex++` strategy.
|
||||
|
||||
If there are seeks or rendition changes, then `chooseNextRequest_` will look at segment timing values via the `SyncController` (created previously in MPC), the current time, and the buffer, to determine what the next segment should be, and what it's start time should be (to position it on the timeline).
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
VhsHandler --> MasterPlaylistController
|
||||
MasterPlaylistController --> PlaylistLoader
|
||||
MasterPlaylistController --> SourceUpdater
|
||||
MasterPlaylistController --> SegmentLoader
|
||||
SegmentLoader --> SyncController
|
||||
```
|
||||
|
||||
The `SyncController` has various [strategies](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/sync-controller.js#L16) for ensuring that different renditions, which can have different media sequence and segment timing values, can be positioned on the playback timeline successfully. (It is also be [used by MPC](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/master-playlist-controller.js#L1477) to establish a `seekable` range.)
|
||||
|
||||
### Downloading and Appending Segments
|
||||
|
||||
If the buffer is not full, and a segment was chosen, then `SegmentLoader` will download and append it. It does this via a [mediaSegmentRequest](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/segment-loader.js#L2489).
|
||||
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
VhsHandler --> MasterPlaylistController
|
||||
MasterPlaylistController --> PlaylistLoader
|
||||
MasterPlaylistController --> SourceUpdater
|
||||
MasterPlaylistController --> SegmentLoader
|
||||
SegmentLoader --> SyncController
|
||||
SegmentLoader --> mediaSegmentRequest
|
||||
```
|
||||
|
||||
`mediaSegmentRequest` takes a lot of arguments. Most are callbacks. These callbacks provide the data that `SegmentLoader` needs to append the segment. It includes the timing information of the segment, captions, and the segment data.
|
||||
|
||||
When the `SegmentLoader` receives timing info events, it can update the source buffer's timestamp offset (via `SourceUpdater`).
|
||||
|
||||
When the `SegmentLoader` receives segment data events, it can append the data to the source buffer (via `SourceUpdater`).
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
VhsHandler --> MasterPlaylistController
|
||||
MasterPlaylistController --> PlaylistLoader
|
||||
MasterPlaylistController --> SourceUpdater
|
||||
MasterPlaylistController --> SegmentLoader
|
||||
SegmentLoader --> SyncController
|
||||
SegmentLoader --> mediaSegmentRequest
|
||||
SegmentLoader --> SourceUpdater
|
||||
```
|
||||
|
||||
## mediaSegmentRequest
|
||||
|
||||
We talked a bit about how `SegmentLoader` uses `mediaSegmentRequest`, but what does [mediaSegmentRequest](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/media-segment-request.js#L941) do?
|
||||
|
||||
Besides downloading segments, `mediaSegmentRequest` [decrypts](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/media-segment-request.js#L621) AES encrypted segments, probes [MP4](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/media-segment-request.js#L171) and [TS](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/media-segment-request.js#L375) segments for timing info, and [transmuxes](https://github.com/videojs/http-streaming/blob/0964cb4827d9e80aa36f2fa29e35dad92ca84111/src/media-segment-request.js#L280) TS segments into MP4s using [mux.js](https://github.com/videojs/mux.js) so they can be appended to the source buffers.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
VhsSourceHandler --> VhsHandler
|
||||
VhsHandler --> MasterPlaylistController
|
||||
MasterPlaylistController --> PlaylistLoader
|
||||
MasterPlaylistController --> SourceUpdater
|
||||
MasterPlaylistController --> SegmentLoader
|
||||
SegmentLoader --> SyncController
|
||||
SegmentLoader --> mediaSegmentRequest
|
||||
SegmentLoader --> SourceUpdater
|
||||
mediaSegmentRequest --> mux.js
|
||||
```
|
||||
|
||||
## Video playback begins
|
||||
|
||||
The video can start playing as soon as there's enough audio and video (for muxed streams) in the buffer to move the playhead forwards. So playback may begin before the `SegmentLoader` completes its full cycle.
|
||||
|
||||
But once `SegmentLoader` does finish, it starts the process again, looking for new content.
|
||||
|
||||
There are other modules, and other functions of the code (e.g., blacklisting logic, ABR, etc.), but this is the most critical path of VHS, the one that allows video to play in the browser.
|
28
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/arch.md
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
## HLS Project Overview
|
||||
This project has three primary duties:
|
||||
|
||||
1. Download and parse playlist files
|
||||
1. Implement the [HTMLVideoElement](https://html.spec.whatwg.org/multipage/embedded-content.html#the-video-element) interface
|
||||
1. Feed content bits to a SourceBuffer by downloading and transmuxing video segments
|
||||
|
||||
### Playlist Management
|
||||
The [playlist loader](../src/playlist-loader.js) handles all of the details of requesting, parsing, updating, and switching playlists at runtime. It's operation is described by this state diagram:
|
||||
|
||||

|
||||
|
||||
During VOD playback, the loader will move quickly to the HAVE_METADATA state and then stay there unless a quality switch request sends it to SWITCHING_MEDIA while it fetches an alternate playlist. The loader enters the HAVE_CURRENT_METADATA when a live stream is detected and it's time to refresh the current media playlist to find out about new video segments.
|
||||
|
||||
### HLS Tech
|
||||
Currently, the HLS project integrates with [video.js](http://www.videojs.com/) as a [tech](https://github.com/videojs/video.js/blob/master/docs/guides/tech.md). That means it's responsible for providing an interface that closely mirrors the `<video>` element. You can see that implementation in [videojs-http-streaming.js](../src/videojs-http-streaming.js), the primary entry point of the project.
|
||||
|
||||
### Transmuxing
|
||||
Most browsers don't have support for the file type that HLS video segments are stored in. To get HLS playing back on those browsers, contrib-hls strings together a number of technologies:
|
||||
|
||||
1. The [Netstream](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html) in [video.js SWF](https://github.com/videojs/video-js-swf) has a special mode of operation that allows binary video data packaged as an [FLV](http://en.wikipedia.org/wiki/Flash_Video) to be provided directly
|
||||
1. [videojs-contrib-media-sources](https://github.com/videojs/videojs-contrib-media-sources) provides an abstraction layer over the SWF that operates like a [Media Source](https://w3c.github.io/media-source/#mediasource)
|
||||
1. A pure javascript transmuxer that repackages HLS segments as FLVs
|
||||
|
||||
Transmuxing is the process of transforming media stored in one container format into another container without modifying the underlying media data. If that last sentence doesn't make any sense to you, check out the [Introduction to Media](media.md) for more details.
|
||||
|
||||
### Buffer Management
|
||||
Buffering in contrib-hls is driven by two functions in videojs-hls.js: fillBuffer() and drainBuffer(). During its operation, contrib-hls periodically calls fillBuffer() which determines when more video data is required and begins a segment download if so. Meanwhile, drainBuffer() is invoked periodically during playback to process incoming segments and append them onto the [SourceBuffer](http://w3c.github.io/media-source/#sourcebuffer). In conjunction with a goal buffer length, this producer-consumer relationship drives the buffering behavior of contrib-hls.
|
44
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/bitrate-switching.md
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Adaptive Switching Behavior
|
||||
The HLS tech tries to ensure the highest-quality viewing experience
|
||||
possible, given the available bandwidth and encodings. This doesn't
|
||||
always mean using the highest-bitrate rendition available-- if the player
|
||||
is 300px by 150px, it would be a big waste of bandwidth to download a 4k
|
||||
stream. By default, the player attempts to load the highest-bitrate
|
||||
variant that is less than the most recently detected segment bandwidth,
|
||||
with one condition: if there are multiple variants with dimensions greater
|
||||
than the current player size, it will only switch up one size greater
|
||||
than the current player size.
|
||||
|
||||
If you're the visual type, the whole process is illustrated
|
||||
below. Whenever a new segment is downloaded, we calculate the download
|
||||
bitrate based on the size of the segment and the time it took to
|
||||
download:
|
||||
|
||||

|
||||
|
||||
First, we filter out all the renditions that have a higher bitrate
|
||||
than the new measurement:
|
||||
|
||||

|
||||
|
||||
Then we get rid of any renditions that are bigger than the current
|
||||
player dimensions:
|
||||
|
||||

|
||||
|
||||
We don't want to signficant quality drop just because your player is
|
||||
one pixel too small, so we add back in the next highest
|
||||
resolution. The highest bitrate rendition that remains is the one that
|
||||
gets used:
|
||||
|
||||

|
||||
|
||||
If it turns out no rendition is acceptable based on the filtering
|
||||
described above, the first encoding listed in the master playlist will
|
||||
be used.
|
||||
|
||||
If you'd like your player to use a different set of priorities, it's
|
||||
possible to completely replace the rendition selection logic. For
|
||||
instance, you could always choose the most appropriate rendition by
|
||||
resolution, even though this might mean more stalls during playback.
|
||||
See the documentation on `player.vhs.selectPlaylist` for more details.
|
264
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/creating-content.md
generated
vendored
Normal file
|
@ -0,0 +1,264 @@
|
|||
# Creating Content
|
||||
|
||||
## Commands for creating tests streams
|
||||
|
||||
### Streams with EXT-X-PROGRAM-DATE-TIME for testing seekToProgramTime and convertToProgramTime
|
||||
|
||||
lavfi and testsrc are provided for creating a test stream in ffmpeg
|
||||
-g 300 sets the GOP size to 300 (keyframe interval, at 30fps, one keyframe every 10 seconds)
|
||||
-f hls sets the format to HLS (creates an m3u8 and TS segments)
|
||||
-hls\_time 10 sets the goal segment size to 10 seconds
|
||||
-hls\_list\_size 20 sets the number of segments in the m3u8 file to 20
|
||||
-program\_date\_time an hls flag for setting #EXT-X-PROGRAM-DATE-TIME on each segment
|
||||
|
||||
```
|
||||
ffmpeg \
|
||||
-f lavfi \
|
||||
-i testsrc=duration=200:size=1280x720:rate=30 \
|
||||
-g 300 \
|
||||
-f hls \
|
||||
-hls_time 10 \
|
||||
-hls_list_size 20 \
|
||||
-hls_flags program_date_time \
|
||||
stream.m3u8
|
||||
```
|
||||
|
||||
## Commands used for segments in `test/segments` dir
|
||||
|
||||
### video.ts
|
||||
|
||||
Copy only the first two video frames, leave out audio.
|
||||
|
||||
```
|
||||
$ ffmpeg -i index0.ts -vframes 2 -an -vcodec copy video.ts
|
||||
```
|
||||
|
||||
### videoOneSecond.ts
|
||||
|
||||
Blank video for 1 second, MMS-Small resolution, start at 0 PTS/DTS, 2 frames per second
|
||||
|
||||
```
|
||||
$ ffmpeg -f lavfi -i color=c=black:s=128x96:r=2:d=1 -muxdelay 0 -c:v libx264 videoOneSecond.ts
|
||||
```
|
||||
|
||||
### videoOneSecond1.ts through videoOneSecond4.ts
|
||||
|
||||
Same as videoOneSecond.ts, but follows timing in sequence, with videoOneSecond.ts acting as the 0 index. Each segment starts at the second that its index indicates (e.g., videoOneSecond2.ts has a start time of 2 seconds).
|
||||
|
||||
```
|
||||
$ ffmpeg -i videoOneSecond.ts -muxdelay 0 -output_ts_offset 1 -vcodec copy videoOneSecond1.ts
|
||||
$ ffmpeg -i videoOneSecond.ts -muxdelay 0 -output_ts_offset 2 -vcodec copy videoOneSecond2.ts
|
||||
$ ffmpeg -i videoOneSecond.ts -muxdelay 0 -output_ts_offset 3 -vcodec copy videoOneSecond3.ts
|
||||
$ ffmpeg -i videoOneSecond.ts -muxdelay 0 -output_ts_offset 4 -vcodec copy videoOneSecond4.ts
|
||||
```
|
||||
|
||||
### audio.ts
|
||||
|
||||
Copy only the first two audio frames, leave out video.
|
||||
|
||||
```
|
||||
$ ffmpeg -i index0.ts -aframes 2 -vn -acodec copy audio.ts
|
||||
```
|
||||
|
||||
### videoMinOffset.ts
|
||||
|
||||
video.ts but with an offset of 0
|
||||
|
||||
```
|
||||
$ ffmpeg -i video.ts -muxpreload 0 -muxdelay 0 -vcodec copy videoMinOffset.ts
|
||||
```
|
||||
|
||||
### audioMinOffset.ts
|
||||
|
||||
audio.ts but with an offset of 0. Note that muxed.ts is used because ffmpeg didn't like
|
||||
the use of audio.ts
|
||||
|
||||
```
|
||||
$ ffmpeg -i muxed.ts -muxpreload 0 -muxdelay 0 -acodec copy -vn audioMinOffset.ts
|
||||
```
|
||||
|
||||
### videoMaxOffset.ts
|
||||
|
||||
This segment offsets content such that it ends at exactly the max timestamp before a rollover occurs. It uses the max timestamp of 2^33 (8589934592) minus the segment duration of 6006 (0.066733 seconds) in order to not rollover mid segment, and divides the value by 90,000 to convert it from media time to seconds.
|
||||
|
||||
(2^33 - 6006) / 90,000 = 95443.6509556
|
||||
|
||||
```
|
||||
$ ffmpeg -i videoMinOffset.ts -muxdelay 95443.6509556 -muxpreload 95443.6509556 -output_ts_offset 95443.6509556 -vcodec copy videoMaxOffset.ts
|
||||
```
|
||||
|
||||
### audioMaxOffset.ts
|
||||
|
||||
This segment offsets content such that it ends at exactly the max timestamp before a rollover occurs. It uses the max timestamp of 2^33 (8589934592) minus the segment duration of 11520 (0.128000 seconds) in order to not rollover mid segment, and divides the value by 90,000 to convert it from media time to seconds.
|
||||
|
||||
(2^33 - 11520) / 90,000 = 95443.5896889
|
||||
|
||||
```
|
||||
$ ffmpeg -i audioMinOffset.ts -muxdelay 95443.5896889 -muxpreload 95443.5896889 -output_ts_offset 95443.5896889 -acodec copy audioMaxOffset.ts
|
||||
```
|
||||
|
||||
### videoLargeOffset.ts
|
||||
|
||||
This segment offsets content by the rollover threshhold of 2^32 (4294967296) found in the rollover handling of mux.js, adds 1 to ensure there aren't any cases where there's an equal match, then divides the value by 90,000 to convert it from media time to seconds.
|
||||
|
||||
(2^32 + 1) / 90,000 = 47721.8588556
|
||||
|
||||
```
|
||||
$ ffmpeg -i videoMinOffset.ts -muxdelay 47721.8588556 -muxpreload 47721.8588556 -output_ts_offset 47721.8588556 -vcodec copy videoLargeOffset.ts
|
||||
```
|
||||
|
||||
### audioLargeOffset.ts
|
||||
|
||||
This segment offsets content by the rollover threshhold of 2^32 (4294967296) found in the rollover handling of mux.js, adds 1 to ensure there aren't any cases where there's an equal match, then divides the value by 90,000 to convert it from media time to seconds.
|
||||
|
||||
(2^32 + 1) / 90,000 = 47721.8588556
|
||||
|
||||
```
|
||||
$ ffmpeg -i audioMinOffset.ts -muxdelay 47721.8588556 -muxpreload 47721.8588556 -output_ts_offset 47721.8588556 -acodec copy audioLargeOffset.ts
|
||||
```
|
||||
|
||||
### videoLargeOffset2.ts
|
||||
|
||||
This takes videoLargeOffset.ts and adds the duration of videoLargeOffset.ts (6006 / 90,000 = 0.066733 seconds) to its offset so that this segment can act as the second in one continuous stream.
|
||||
|
||||
47721.8588556 + 0.066733 = 47721.9255886
|
||||
|
||||
```
|
||||
$ ffmpeg -i videoLargeOffset.ts -muxdelay 47721.9255886 -muxpreload 47721.9255886 -output_ts_offset 47721.9255886 -vcodec copy videoLargeOffset2.ts
|
||||
```
|
||||
|
||||
### audioLargeOffset2.ts
|
||||
|
||||
This takes audioLargeOffset.ts and adds the duration of audioLargeOffset.ts (11520 / 90,000 = 0.128 seconds) to its offset so that this segment can act as the second in one continuous stream.
|
||||
|
||||
47721.8588556 + 0.128 = 47721.9868556
|
||||
|
||||
```
|
||||
$ ffmpeg -i audioLargeOffset.ts -muxdelay 47721.9868556 -muxpreload 47721.9868556 -output_ts_offset 47721.9868556 -acodec copy audioLargeOffset2.ts
|
||||
```
|
||||
|
||||
### caption.ts
|
||||
|
||||
Copy the first two frames of video out of a ts segment that already includes CEA-608 captions.
|
||||
|
||||
`ffmpeg -i index0.ts -vframes 2 -an -vcodec copy caption.ts`
|
||||
|
||||
### id3.ts
|
||||
|
||||
Copy only the first five frames of video, leave out audio.
|
||||
|
||||
`ffmpeg -i index0.ts -vframes 5 -an -vcodec copy smaller.ts`
|
||||
|
||||
Create an ID3 tag using [id3taggenerator][apple_streaming_tools]:
|
||||
|
||||
`id3taggenerator -text "{\"id\":1, \"data\": \"id3\"}" -o tag.id3`
|
||||
|
||||
Create a file `macro.txt` with the following:
|
||||
|
||||
`0 id3 tag.id3`
|
||||
|
||||
Run [mediafilesegmenter][apple_streaming_tools] with the small video segment and macro file, to produce a new segment with ID3 tags inserted at the specified times.
|
||||
|
||||
`mediafilesegmenter -start-segments-with-iframe --target-duration=1 --meta-macro-file=macro.txt -s -A smaller.ts`
|
||||
|
||||
### mp4Video.mp4
|
||||
|
||||
Copy only the first two video frames, leave out audio.
|
||||
movflags:
|
||||
* frag\_keyframe: "Start a new fragment at each video keyframe."
|
||||
* empty\_moov: "Write an initial moov atom directly at the start of the file, without describing any samples in it."
|
||||
* omit\_tfhd\_offset: "Do not write any absolute base\_data\_offset in tfhd atoms. This avoids tying fragments to absolute byte positions in the file/streams." (see also: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing)
|
||||
|
||||
```
|
||||
$ ffmpeg -i file.mp4 -movflags frag_keyframe+empty_moov+omit_tfhd_offset -vframes 2 -an -vcodec copy mp4Video.mp4
|
||||
```
|
||||
|
||||
### mp4Audio.mp4
|
||||
|
||||
Copy only the first two audio frames, leave out video.
|
||||
movflags:
|
||||
* frag\_keyframe: "Start a new fragment at each video keyframe."
|
||||
* empty\_moov: "Write an initial moov atom directly at the start of the file, without describing any samples in it."
|
||||
* omit\_tfhd\_offset: "Do not write any absolute base\_data\_offset in tfhd atoms. This avoids tying fragments to absolute byte positions in the file/streams." (see also: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing)
|
||||
|
||||
```
|
||||
$ ffmpeg -i file.mp4 -movflags frag_keyframe+empty_moov+omit_tfhd_offset -aframes 2 -vn -acodec copy mp4Audio.mp4
|
||||
```
|
||||
|
||||
### mp4VideoInit.mp4 and mp4AudioInit.mp4
|
||||
|
||||
Using DASH as the format type (-f) will lead to two init segments, one for video and one for audio. Using HLS will lead to one joined.
|
||||
Renamed from .m4s to .mp4
|
||||
|
||||
```
|
||||
$ ffmpeg -i input.mp4 -f dash out.mpd
|
||||
```
|
||||
|
||||
### webmVideoInit.webm and webmVideo.webm
|
||||
|
||||
```
|
||||
$ cat mp4VideoInit.mp4 mp4Video.mp4 > video.mp4
|
||||
$ ffmpeg -i video.mp4 -dash_segment_type webm -c:v libvpx-vp9 -f dash output.mpd
|
||||
$ mv init-stream0.webm webmVideoInit.webm
|
||||
$ mv chunk-stream0-00001.webm webmVideo.webm
|
||||
```
|
||||
|
||||
### subtitlesEncrypted.vtt
|
||||
|
||||
Run subtitles.vtt through subtle crypto. As an example:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs');
|
||||
const { subtle } = require('crypto').webcrypto;
|
||||
|
||||
// first segment has media index 0, so should have the following IV
|
||||
const DEFAULT_IV = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
const getCryptoKey = async (bytes, iv = DEFAULT_IV) => {
|
||||
const algorithm = { name: 'AES-CBC', iv };
|
||||
const extractable = true;
|
||||
const usages = ['encrypt', 'decrypt'];
|
||||
|
||||
return subtle.importKey('raw', bytes, algorithm, extractable, usages);
|
||||
};
|
||||
|
||||
const run = async () => {
|
||||
const keyFilePath = process.argv[2];
|
||||
const segmentFilePath = process.argv[3];
|
||||
|
||||
const keyBytes = fs.readFileSync(keyFilePath);
|
||||
const segmentBytes = fs.readFileSync(segmentFilePath);
|
||||
|
||||
const key = await getCryptoKey(keyBytes);
|
||||
const encryptedBytes = await subtle.encrypt({
|
||||
name: 'AES-CBC',
|
||||
iv: DEFAULT_IV,
|
||||
}, key, segmentBytes);
|
||||
|
||||
fs.writeFileSync('./encrypted.vtt', new Buffer(encryptedBytes));
|
||||
|
||||
console.log(`Wrote ${encryptedBytes.length} bytes to encrypted.vtt:`);
|
||||
};
|
||||
|
||||
run();
|
||||
```
|
||||
|
||||
To use the script:
|
||||
|
||||
```
|
||||
$ node index.js encryptionKey.key subtitles.vtt
|
||||
```
|
||||
|
||||
## Other useful commands
|
||||
|
||||
### Joined (audio and video) initialization segment (for HLS)
|
||||
|
||||
Using DASH as the format type (-f) will lead to two init segments, one for video and one for audio. Using HLS will lead to one joined.
|
||||
Note that -hls\_fmp4\_init\_filename defaults to init.mp4, but is here for readability.
|
||||
Without specifying fmp4 for hls\_segment\_type, ffmpeg defaults to ts.
|
||||
|
||||
```
|
||||
$ ffmpeg -i input.mp4 -f hls -hls_fmp4_init_filename init.mp4 -hls_segment_type fmp4 out.m3u8
|
||||
```
|
||||
|
||||
[apple_streaming_tools]: https://developer.apple.com/documentation/http_live_streaming/about_apple_s_http_live_streaming_tools
|
87
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/dash-playlist-loader.md
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
# DASH Playlist Loader
|
||||
|
||||
## Purpose
|
||||
|
||||
The [DashPlaylistLoader][dpl] (DPL) is responsible for requesting MPDs, parsing them and keeping track of the media "playlists" associated with the MPD. The [DPL] is used with a [SegmentLoader] to load fmp4 fragments from a DASH source.
|
||||
|
||||
## Basic Responsibilities
|
||||
|
||||
1. To request an MPD.
|
||||
2. To parse an MPD into a format [videojs-http-streaming][vhs] can understand.
|
||||
3. To refresh MPDs according to their minimumUpdatePeriod.
|
||||
4. To allow selection of a specific media stream.
|
||||
5. To sync the client clock with a server clock according to the UTCTiming node.
|
||||
6. To refresh a live MPD for changes.
|
||||
|
||||
## Design
|
||||
|
||||
The [DPL] is written to be as similar as possible to the [PlaylistLoader][pl]. This means that majority of the public API for these two classes are the same, and so are the states they go through and events that they trigger.
|
||||
|
||||
### States
|
||||
|
||||

|
||||
|
||||
- `HAVE_NOTHING` the state before the MPD is received and parsed.
|
||||
- `HAVE_MASTER` the state before a media stream is setup but the MPD has been parsed.
|
||||
- `HAVE_METADATA` the state after a media stream is setup.
|
||||
|
||||
### API
|
||||
|
||||
- `load()` this will either start or kick the loader during playback.
|
||||
- `start()` this will start the [DPL] and request the MPD.
|
||||
- `parseMasterXml()` this will parse the MPD manifest and return the result.
|
||||
- `media()` this will return the currently active media stream or set a new active media stream.
|
||||
|
||||
### Events
|
||||
|
||||
- `loadedplaylist` signals the setup of a master playlist, representing the DASH source as a whole, from the MPD; or a media playlist, representing a media stream.
|
||||
- `loadedmetadata` signals initial setup of a media stream.
|
||||
- `minimumUpdatePeriod` signals that a update period has ended and the MPD must be requested again.
|
||||
- `playlistunchanged` signals that no changes have been made to a MPD.
|
||||
- `mediaupdatetimeout` signals that a live MPD and media stream must be refreshed.
|
||||
- `mediachanging` signals that the currently active media stream is going to be changed.
|
||||
- `mediachange` signals that the new media stream has been updated.
|
||||
|
||||
### Interaction with Other Modules
|
||||
|
||||

|
||||
|
||||
### Special Features
|
||||
|
||||
There are a few features of [DPL] that are different from [PL] due to fundamental differences between HLS and DASH standards.
|
||||
|
||||
#### MinimumUpdatePeriod
|
||||
|
||||
This is a time period specified in the MPD after which the MPD should be re-requested and parsed. There could be any number of changes to the MPD between these update periods.
|
||||
|
||||
#### SyncClientServerClock
|
||||
|
||||
There is a UTCTiming node in the MPD that allows the client clock to be synced with a clock on the server. This may affect the results of parsing the MPD.
|
||||
|
||||
#### Requesting `sidx` Boxes
|
||||
|
||||
To be filled out.
|
||||
|
||||
### Previous Behavior
|
||||
|
||||
Until version 1.9.0 of [VHS], we thought that [DPL] could skip the `HAVE_NOTHING` and `HAVE_MASTER` states, as no other XHR requests are needed once the MPD has been downloaded and parsed. However, this is incorrect as there are some Presentations that signal the use of a "Segment Index box" or `sidx`. This `sidx` references specific byte ranges in a file that could contain media or potentially other `sidx` boxes.
|
||||
|
||||
A DASH MPD that describes a `sidx` is therefore similar to an HLS master manifest, in that the MPD contains references to something that must be requested and parsed first before references to media segments can be obtained. With this in mind, it was necessary to update the initialization and state transitions of [DPL] to allow further XHR requests to be made after the initial request for the MPD.
|
||||
|
||||
### Current Behavior
|
||||
|
||||
In [this PR](https://github.com/videojs/http-streaming/pull/386), the [DPL] was updated to go through the `HAVE_NOTHING` and `HAVE_MASTER` states before arriving at `HAVE_METADATA`. If the MPD does not contain `sidx` boxes, then this transition happens quickly after `load()` is called, spending little time in the `HAVE_MASTER` state.
|
||||
|
||||
The initial media selection for `masterPlaylistLoader` is made in the `loadedplaylist` handler located in [MasterPlaylistController][mpc]. We now use `hasPendingRequest` to determine whether to automatically select a media playlist for the `masterPlaylistLoader` as a fallback in case one is not selected by [MPC]. The child [DPL]s are created with a media playlist passed in as an argument, so this fallback is not necessary for them. Instead, that media playlist is saved and auto-selected once we enter the `HAVE_MASTER` state.
|
||||
|
||||
The `updateMaster` method will return `null` if no updates are found.
|
||||
|
||||
The `selectinitialmedia` event is not triggered until an audioPlaylistLoader (which for DASH is always a child [DPL]) has a media playlist. This is signaled by triggering `loadedmetadata` on the respective [DPL]. This event is used to initialize the [Representations API][representations] and setup EME (see [contrib-eme]).
|
||||
|
||||
[dpl]: ../src/dash-playlist-loader.js
|
||||
[sl]: ../src/segment-loader.js
|
||||
[vhs]: intro.md
|
||||
[pl]: ../src/playlist-loader.js
|
||||
[mpc]: ../src/master-playlist-controller.js
|
||||
[representations]: ../README.md#hlsrepresentations
|
||||
[contrib-eme]: https://github.com/videojs/videojs-contrib-eme
|
23
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/glossary.md
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Glossary
|
||||
|
||||
**Playlist**: This is a representation of an HLS or DASH manifest.
|
||||
|
||||
**Media Playlist**: This is a manifest that represents a single rendition or media stream of the source.
|
||||
|
||||
**Master Playlist Controller**: This acts as the main controller for the playback engine. It interacts with the SegmentLoaders, PlaylistLoaders, PlaybackWatcher, etc.
|
||||
|
||||
**Playlist Loader**: This will request the source and load the master manifest. It is also instructed by the ABR algorithm to load a media playlist or wraps a media playlist if it is provided as the source. There are more details about the playlist loader [here](./arch.md).
|
||||
|
||||
**DASH Playlist Loader**: This will do as the PlaylistLoader does, but for DASH sources. It also handles DASH specific functionaltiy, such as refreshing the MPD according to the minimumRefreshPeriod and synchronizing to a server clock.
|
||||
|
||||
**Segment Loader**: This determines which segment should be loaded, requests it via the Media Segment Loader and passes the result to the Source Updater.
|
||||
|
||||
**Media Segment Loader**: This requests a given segment, decrypts the segment if necessary, and returns it to the Segment Loader.
|
||||
|
||||
**Source Updater**: This manages the browser's [SourceBuffers](https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer). It appends decrypted segment bytes provided by the Segment Loader to the corresponding Source Buffer.
|
||||
|
||||
**ABR(Adaptive Bitrate) Algorithm**: This concept is described more in detail [here](https://en.wikipedia.org/wiki/Adaptive_bitrate_streaming). Our chosen ABR algorithm is referenced by [selectPlaylist](../README.md#hlsselectplaylist) and is described more [here](./bitrate-switching.md).
|
||||
|
||||
**Playback Watcher**: This attemps to resolve common playback stalls caused by improper seeking, gaps in content and browser issues.
|
||||
|
||||
**Sync Controller**: This will attempt to create a mapping between the segment index and a display time on the player.
|
20
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/hlse.md
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Encrypted HTTP Live Streaming
|
||||
The [HLS spec](http://tools.ietf.org/html/draft-pantos-http-live-streaming-13#section-6.2.3) requires segments to be encrypted with AES-128 in CBC mode with PKCS7 padding. You can encrypt data to that specification with a combination of [OpenSSL](https://www.openssl.org/) and the [pkcs7 utility](https://github.com/brightcove/pkcs7). From the command-line:
|
||||
|
||||
```sh
|
||||
# encrypt the text "hello" into a file
|
||||
# since this is for testing, skip the key salting so the output is stable
|
||||
# using -nosalt outside of testing is a terrible idea!
|
||||
echo -n "hello" | pkcs7 | \
|
||||
openssl enc -aes-128-cbc -nopad -nosalt -K $KEY -iv $IV > hello.encrypted
|
||||
|
||||
# xxd is a handy way of translating binary into a format easily consumed by
|
||||
# javascript
|
||||
xxd -i hello.encrypted
|
||||
```
|
||||
|
||||
Later, you can decrypt it:
|
||||
|
||||
```sh
|
||||
openssl enc -d -nopad -aes-128-cbc -K $KEY -iv $IV
|
||||
```
|
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/bitrate-switching-1.png
generated
vendored
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/bitrate-switching-2.png
generated
vendored
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/bitrate-switching-3.png
generated
vendored
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/bitrate-switching-4.png
generated
vendored
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/containers.png
generated
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/dash-playlist-loader-mpc-mg-sequence.plantuml.png
generated
vendored
Normal file
After Width: | Height: | Size: 169 KiB |
12
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/dash-playlist-loader-states.nomnoml.svg
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svg width="228" height="310" version="1.1" baseProfile="full" viewbox="0 0 228 310" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" style="font-weight:bold; font-size:10pt; font-family:'Arial', Helvetica, sans-serif;;stroke-width:2;stroke-linejoin:round;stroke-linecap:round"><text x="134" y="111" style="font-weight:normal;">load()</text>
|
||||
<path d="M114 81 L114 105 L114 129 L114 129 " style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
|
||||
<path d="M110.8 121 L114 125 L117.2 121 L114 129 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<text x="134" y="211" style="font-weight:normal;">media()</text>
|
||||
<path d="M114 181 L114 205 L114 229 L114 229 " style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
|
||||
<path d="M110.8 221 L114 225 L117.2 221 L114 229 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<rect x="37" y="30" height="50" width="154" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="57" y="60" style="">HAVE_NOTHING</text>
|
||||
<rect x="40" y="130" height="50" width="149" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="60" y="160" style="">HAVE_MASTER</text>
|
||||
<rect x="30" y="230" height="50" width="168" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="50" y="260" style="">HAVE_METADATA</text></svg>
|
After Width: | Height: | Size: 1.4 KiB |
125
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/h264-nal.svg
generated
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="New document 1">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.74898074"
|
||||
inkscape:cx="405.31989"
|
||||
inkscape:cy="721.1724"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1165"
|
||||
inkscape:window-height="652"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g3832">
|
||||
<g
|
||||
transform="translate(-80,0)"
|
||||
id="g3796">
|
||||
<rect
|
||||
style="fill:none;stroke:#000000;stroke-width:4.99253178;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3756"
|
||||
width="195.00757"
|
||||
height="75.007133"
|
||||
x="57.496265"
|
||||
y="302.08554" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:39.94025421px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="80.563461"
|
||||
y="353.93951"
|
||||
id="text3758"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="scale(0.99841144,1.0015911)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3760"
|
||||
x="80.563461"
|
||||
y="353.93951">Header</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-80,0)"
|
||||
id="g3801">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="278.44489"
|
||||
y="354.50266"
|
||||
id="text3762"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3764"
|
||||
x="278.44489"
|
||||
y="354.50266">Raw Bitstream Payload (RBSP)</tspan></text>
|
||||
<rect
|
||||
style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3768"
|
||||
width="660.63977"
|
||||
height="75"
|
||||
x="252.5"
|
||||
y="302.09293" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="10.078175"
|
||||
y="432.12851"
|
||||
id="text3806"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3808"
|
||||
x="10.078175"
|
||||
y="432.12851">1 byte</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="-31.193787"
|
||||
y="252.32137"
|
||||
id="text3810"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3812"
|
||||
x="-31.193787"
|
||||
y="252.32137">H264 Network Abstraction Layer (NAL) Unit</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/hls-format.png
generated
vendored
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/mp2t-packet-types.png
generated
vendored
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/mp2t-structure.png
generated
vendored
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/playlist-loader-mpc-mg-sequence.plantuml.png
generated
vendored
Normal file
After Width: | Height: | Size: 162 KiB |
26
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/playlist-loader-states.nomnoml.svg
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<svg width="304" height="610" version="1.1" baseProfile="full" viewbox="0 0 304 610" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" style="font-weight:bold; font-size:10pt; font-family:'Arial', Helvetica, sans-serif;;stroke-width:2;stroke-linejoin:round;stroke-linecap:round"><text x="172" y="111" style="font-weight:normal;">load()</text>
|
||||
<path d="M152 81 L152 105 L152 129 L152 129 " style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
|
||||
<path d="M148.8 121 L152 125 L155.2 121 L152 129 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<text x="172" y="211" style="font-weight:normal;">media()</text>
|
||||
<path d="M152 181 L152 205 L152 229 L152 229 " style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
|
||||
<path d="M148.8 221 L152 225 L155.2 221 L152 229 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<text x="172" y="311" style="font-weight:normal;">media()/ start()</text>
|
||||
<path d="M152 281 L152 305 L152 329 L152 329 " style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
|
||||
<path d="M148.8 321 L152 325 L155.2 321 L152 329 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<path d="M152 381 L152 405 L152 429 L152 429 " style="stroke:#33322E;fill:none;stroke-dasharray:4 4;"></path>
|
||||
<path d="M148.8 421 L152 425 L155.2 421 L152 429 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<path d="M155.2 389 L152 385 L148.8 389 L152 381 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<path d="M152 481 L152 505 L152 529 L152 529 " style="stroke:#33322E;fill:none;stroke-dasharray:4 4;"></path>
|
||||
<path d="M148.8 521 L152 525 L155.2 521 L152 529 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<path d="M155.2 489 L152 485 L148.8 489 L152 481 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
|
||||
<rect x="75" y="30" height="50" width="154" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="95" y="60" style="">HAVE_NOTHING</text>
|
||||
<rect x="78" y="130" height="50" width="149" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="98" y="160" style="">HAVE_MASTER</text>
|
||||
<rect x="56" y="230" height="50" width="192" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="76.3" y="260" style="">SWITCHING_MEDIA</text>
|
||||
<rect x="68" y="330" height="50" width="168" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="88" y="360" style="">HAVE_METADATA</text>
|
||||
<text x="67" y="460" style="font-weight:normal;font-style:italic;">mediaupdatetimeout</text>
|
||||
<rect x="30" y="530" height="50" width="244" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
|
||||
<text x="50" y="560" style="">HAVE_CURRENT_METADATA</text></svg>
|
After Width: | Height: | Size: 2.8 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/segment-loader-states.png
generated
vendored
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/bitrate-switching-1.graffle
generated
vendored
Normal file
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/bitrate-switching-2.graffle
generated
vendored
Normal file
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/bitrate-switching-3.graffle
generated
vendored
Normal file
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/bitrate-switching-4.graffle
generated
vendored
Normal file
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/containers.graffle
generated
vendored
Normal file
119
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/dash-playlist-loader-mpc-mg-sequence.plantuml
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
@startuml
|
||||
|
||||
header DashPlaylistLoader sequences
|
||||
title DashPlaylistLoader sequences: Master Manifest with Alternate Audio
|
||||
|
||||
Participant "MasterPlaylistController" as MPC #red
|
||||
Participant "MasterDashPlaylistLoader" as MPL #blue
|
||||
Participant "mainSegmentLoader" as SL #blue
|
||||
Participant "AudioDashPlaylistLoader" as APL #green
|
||||
Participant "audioSegmentLoader" as ASL #green
|
||||
Participant "external server" as ext #brown
|
||||
Participant "mpdParser" as parser #orange
|
||||
Participant "mediaGroups" as MG #purple
|
||||
Participant Tech #lightblue
|
||||
|
||||
== Initialization ==
|
||||
|
||||
MPC -> MPL : construct MasterPlaylistLoader
|
||||
MPC -> MPL: load()
|
||||
|
||||
== Requesting Master Manifest ==
|
||||
|
||||
MPL -> MPL : start()
|
||||
|
||||
MPL -> ext: xhr request for master manifest
|
||||
ext -> MPL : response with master manifest
|
||||
|
||||
MPL -> parser: parse manifest
|
||||
parser -> MPL: object representing manifest
|
||||
|
||||
note over MPL #lightblue: trigger 'loadedplaylist'
|
||||
|
||||
== Requesting Video Manifest ==
|
||||
|
||||
note over MPL #lightblue: handling loadedplaylist
|
||||
MPL -> MPL: media(x)
|
||||
|
||||
alt if no sidx
|
||||
note over MPL #lightgray: zero delay to fake network request
|
||||
else if sidx
|
||||
break
|
||||
MPL -> ext: request sidx
|
||||
end
|
||||
end
|
||||
|
||||
note over MPL #lightblue: trigger 'loadedmetadata' on master loader [T1]
|
||||
|
||||
note over MPL #lightblue: handling 'loadedmetadata'
|
||||
|
||||
opt vod and preload !== 'none'
|
||||
|
||||
MPL -> SL: playlist()
|
||||
MPL -> SL: load()
|
||||
|
||||
end
|
||||
|
||||
== Initializing Media Groups, Choosing Active Tracks ==
|
||||
|
||||
MPL -> MG: setupMediaGroups()
|
||||
MG -> MG: initialize()
|
||||
|
||||
== Initializing Alternate Audio Loader ==
|
||||
|
||||
MG -> APL: create child playlist loader for alt audio
|
||||
|
||||
MG -> MG: activeGroup and audio variant selected
|
||||
MG -> MG: enable activeTrack, onTrackChanged()
|
||||
MG -> ASL: reset audio segment loader
|
||||
|
||||
== Requesting Alternate Audio Manifest ==
|
||||
|
||||
MG -> MG: startLoaders()
|
||||
|
||||
MG -> APL: load()
|
||||
APL -> APL: start()
|
||||
APL -> APL: zero delay to fake network request
|
||||
|
||||
break finish pending tasks
|
||||
MG -> Tech: add audioTrack
|
||||
MPL -> MPC: setupSourceBuffers_()
|
||||
MPL -> MPC: setupFirstPlay()
|
||||
|
||||
loop mainSegmentLoader.monitorBufferTick_()
|
||||
SL -> ext: requests media segments
|
||||
ext -> SL: response with media segment bytes
|
||||
end
|
||||
end
|
||||
|
||||
APL -> APL: zero delay over
|
||||
APL -> APL: media(x)
|
||||
|
||||
alt if no sidx
|
||||
note over APL #lightgray: zero delay to fake network request
|
||||
else if sidx
|
||||
break
|
||||
MPL -> ext: request sidx
|
||||
end
|
||||
end
|
||||
|
||||
== Requesting Alternate Audio Segments ==
|
||||
|
||||
note over APL #lightblue: trigger 'loadedplaylist'
|
||||
note over APL #lightblue: handling 'loadedplaylist'
|
||||
APL -> ASL: playlist()
|
||||
|
||||
|
||||
note over ASL #lightblue: trigger 'loadedmetadata' [T2]
|
||||
note over APL #lightblue: handling 'loadedmetadata'
|
||||
APL -> ASL: playlist()
|
||||
APL -> ASL: load()
|
||||
|
||||
loop audioSegmentLoader.monitorBufferTick_()
|
||||
|
||||
ASL -> ext: requests media segments
|
||||
ext -> ASL: response with media segment bytes
|
||||
|
||||
end
|
||||
|
||||
@enduml
|
21
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/dash-playlist-loader-states.nomnoml.txt
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
#title: DASH Playlist Loader States
|
||||
#arrowSize: 0.5
|
||||
#bendSize: 1
|
||||
#direction: down
|
||||
#gutter: 10
|
||||
#edgeMargin: 1
|
||||
#edges: rounded
|
||||
#fillArrows: false
|
||||
#font: Arial
|
||||
#fontSize: 10
|
||||
#leading: 1
|
||||
#lineWidth: 2
|
||||
#padding: 20
|
||||
#spacing: 50
|
||||
#stroke: #33322E
|
||||
#zoom: 1
|
||||
|
||||
#.label: align=center visual=none italic
|
||||
|
||||
[HAVE_NOTHING] load()-> [HAVE_MASTER]
|
||||
[HAVE_MASTER] media()-> [HAVE_METADATA]
|
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/hls-format.graffle
generated
vendored
Normal file
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/mp2t-packet-types.graffle
generated
vendored
Normal file
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/mp2t-structure.graffle
generated
vendored
Normal file
|
@ -0,0 +1,246 @@
|
|||
@startuml
|
||||
|
||||
header PlaylistLoader sequences
|
||||
title PlaylistLoader sequences: Master Manifest and Alternate Audio
|
||||
|
||||
Participant "MasterPlaylistController" as MPC #red
|
||||
Participant "MasterPlaylistLoader" as MPL #blue
|
||||
Participant "mainSegmentLoader" as SL #blue
|
||||
Participant "AudioPlaylistLoader" as APL #green
|
||||
Participant "audioSegmentLoader" as ASL #green
|
||||
Participant "external server" as ext #brown
|
||||
Participant "m3u8Parser" as parser #orange
|
||||
Participant "mediaGroups" as MG #purple
|
||||
Participant Tech #lightblue
|
||||
|
||||
== Initialization ==
|
||||
|
||||
group MasterPlaylistController.constructor()
|
||||
|
||||
MPC -> MPL : setting up MasterPlaylistLoader
|
||||
note left #lightyellow
|
||||
sets up mediaupdatetimeout
|
||||
handler for live playlist staleness
|
||||
end note
|
||||
note over MPL #lightgray: state = 'HAVE_NOTHING'
|
||||
|
||||
MPC -> MPL: load()
|
||||
|
||||
end
|
||||
|
||||
group MasterPlaylistLoader.load()
|
||||
|
||||
MPL -> MPL : start()
|
||||
note left #lightyellow: not started yet
|
||||
|
||||
== Requesting Master Manifest ==
|
||||
|
||||
group start()
|
||||
|
||||
note over MPL #lightgray: started = true
|
||||
|
||||
MPL -> ext: xhr request for master manifest
|
||||
ext -> MPL : response with master manifest
|
||||
|
||||
MPL -> parser: parse master manifest
|
||||
parser -> MPL: object representing manifest
|
||||
MPL -> MPL: set loader's master playlist
|
||||
note over MPL #lightgray: state = 'HAVE_MASTER'
|
||||
note over MPL #lightblue: trigger 'loadedplaylist' on master loader
|
||||
|
||||
== Requesting Video Manifest ==
|
||||
|
||||
group 'loadedplaylist' handler
|
||||
|
||||
note over MPL #lightblue: handling loadedplaylist
|
||||
MPL -> MPL : media()
|
||||
note left #lightgray: select initial (video) playlist
|
||||
note over MPL #lightyellow: state = 'SWITCHING_MEDIA'
|
||||
|
||||
group media()
|
||||
|
||||
MPL -> ext : request child manifest
|
||||
ext -> MPL: child manifest returned
|
||||
MPL -> MPL: haveMetadata()
|
||||
note over MPL #lightyellow: state = 'HAVE_METADATA'
|
||||
|
||||
group haveMetadata()
|
||||
|
||||
MPL -> parser: parse child manifest
|
||||
parser -> MPL: object representing the child manifest
|
||||
note over MPL #lightyellow
|
||||
update master and media playlists
|
||||
end note
|
||||
|
||||
opt live
|
||||
MPL -> MPL: setup mediaupdatetimeout
|
||||
end
|
||||
|
||||
note over MPL #lightblue
|
||||
trigger 'loadedplaylist' on master loader.
|
||||
This does not end up requesting segments
|
||||
at this point.
|
||||
end note
|
||||
|
||||
group MasterPlaylistLoader 'loadedplaylist' handler
|
||||
|
||||
MPL -> MPL : setup durationchange handler
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
== Requesting Video Segments ==
|
||||
|
||||
note over MPL #lightblue: trigger 'loadedmetadata'
|
||||
|
||||
group 'loadedmetadata' handler
|
||||
|
||||
note over MPL #lightblue: handling 'loadedmetadata'
|
||||
|
||||
opt vod and preload !== 'none'
|
||||
|
||||
MPL -> SL: playlist()
|
||||
note over SL #lightyellow: updates playlist
|
||||
|
||||
MPL -> SL: load()
|
||||
note right #lightgray
|
||||
This does nothing as mimeTypes
|
||||
have not been set yet.
|
||||
end note
|
||||
|
||||
end
|
||||
|
||||
MPL -> MG: setupMediaGroups()
|
||||
|
||||
== Initializing Media Groups, Choosing Active Tracks ==
|
||||
|
||||
group MediaGroups.setupMediaGroups()
|
||||
|
||||
group initialize()
|
||||
|
||||
MG -> APL: create child playlist loader for alt audio
|
||||
note over APL #lightyellow: state = 'HAVE_NOTHING'
|
||||
|
||||
note left #lightgray
|
||||
setup 'loadedmetadata' and 'loadedplaylist' listeners
|
||||
on child alt audio playlist loader
|
||||
end note
|
||||
|
||||
MG -> Tech: add audioTracks
|
||||
|
||||
end
|
||||
|
||||
MG -> MG: activeGroup and audio variant selected
|
||||
MG -> MG: enable activeTrack, onTrackChanged()
|
||||
note left #lightgray
|
||||
There is no activePlaylistLoader at this point,
|
||||
but there is an audio playlistLoader
|
||||
end note
|
||||
|
||||
group onTrackChanged()
|
||||
|
||||
MG -> SL: reset mainSegmentLoader
|
||||
note left #lightgray: Clears buffer, aborts all inflight requests
|
||||
|
||||
== Requesting Alternate Audio Manifest ==
|
||||
|
||||
MG -> MG: startLoaders()
|
||||
|
||||
group startLoaders()
|
||||
note over MG #lightyellow
|
||||
activePlaylistLoader = AudioPlaylistLoader
|
||||
end note
|
||||
|
||||
MG -> APL: load()
|
||||
end
|
||||
|
||||
group AudioPlaylistLoader.load()
|
||||
APL -> APL: start()
|
||||
|
||||
group alt start()
|
||||
|
||||
note over APL #lightyellow: started = true
|
||||
APL -> ext: request alt audio media manifest
|
||||
|
||||
break MasterPlaylistLoader 'loadedmetadata' handler
|
||||
|
||||
MPL -> MPC: setupSourceBuffers()
|
||||
note left #lightgray
|
||||
This will set mimeType.
|
||||
Segments can be loaded from now on.
|
||||
end note
|
||||
|
||||
MPL -> MPC: setupFirstPlay()
|
||||
note left #lightgray
|
||||
Immediate exit since the player
|
||||
is paused
|
||||
end note
|
||||
|
||||
end
|
||||
|
||||
ext -> APL: responds with child manifest
|
||||
APL -> parser: parse child manifest
|
||||
parser -> APL: object representing child manifest returned
|
||||
note over APL #lightyellow: state = 'HAVE_MASTER'
|
||||
note left #lightgray: Infer a master playlist
|
||||
|
||||
APL -> APL: haveMetadata()
|
||||
note over APL #lightyellow: state = 'HAVE_METADATA'
|
||||
|
||||
group haveMetadata()
|
||||
|
||||
APL -> parser: parsing the child manifest again
|
||||
parser -> APL: returning object representing child manifest
|
||||
note over APL #lightyellow
|
||||
update master and media references
|
||||
end note
|
||||
|
||||
== Requesting Alternate Audio Segments ==
|
||||
|
||||
note over APL #lightblue: trigger 'loadedplaylist'
|
||||
|
||||
group 'loadedplaylist' handler
|
||||
|
||||
note over APL #lightblue: handling 'loadedplaylist'
|
||||
APL -> ASL: playlist()
|
||||
note over ASL #lightyellow: set playlist
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
note over APL #lightblue: trigger 'loadedmetadata'
|
||||
|
||||
group 'loadedmetadata' handler
|
||||
|
||||
note over APL #lightblue: handling 'loadedmetadata'
|
||||
|
||||
APL -> ASL: playlist()
|
||||
APL -> ASL: load()
|
||||
|
||||
loop audioSegmentLoader.load()
|
||||
|
||||
ASL -> ext: requests media segments
|
||||
ext -> ASL: response with media segment bytes
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@enduml
|
114
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/playlist-loader-mpc-mg-sequence.plantuml
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
@startuml
|
||||
|
||||
header PlaylistLoader sequences
|
||||
title PlaylistLoader sequences: Master Manifest and Alternate Audio
|
||||
|
||||
Participant "MasterPlaylistController" as MPC #red
|
||||
Participant "MasterPlaylistLoader" as MPL #blue
|
||||
Participant "mainSegmentLoader" as SL #blue
|
||||
Participant "AudioPlaylistLoader" as APL #green
|
||||
Participant "audioSegmentLoader" as ASL #green
|
||||
Participant "external server" as ext #brown
|
||||
Participant "m3u8Parser" as parser #orange
|
||||
Participant "mediaGroups" as MG #purple
|
||||
Participant Tech #lightblue
|
||||
|
||||
== Initialization ==
|
||||
|
||||
MPC -> MPL : construct MasterPlaylistLoader
|
||||
MPC -> MPL: load()
|
||||
|
||||
MPL -> MPL : start()
|
||||
|
||||
== Requesting Master Manifest ==
|
||||
|
||||
MPL -> ext: xhr request for master manifest
|
||||
ext -> MPL : response with master manifest
|
||||
|
||||
MPL -> parser: parse master manifest
|
||||
parser -> MPL: object representing manifest
|
||||
|
||||
note over MPL #lightblue: trigger 'loadedplaylist'
|
||||
|
||||
== Requesting Video Manifest ==
|
||||
|
||||
note over MPL #lightblue: handling loadedplaylist
|
||||
MPL -> MPL : media()
|
||||
|
||||
MPL -> ext : request child manifest
|
||||
ext -> MPL: child manifest returned
|
||||
|
||||
MPL -> parser: parse child manifest
|
||||
parser -> MPL: object representing the child manifest
|
||||
|
||||
note over MPL #lightblue: trigger 'loadedplaylist'
|
||||
note over MPL #lightblue: handleing 'loadedplaylist'
|
||||
|
||||
MPL -> SL: playlist()
|
||||
MPL -> SL: load()
|
||||
|
||||
== Requesting Video Segments ==
|
||||
|
||||
note over MPL #lightblue: trigger 'loadedmetadata'
|
||||
note over MPL #lightblue: handling 'loadedmetadata'
|
||||
|
||||
opt vod and preload !== 'none'
|
||||
|
||||
MPL -> SL: playlist()
|
||||
MPL -> SL: load()
|
||||
|
||||
end
|
||||
|
||||
MPL -> MG: setupMediaGroups()
|
||||
|
||||
== Initializing Media Groups, Choosing Active Tracks ==
|
||||
|
||||
MG -> APL: create child playlist loader for alt audio
|
||||
|
||||
MG -> MG: activeGroup and audio variant selected
|
||||
MG -> MG: enable activeTrack, onTrackChanged()
|
||||
MG -> SL: reset mainSegmentLoader
|
||||
|
||||
== Requesting Alternate Audio Manifest ==
|
||||
|
||||
MG -> MG: startLoaders()
|
||||
|
||||
MG -> APL: load()
|
||||
APL -> APL: start()
|
||||
|
||||
APL -> ext: request alt audio media manifest
|
||||
|
||||
break finish pending tasks
|
||||
MG -> Tech: add audioTracks
|
||||
MPL -> MPC: setupSourceBuffers()
|
||||
MPL -> MPC: setupFirstPlay()
|
||||
|
||||
loop on monitorBufferTick
|
||||
SL -> ext: requests media segments
|
||||
ext -> SL: response with media segment bytes
|
||||
end
|
||||
end
|
||||
|
||||
ext -> APL: responds with child manifest
|
||||
|
||||
APL -> parser: parse child manifest
|
||||
parser -> APL: object representing child manifest returned
|
||||
|
||||
== Requesting Alternate Audio Segments ==
|
||||
|
||||
note over APL #lightblue: trigger 'loadedplaylist'
|
||||
note over APL #lightblue: handling 'loadedplaylist'
|
||||
APL -> ASL: playlist()
|
||||
|
||||
note over APL #lightblue: trigger 'loadedmetadata'
|
||||
note over APL #lightblue: handling 'loadedmetadata'
|
||||
APL -> ASL: playlist()
|
||||
APL -> ASL: load()
|
||||
|
||||
loop audioSegmentLoader.load()
|
||||
|
||||
ASL -> ext: requests media segments
|
||||
ext -> ASL: response with media segment bytes
|
||||
end
|
||||
|
||||
@enduml
|
25
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/images/sources/playlist-loader-states.nomnoml.txt
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
#title: Playlist Loader States
|
||||
#arrowSize: 0.5
|
||||
#bendSize: 1
|
||||
#direction: down
|
||||
#gutter: 10
|
||||
#edgeMargin: 1
|
||||
#edges: rounded
|
||||
#fillArrows: false
|
||||
#font: Arial
|
||||
#fontSize: 10
|
||||
#leading: 1
|
||||
#lineWidth: 2
|
||||
#padding: 20
|
||||
#spacing: 50
|
||||
#stroke: #33322E
|
||||
#zoom: 1
|
||||
|
||||
#.label: align=center visual=none italic
|
||||
|
||||
[HAVE_NOTHING] load()-> [HAVE_MASTER]
|
||||
[HAVE_MASTER] media()-> [SWITCHING_MEDIA]
|
||||
[SWITCHING_MEDIA] media()/ start()-> [HAVE_METADATA]
|
||||
|
||||
[HAVE_METADATA] <--> [<label> mediaupdatetimeout]
|
||||
[<label> mediaupdatetimeout] <--> [HAVE_CURRENT_METADATA]
|
13
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/current-flow.plantuml
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
@startuml
|
||||
|
||||
state "Download Segment" as DL
|
||||
state "Prepare for Append" as PfA
|
||||
|
||||
[*] -> DL
|
||||
DL -> PfA
|
||||
PfA : transmux (if needed)
|
||||
PfA -> Append
|
||||
Append : MSE source buffer
|
||||
Append -> [*]
|
||||
|
||||
@enduml
|
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/current-flow.plantuml.png
generated
vendored
Normal file
After Width: | Height: | Size: 9.1 KiB |
57
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/current-transmux-and-append-flow.plantuml
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
@startuml
|
||||
|
||||
participant SegmentLoader order 1
|
||||
participant "media-segment-request" order 2
|
||||
participant "videojs-contrib-media-sources" order 3
|
||||
participant mux.js order 4
|
||||
participant "Native Source Buffer" order 5
|
||||
|
||||
SegmentLoader -> "media-segment-request" : mediaSegmentRequest(...)
|
||||
|
||||
group Request
|
||||
"media-segment-request" -> SegmentLoader : doneFn(...)
|
||||
note left
|
||||
At end of all requests
|
||||
(key/segment/init segment)
|
||||
end note
|
||||
SegmentLoader -> SegmentLoader : handleSegment(...)
|
||||
note left
|
||||
"Probe" (parse) segment for
|
||||
timing and track information
|
||||
end note
|
||||
SegmentLoader -> "videojs-contrib-media-sources" : append to "fake" source buffer
|
||||
note left
|
||||
Source buffer here is a
|
||||
wrapper around native buffers
|
||||
end note
|
||||
group Transmux
|
||||
"videojs-contrib-media-sources" -> mux.js : postMessage(...setAudioAppendStart...)
|
||||
note left
|
||||
Used for checking for overlap when
|
||||
prefixing audio with silence.
|
||||
end note
|
||||
"videojs-contrib-media-sources" -> mux.js : postMessage(...alignGopsWith...)
|
||||
note left
|
||||
Used for aligning gops when overlapping
|
||||
content (switching renditions) to fix
|
||||
some browser glitching.
|
||||
end note
|
||||
|
||||
"videojs-contrib-media-sources" -> mux.js : postMessage(...push...)
|
||||
note left
|
||||
Pushes bytes into the transmuxer pipeline.
|
||||
end note
|
||||
"videojs-contrib-media-sources" -> mux.js : postMessage(...flush...)
|
||||
"mux.js" -> "videojs-contrib-media-sources" : postMessage(...data...)
|
||||
"videojs-contrib-media-sources" -> "Native Source Buffer" : append
|
||||
"Native Source Buffer" -> "videojs-contrib-media-sources" : //updateend//
|
||||
"videojs-contrib-media-sources" -> SegmentLoader : handleUpdateEnd(...)
|
||||
end
|
||||
end
|
||||
SegmentLoader -> SegmentLoader : handleUpdateEnd_()
|
||||
note left
|
||||
Saves segment timing info
|
||||
and starts next request.
|
||||
end note
|
||||
|
||||
@enduml
|
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/current-transmux-and-append-flow.plantuml.png
generated
vendored
Normal file
After Width: | Height: | Size: 65 KiB |
29
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/expected-flow.plantuml
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
@startuml
|
||||
|
||||
state "Request Segment" as RS
|
||||
state "Partial Response (1)" as PR1
|
||||
state "..." as DDD
|
||||
state "Partial Response (n)" as PRN
|
||||
state "Prepare for Append (1)" as PfA1
|
||||
state "Prepare for Append (n)" as PfAN
|
||||
state "Append (1)" as A1
|
||||
state "Append (n)" as AN
|
||||
|
||||
[*] -> RS
|
||||
|
||||
RS --> PR1
|
||||
PR1 --> DDD
|
||||
DDD --> PRN
|
||||
|
||||
PR1 -> PfA1
|
||||
PfA1 : transmux (if needed)
|
||||
PfA1 -> A1
|
||||
A1 : MSE source buffer
|
||||
PRN -> PfAN
|
||||
PfAN : transmux (if needed)
|
||||
PfAN -> AN
|
||||
AN : MSE source buffer
|
||||
|
||||
AN --> [*]
|
||||
|
||||
@enduml
|
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/expected-flow.plantuml.png
generated
vendored
Normal file
After Width: | Height: | Size: 22 KiB |
109
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/index.md
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
# LHLS
|
||||
|
||||
### Table of Contents
|
||||
|
||||
* [Background](#background)
|
||||
* [Current Support for LHLS in VHS](#current-support-for-lhls-in-vhs)
|
||||
* [Request a Segment in Pieces](#request-a-segment-in-pieces)
|
||||
* [Transmux and Append Segment Pieces](#transmux-and-append-segment-pieces)
|
||||
* [videojs-contrib-media-sources background](#videojs-contrib-media-sources-background)
|
||||
* [Transmux Before Append](#transmux-before-append)
|
||||
* [Transmux Within media-segment-request](#transmux-within-media-segment-request)
|
||||
* [mux.js](#muxjs)
|
||||
* [The New Flow](#the-new-flow)
|
||||
* [Resources](#resources)
|
||||
|
||||
### Background
|
||||
|
||||
LHLS stands for Low-Latency HLS (see [Periscope's post](https://medium.com/@periscopecode/introducing-lhls-media-streaming-eb6212948bef)). It's meant to be used for ultra low latency live streaming, where a server can send pieces of a segment before the segment is done being written to, and the player can append those pieces to the browser, allowing sub segment duration latency from true live.
|
||||
|
||||
In order to support LHLS, a few components are required:
|
||||
|
||||
* A server that supports [chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding).
|
||||
* A client that can:
|
||||
* request segment pieces
|
||||
* transmux segment pieces (for browsers that don't natively support the media type)
|
||||
* append segment pieces
|
||||
|
||||
### Current Support for LHLS in VHS
|
||||
|
||||
At the moment, VHS doesn't support any of the client requirements. It waits until a request is completed and the transmuxer expects full segments.
|
||||
|
||||
Current flow:
|
||||
|
||||

|
||||
|
||||
Expected flow:
|
||||
|
||||

|
||||
|
||||
### Request Segment Pieces
|
||||
|
||||
The first change was to request pieces of a segment. There are a few approaches to accomplish this:
|
||||
|
||||
* [Range Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests)
|
||||
* requires server support
|
||||
* more round trips
|
||||
* [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
||||
* limited browser support
|
||||
* doesn't support aborts
|
||||
* [Plain text MIME type](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data)
|
||||
* slightly non-standard
|
||||
* incurs a cost of converting from string to bytes
|
||||
|
||||
*Plain text MIME type* was chosen because of its wide support. It provides a mechanism to access progressive bytes downloaded on [XMLHttpRequest progress events](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequestEventTarget/onprogress).
|
||||
|
||||
This change was made in [media-segment-request](https://github.com/videojs/http-streaming/blob/master/src/media-segment-request.js).
|
||||
|
||||
### Transmux and Append Segment Pieces
|
||||
|
||||
Getting the progress bytes is easy. Supporting partial transmuxing and appending is harder.
|
||||
|
||||
Current flow:
|
||||
|
||||

|
||||
|
||||
In order to support partial transmuxing and appending in the current flow, videojs-contrib-media-sources would have to get more complicated.
|
||||
|
||||
##### videojs-contrib-media-sources background
|
||||
|
||||
Browsers, via MSE source buffers, only support a limited set of media types. For most browsers, this means MP4/fragmented MP4. HLS uses TS segments (it also supports fragmented MP4, but that case is less common). This is why transmuxing is necessary.
|
||||
|
||||
Just like Video.js is a wrapper around the browser video element, bridging compatibility and adding support to extend features, videojs-contrib-media-sources provides support for more media types across different browsers by building in a transmuxer.
|
||||
|
||||
Not only did videojs-contrib-media-sources allow us to transmux TS to FMP4, but it also allowed us to transmux TS to FLV for flash support.
|
||||
|
||||
Over time, the complexity of logic grew in videojs-contrib-media-sources, and it coupled tightly with videojs-contrib-hls and videojs-http-streaming, firing events to communicate between the two.
|
||||
|
||||
Once flash support was moved to a distinct flash module, [via flashls](https://github.com/brightcove/videojs-flashls-source-handler), it was decided to move the videojs-contrib-media-sources logic into VHS, and to remove coupled logic by using only the native source buffers (instead of the wrapper) and transmuxing somewhere within VHS before appending.
|
||||
|
||||
##### Transmux Before Append
|
||||
|
||||
As the LHLS work started, and videojs-contrib-media-sources needed more logic, the native media source [abstraction leaked](https://en.wikipedia.org/wiki/Leaky_abstraction), adding non-standard functions to work around limitations. In addition, the logic in videojs-contrib-media-sources required more conditional paths, leading to more confusing code.
|
||||
|
||||
It was decided that it would be easier to do the transmux before append work in the process of adding support for LHLS. This was widely considered a *good decision*, and provided a means of reducing tech debt while adding in a new feature.
|
||||
|
||||
##### Transmux Within media-segment-request
|
||||
|
||||
Work started by moving transmuxing into segment-loader, however, we quickly realized that media-segment-request provided a better home.
|
||||
|
||||
media-segment-request already handled decrypting segments. If it handled transmuxing as well, then segment-loader could stick with only deciding which segment to request, getting bytes as FMP4, and appending them.
|
||||
|
||||
The transmuxing logic moved to a new module called segment-transmuxer, which wrapped around the [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker) that wrapped around mux.js (the transmuxer itself).
|
||||
|
||||
##### mux.js
|
||||
|
||||
While most of the [mux.js pipeline](https://github.com/videojs/mux.js/blob/master/docs/diagram.png) supports pushing pieces of data (and should support LHLS by default), its "flushes" to send transmuxed data back to the caller expected full segments.
|
||||
|
||||
Much of the pipeline was reused, however, the top level audio and video segment streams, as well as the entry point, were rewritten so that instead of providing a full segment on flushes, each frame of video was provided individually (audio frames still flush as a group). The new concept of partial flushes was added into the pipeline to handle this case.
|
||||
|
||||
##### The New Flow
|
||||
|
||||
One benefit to transmuxing before appending is the possibility of extracting track and timing information from the segments. Previously, this required a separate parsing step to happen on the full segment. Now, it is included in the transmuxing pipeline, and comes back to us on separate callbacks.
|
||||
|
||||

|
||||
|
||||
### Resources
|
||||
|
||||
* https://medium.com/@periscopecode/introducing-lhls-media-streaming-eb6212948bef
|
||||
* https://github.com/jordicenzano/webserver-chunked-growingfiles
|
118
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/new-segment-loader-sequence.plantuml
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
@startuml
|
||||
|
||||
participant SegmentLoader order 1
|
||||
participant "media-segment-request" order 2
|
||||
participant XMLHttpRequest order 3
|
||||
participant "segment-transmuxer" order 4
|
||||
participant mux.js order 5
|
||||
|
||||
SegmentLoader -> "media-segment-request" : mediaSegmentRequest(...)
|
||||
"media-segment-request" -> XMLHttpRequest : request for segment/key/init segment
|
||||
|
||||
group Request
|
||||
XMLHttpRequest -> "media-segment-request" : //segment progress//
|
||||
note over "media-segment-request" #moccasin
|
||||
If handling partial data,
|
||||
tries to transmux new
|
||||
segment bytes.
|
||||
end note
|
||||
"media-segment-request" -> SegmentLoader : progressFn(...)
|
||||
note left
|
||||
Forwards "progress" events from
|
||||
the XML HTTP Request.
|
||||
end note
|
||||
group Transmux
|
||||
"media-segment-request" -> "segment-transmuxer" : transmux(...)
|
||||
|
||||
"segment-transmuxer" -> mux.js : postMessage(...setAudioAppendStart...)
|
||||
note left
|
||||
Used for checking for overlap when
|
||||
prefixing audio with silence.
|
||||
end note
|
||||
"segment-transmuxer" -> mux.js : postMessage(...alignGopsWith...)
|
||||
note left
|
||||
Used for aligning gops when overlapping
|
||||
content (switching renditions) to fix
|
||||
some browser glitching.
|
||||
end note
|
||||
|
||||
"segment-transmuxer" -> mux.js : postMessage(...push...)
|
||||
note left
|
||||
Pushes bytes into the transmuxer pipeline.
|
||||
end note
|
||||
|
||||
"segment-transmuxer" -> mux.js : postMessage(...partialFlush...)
|
||||
note left #moccasin
|
||||
Collates any complete frame data
|
||||
from partial segment and
|
||||
caches remainder.
|
||||
end note
|
||||
"segment-transmuxer" -> mux.js : postMessage(...flush...)
|
||||
note left
|
||||
Collates any complete frame data
|
||||
from segment, caches only data
|
||||
required between segments.
|
||||
end note
|
||||
|
||||
"mux.js" -> "segment-transmuxer" : postMessage(...trackinfo...)
|
||||
"segment-transmuxer" -> "media-segment-request" : onTrackInfo(...)
|
||||
"media-segment-request" -> SegmentLoader : trackInfoFn(...)
|
||||
note left
|
||||
Gets whether the segment
|
||||
has audio and/or video.
|
||||
end note
|
||||
"mux.js" -> "segment-transmuxer" : postMessage(...audioTimingInfo...)
|
||||
"segment-transmuxer" -> "media-segment-request" : onAudioTimingInfo(...)
|
||||
"mux.js" -> "segment-transmuxer" : postMessage(...videoTimingInfo...)
|
||||
"segment-transmuxer" -> "media-segment-request" : onVideoTimingInfo(...)
|
||||
"media-segment-request" -> SegmentLoader : timingInfoFn(...)
|
||||
note left
|
||||
Gets the audio/video
|
||||
start/end times.
|
||||
end note
|
||||
|
||||
"mux.js" -> "segment-transmuxer" : postMessage(...caption...)
|
||||
"segment-transmuxer" -> "media-segment-request" : onCaptions(...)
|
||||
"media-segment-request" -> SegmentLoader : captionsFn(...)
|
||||
note left
|
||||
Gets captions from transmux.
|
||||
end note
|
||||
|
||||
"mux.js" -> "segment-transmuxer" : postMessage(...id3Frame...)
|
||||
"segment-transmuxer" -> "media-segment-request" : onId3(...)
|
||||
"media-segment-request" -> SegmentLoader : id3Fn(...)
|
||||
note left
|
||||
Gets metadata from transmux.
|
||||
end note
|
||||
|
||||
"mux.js" -> "segment-transmuxer" : postMessage(...data...)
|
||||
"segment-transmuxer" -> "media-segment-request" : onData(...)
|
||||
"media-segment-request" -> SegmentLoader : dataFn(...)
|
||||
note left
|
||||
Gets an fmp4 segment
|
||||
ready to be appended.
|
||||
end note
|
||||
|
||||
"mux.js" -> "segment-transmuxer" : postMessage(...done...)
|
||||
note left
|
||||
Gathers GOP info, and calls
|
||||
done callback.
|
||||
end note
|
||||
"segment-transmuxer" -> "media-segment-request" : onDone(...)
|
||||
"media-segment-request" -> SegmentLoader : doneFn(...)
|
||||
note left
|
||||
Queues callbacks on source
|
||||
buffer queue to wait for
|
||||
appends to complete.
|
||||
end note
|
||||
end
|
||||
XMLHttpRequest -> "media-segment-request" : //segment request finished//
|
||||
end
|
||||
|
||||
SegmentLoader -> SegmentLoader : handleAppendsDone_()
|
||||
note left
|
||||
Saves segment timing info
|
||||
and starts next request.
|
||||
end note
|
||||
|
||||
@enduml
|
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/new-segment-loader-sequence.plantuml.png
generated
vendored
Normal file
After Width: | Height: | Size: 132 KiB |
36
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/lhls/transmux-before-append-changes.md
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Transmux Before Append Changes
|
||||
|
||||
## Overview
|
||||
|
||||
In moving our transmuxing stage from after append (to a virtual source buffer from videojs-contrib-media-sources) to before appending (to a native source buffer), some changes were required, and others made the logic simpler. What follows are some details into some of the changes made, why they were made, and what impact they will have.
|
||||
|
||||
### Source Buffer Creation
|
||||
|
||||
In a pre-TBA (transmux before append) world, videojs-contrib-media-source's source buffers provided an abstraction around the native source buffers. They also required a bit more information than the native buffers. For instance, they used the full mime types instead of simply relying on the codec information, when creating the source buffers. This provided the container types, which let the virtual source buffer know whether the media needed to be transmuxed or not. In a post-TBA world, the container type is no longer required, therefore only the codec strings are passed along.
|
||||
|
||||
In terms of when the source buffers are created, in the post-TBA world, the creation of source buffers is delayed until we are sure we have all of the information we need. This means that we don't create the native source buffers until the PMT is parsed from the main media. Even if the content is demuxed, we only need to parse the main media, since, for now, we don't rely on codec information from the segment itself, and instead use the manifest-provided codec info, or default codecs. While we could create the source buffers earlier if the codec information is provided in the manifest, delaying provides a simpler, single, code path, and more opportunity for us to be flexible with how much codec info is provided by the attribute. While the HLS specification requires this information, other formats may not, and we have seen content that plays fine but does not adhere to the strict rules of providing all necessary codec information.
|
||||
|
||||
### Appending Init Segments
|
||||
|
||||
Previously, init segments were handled by videojs-contrib-media-sources for TS segments and segment-loader for FMP4 segments.
|
||||
|
||||
videojs-contrib-media-sources and TS:
|
||||
* video segments
|
||||
* append the video init segment returned from the transmuxer with every segment
|
||||
* audio segments
|
||||
* append the audio init segment returned from the transmuxer only in the following cases:
|
||||
* first append
|
||||
* after timestampOffset is set
|
||||
* audio track events: change/addtrack/removetrack
|
||||
* 'mediachange' event
|
||||
|
||||
segment-loader and FMP4:
|
||||
* if segment.map is set:
|
||||
* save (cache) the init segment after the request finished
|
||||
* append the init segment directly to the source buffer if the segment loader's activeInitSegmentId doesn't match the segment.map generated init segment ID
|
||||
|
||||
With the transmux before append and LHLS changes, we only append video init segments on changes as well. This is more important with LHLS, as prepending an init segment before every frame of video would be wasteful.
|
||||
|
||||
### Test Changes
|
||||
|
||||
Some tests were removed because they were no longer relevant after the change to creating source buffers later. For instance, `waits for both main and audio loaders to finish before calling endOfStream if main loader starting media is unknown` no longer can be tested by waiting for an audio loader response and checking for end of stream, as the test will time out since MasterPlaylistController will wait for track info from the main loader before the source buffers are created. That condition is checked elsewhere.
|
29
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/media.md
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
This doc is just a stub right now. Check back later for updates.
|
||||
|
||||
# General
|
||||
When we talk about video, we normally think about it as one monolithic thing. If you ponder it for a moment though, you'll realize it's actually two distinct sorts of information that are presented to the viewer in tandem: a series of pictures and a sequence of audio samples. The temporal nature of audio and video is shared but the techniques used to efficiently transmit them are very different and necessitate a lot of the complexity in video file formats. Bundling up these (at least) two streams into a single package is the first of many issues introduced by the need to serialize video data and is solved by meta-formats called _containers_.
|
||||
|
||||
Containers formats are probably the most recongnizable of the video components because they get the honor of determining the file extension. You've probably heard of MP4, MOV, and WMV, all of which are container formats. Containers specify how to serialize audio, video, and metadata streams into a sequential series of bits and how to unpack them for decoding. Containers are basically a box that can hold video information and timed media data:
|
||||
|
||||

|
||||
|
||||
- codecs
|
||||
- containers, multiplexing
|
||||
|
||||
# MPEG2-TS
|
||||

|
||||
|
||||

|
||||
|
||||
- streaming vs storage
|
||||
- program table
|
||||
- program map table
|
||||
- history, context
|
||||
|
||||
# H.264
|
||||
- NAL units
|
||||
- Annex B vs MP4 elementary stream
|
||||
- access unit -> sample
|
||||
|
||||
# MP4
|
||||
- origins: quicktime
|
75
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/mse.md
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
# Media Source Extensions Notes
|
||||
A collection of findings experimenting with Media Source Extensions on
|
||||
Chrome 36.
|
||||
|
||||
* Specifying an audio and video codec when creating a source buffer
|
||||
but passing in an initialization segment with only a video track
|
||||
results in a decode error
|
||||
|
||||
## ISO Base Media File Format (BMFF)
|
||||
|
||||
### Init Segment
|
||||
A working initialization segment is outlined below. It may be possible
|
||||
to trim this structure down further.
|
||||
|
||||
- `ftyp`
|
||||
- `moov`
|
||||
- `mvhd`
|
||||
- `trak`
|
||||
- `tkhd`
|
||||
- `mdia`
|
||||
- `mdhd`
|
||||
- `hdlr`
|
||||
- `minf`
|
||||
- `mvex`
|
||||
|
||||
### Media Segment
|
||||
The structure of a minimal media segment that actually encapsulates
|
||||
movie data is outlined below:
|
||||
|
||||
- `moof`
|
||||
- `mfhd`
|
||||
- `traf`
|
||||
- `tfhd`
|
||||
- `tfdt`
|
||||
- `trun` containing samples
|
||||
- `mdat`
|
||||
|
||||
### Structure
|
||||
|
||||
sample: time {number}, data {array}
|
||||
chunk: samples {array}
|
||||
track: samples {array}
|
||||
segment: moov {box}, mdats {array} | moof {box}, mdats {array}, data {array}
|
||||
|
||||
track
|
||||
chunk
|
||||
sample
|
||||
|
||||
movie fragment -> track fragment -> [samples]
|
||||
|
||||
### Sample Data Offsets
|
||||
Movie-fragment Relative Addressing: all trun data offsets are relative
|
||||
to the containing moof (?).
|
||||
|
||||
Without default-base-is-moof, the base data offset for each trun in
|
||||
trafs after the first is the *end* of the previous traf.
|
||||
|
||||
#### iso5/DASH Style
|
||||
moof
|
||||
|- traf (default-base-is-moof)
|
||||
| |- trun_0 <size of moof> + 0
|
||||
| `- trun_1 <size of moof> + 100
|
||||
`- traf (default-base-is-moof)
|
||||
`- trun_2 <size of moof> + 300
|
||||
mdat
|
||||
|- samples_for_trun_0 (100 bytes)
|
||||
|- samples_for_trun_1 (200 bytes)
|
||||
`- samples_for_trun_2
|
||||
|
||||
#### Single Track Style
|
||||
moof
|
||||
`- traf
|
||||
`- trun_0 <size of moof> + 0
|
||||
mdat
|
||||
`- samples_for_trun_0
|
96
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/multiple-alternative-audio-tracks.md
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
# Multiple Alternative Audio Tracks
|
||||
## General
|
||||
m3u8 manifests with multiple audio streams will have those streams added to `video.js` in an `AudioTrackList`. The `AudioTrackList` can be accessed using `player.audioTracks()` or `tech.audioTracks()`.
|
||||
|
||||
## Mapping m3u8 metadata to AudioTracks
|
||||
The mapping between `AudioTrack` and the parsed m3u8 file is fairly straight forward. The table below shows the mapping
|
||||
|
||||
| m3u8 | AudioTrack |
|
||||
|---------|------------|
|
||||
| label | label |
|
||||
| lang | language |
|
||||
| default | enabled |
|
||||
| ??? | kind |
|
||||
| ??? | id |
|
||||
|
||||
As you can see m3u8's do not have a property for `AudioTrack.id`, which means that we let `video.js` randomly generate the id for `AudioTrack`s. This will have no real impact on any part of the system as we do not use the `id` anywhere.
|
||||
|
||||
The other property that does not have a mapping in the m3u8 is `AudioTrack.kind`. It was decided that we would set the `kind` to `main` when `default` is set to `true` and in other cases we set it to `alternative` unless the track has `characteristics` which include `public.accessibility.describes-video`, in which case we set it to `main-desc` (note that this `kind` indicates that the track is a mix of the main track and description, so it can be played *instead* of the main track; a track with kind `description` *only* has the description, not the main track).
|
||||
|
||||
Below is a basic example of a mapping
|
||||
m3u8 layout
|
||||
``` JavaScript
|
||||
{
|
||||
'media-group-1': [{
|
||||
'audio-track-1': {
|
||||
default: true,
|
||||
lang: 'eng'
|
||||
},
|
||||
'audio-track-2': {
|
||||
default: false,
|
||||
lang: 'fr'
|
||||
},
|
||||
'audio-track-3': {
|
||||
default: false,
|
||||
lang: 'eng',
|
||||
characteristics: 'public.accessibility.describes-video'
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
Corresponding AudioTrackList when media-group-1 is used (before any tracks have been changed)
|
||||
``` JavaScript
|
||||
[{
|
||||
label: 'audio-tracks-1',
|
||||
enabled: true,
|
||||
language: 'eng',
|
||||
kind: 'main',
|
||||
id: 'random'
|
||||
}, {
|
||||
label: 'audio-tracks-2',
|
||||
enabled: false,
|
||||
language: 'fr',
|
||||
kind: 'alternative',
|
||||
id: 'random'
|
||||
}, {
|
||||
label: 'audio-tracks-3',
|
||||
enabled: false,
|
||||
language: 'eng',
|
||||
kind: 'main-desc',
|
||||
id: 'random'
|
||||
}]
|
||||
```
|
||||
|
||||
## Startup (how tracks are added and used)
|
||||
> AudioTrack & AudioTrackList live in video.js
|
||||
|
||||
1. `HLS` creates a `MasterPlaylistController` and watches for the `loadedmetadata` event
|
||||
1. `HLS` parses the m3u8 using the `MasterPlaylistController`
|
||||
1. `MasterPlaylistController` creates a `PlaylistLoader` for the master m3u8
|
||||
1. `MasterPlaylistController` creates `PlaylistLoader`s for every audio playlist
|
||||
1. `MasterPlaylistController` creates a `SegmentLoader` for the main m3u8
|
||||
1. `MasterPlaylistController` creates a `SegmentLoader` for a potential audio playlist
|
||||
1. `HLS` sees the `loadedmetadata` and finds the currently selected MediaGroup and all the metadata
|
||||
1. `HLS` removes all `AudioTrack`s from the `AudioTrackList`
|
||||
1. `HLS` created `AudioTrack`s for the MediaGroup and adds them to the `AudioTrackList`
|
||||
1. `HLS` calls `MasterPlaylistController`s `useAudio` with no arguments (causes it to use the currently enabled audio)
|
||||
1. `MasterPlaylistController` turns off the current audio `PlaylistLoader` if it is on
|
||||
1. `MasterPlaylistController` maps the `label` to the `PlaylistLoader` containing the audio
|
||||
1. `MasterPlaylistController` turns on that `PlaylistLoader` and the Corresponding `SegmentLoader` (master or audio only)
|
||||
1. `MediaSource`/`mux.js` determine how to mux
|
||||
|
||||
## How tracks are switched
|
||||
> AudioTrack & AudioTrackList live in video.js
|
||||
|
||||
1. `HLS` is setup to watch for the `changed` event on the `AudioTrackList`
|
||||
1. User selects a new `AudioTrack` from a menu (where only one track can be enabled)
|
||||
1. `AudioTrackList` enables the new `Audiotrack` and disables all others
|
||||
1. `AudioTrackList` triggers a `changed` event
|
||||
1. `HLS` sees the `changed` event and finds the newly enabled `AudioTrack`
|
||||
1. `HLS` sends the `label` for the new `AudioTrack` to `MasterPlaylistController`s `useAudio` function
|
||||
1. `MasterPlaylistController` turns off the current audio `PlaylistLoader` if it is on
|
||||
1. `MasterPlaylistController` maps the `label` to the `PlaylistLoader` containing the audio
|
||||
1. `MasterPlaylistController` maps the `label` to the `PlaylistLoader` containing the audio
|
||||
1. `MasterPlaylistController` turns on that `PlaylistLoader` and the Corresponding `SegmentLoader` (master or audio only)
|
||||
1. `MediaSource`/`mux.js` determine how to mux
|
16
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/player-time-to-program-time.md
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
# How to get player time from program time
|
||||
|
||||
NOTE: See the doc on [Program Time to Player Time](program-time-to-player-time.md) for definitions and an overview of the conversion process.
|
||||
|
||||
## Overview
|
||||
|
||||
To convert a program time to a player time, the following steps must be taken:
|
||||
|
||||
1. Find the right segment by sequentially searching through the playlist until the program time requested is >= the EXT-X-PROGRAM-DATE-TIME of the segment, and < the EXT-X-PROGRAM-DATE-TIME of the following segment (or the end of the playlist is reached).
|
||||
2. Determine the segment's start and end player times.
|
||||
|
||||
To accomplish #2, the segment must be downloaded and transmuxed (right now only TS segments are handled, and TS is always transmuxed to FMP4). This will obtain start and end times post transmuxer modifications. These are the times that the source buffer will recieve and report for the segment's newly created MP4 fragment.
|
||||
|
||||
Since there isn't a simple code path for downloading a segment without appending, the easiest approach is to seek to the estimated start time of that segment using the playlist duration calculation function. Because this process is not always accurate (manifest timing values are almost never accurate), a few seeks may be required to accurately seek into that segment.
|
||||
|
||||
If all goes well, and the target segment is downloaded and transmuxed, the player time may be found by taking the difference between the requested program time and the EXT-X-PROGRAM-DATE-TIME of the segment, then adding that difference to `segment.videoTimingInfo.transmuxedPresentationStart`.
|
47
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/playlist-loader.md
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Playlist Loader
|
||||
|
||||
## Purpose
|
||||
|
||||
The [PlaylistLoader][pl] (PL) is responsible for requesting m3u8s, parsing them and keeping track of the media "playlists" associated with the manifest. The [PL] is used with a [SegmentLoader] to load ts or fmp4 fragments from an HLS source.
|
||||
|
||||
## Basic Responsibilities
|
||||
|
||||
1. To request an m3u8.
|
||||
2. To parse a m3u8 into a format [videojs-http-streaming][vhs] can understand.
|
||||
3. To allow selection of a specific media stream.
|
||||
4. To refresh a live master m3u8 for changes.
|
||||
|
||||
## Design
|
||||
|
||||
### States
|
||||
|
||||

|
||||
|
||||
- `HAVE_NOTHING` the state before the m3u8 is received and parsed.
|
||||
- `HAVE_MASTER` the state before a media manifest is parsed and setup but after the master manifest has been parsed and setup.
|
||||
- `HAVE_METADATA` the state after a media stream is setup.
|
||||
- `SWITCHING_MEDIA` the intermediary state we go though while changing to a newly selected media playlist
|
||||
- `HAVE_CURRENT_METADATA` a temporary state after requesting a refresh of the live manifest and before receiving the update
|
||||
|
||||
### API
|
||||
|
||||
- `load()` this will either start or kick the loader during playback.
|
||||
- `start()` this will start the [PL] and request the m3u8.
|
||||
- `media()` this will return the currently active media stream or set a new active media stream.
|
||||
|
||||
### Events
|
||||
|
||||
- `loadedplaylist` signals the setup of a master playlist, representing the HLS source as a whole, from the m3u8; or a media playlist, representing a media stream.
|
||||
- `loadedmetadata` signals initial setup of a media stream.
|
||||
- `playlistunchanged` signals that no changes have been made to a m3u8.
|
||||
- `mediaupdatetimeout` signals that a live m3u8 and media stream must be refreshed.
|
||||
- `mediachanging` signals that the currently active media stream is going to be changed.
|
||||
- `mediachange` signals that the new media stream has been updated.
|
||||
|
||||
### Interaction with Other Modules
|
||||
|
||||

|
||||
|
||||
[pl]: ../src/playlist-loader.js
|
||||
[sl]: ../src/segment-loader.js
|
||||
[vhs]: intro.md
|
141
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/program-time-from-player-time.md
generated
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
# How to get program time from player time
|
||||
|
||||
## Definitions
|
||||
|
||||
NOTE: All times referenced in seconds unless otherwise specified.
|
||||
|
||||
*Player Time*: any time that can be gotten/set from player.currentTime() (e.g., any time within player.seekable().start(0) to player.seekable().end(0)).<br />
|
||||
*Stream Time*: any time within one of the stream's segments. Used by video frames (e.g., dts, pts, base media decode time). While these times natively use clock values, throughout the document the times are referenced in seconds.<br />
|
||||
*Program Time*: any time referencing the real world (e.g., EXT-X-PROGRAM-DATE-TIME).<br />
|
||||
*Start of Segment*: the pts (presentation timestamp) value of the first frame in a segment.<br />
|
||||
|
||||
## Overview
|
||||
|
||||
In order to convert from a *player time* to a *stream time*, an "anchor point" is required to match up a *player time*, *stream time*, and *program time*.
|
||||
|
||||
Two anchor points that are usable are the time since the start of a new timeline (e.g., the time since the last discontinuity or start of the stream), and the start of a segment. Because, in our requirements for this conversion, each segment is tagged with its *program time* in the form of an [EXT-X-PROGRAM-DATE-TIME tag](https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.6), using the segment start as the anchor point is the easiest solution. It's the closest potential anchor point to the time to convert, and it doesn't require us to track time changes across segments (e.g., trimmed or prepended content).
|
||||
|
||||
Those time changes are the result of the transmuxer, which can add/remove content in order to keep the content playable (without gaps or other breaking changes between segments), particularly when a segment doesn't start with a key frame.
|
||||
|
||||
In order to make use of the segment start, and to calculate the offset between the segment start and the time to convert, a few properties are needed:
|
||||
|
||||
1. The start of the segment before transmuxing
|
||||
1. Time changes made to the segment during transmuxing
|
||||
1. The start of the segment after transmuxing
|
||||
|
||||
While the start of the segment before and after transmuxing is trivial to retrieve, getting the time changes made during transmuxing is more complicated, as we must account for any trimming, prepending, and gap filling made during the transmux stage. However, the required use-case only needs the position of a video frame, allowing us to ignore any changes made to the audio timeline (because VHS uses video as the timeline of truth), as well as a couple of the video modifications.
|
||||
|
||||
What follows are the changes made to a video stream by the transmuxer that could alter the timeline, and if they must be accounted for in the conversion:
|
||||
|
||||
* Keyframe Pulling
|
||||
* Used when: the segment doesn't start with a keyframe.
|
||||
* Impact: the keyframe with the lowest dts value in the segment is "pulled" back to the first dts value in the segment, and all frames in-between are dropped.
|
||||
* Need to account in time conversion? No. If a keyframe is pulled, and frames before it are dropped, then the segment will maintain the same segment duration, and the viewer is only seeing the keyframe during that period.
|
||||
* GOP Fusion
|
||||
* Used when: the segment doesn't start with a keyframe.
|
||||
* Impact: if GOPs were saved from previous segment appends, the last GOP will be prepended to the segment.
|
||||
* Need to account in time conversion? Yes. The segment is artificially extended, so while it shouldn't impact the stream time itself (since it will overlap with content already appended), it will impact the post transmux start of segment.
|
||||
* GOPS to Align With
|
||||
* Used when: switching renditions, or appending segments with overlapping GOPs (intersecting time ranges).
|
||||
* Impact: GOPs in the segment will be dropped until there are no overlapping GOPs with previous segments.
|
||||
* Need to account in time conversion? No. So long as we aren't switching renditions, and the content is sane enough to not contain overlapping GOPs, this should not have a meaningful impact.
|
||||
|
||||
Among the changes, with only GOP Fusion having an impact, the task is simplified. Instead of accounting for any changes to the video stream, only those from GOP Fusion should be accounted for. Since GOP fusion will potentially only prepend frames to the segment, we just need the number of seconds prepended to the segment when offsetting the time. As such, we can add the following properties to each segment:
|
||||
|
||||
```
|
||||
segment: {
|
||||
// calculated start of segment from either end of previous segment or end of last buffer
|
||||
// (in stream time)
|
||||
start,
|
||||
...
|
||||
videoTimingInfo: {
|
||||
// number of seconds prepended by GOP fusion
|
||||
transmuxerPrependedSeconds
|
||||
// start of transmuxed segment (in player time)
|
||||
transmuxedPresentationStart
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## The Formula
|
||||
|
||||
With the properties listed above, calculating a *program time* from a *player time* is given as follows:
|
||||
|
||||
```
|
||||
const playerTimeToProgramTime = (playerTime, segment) => {
|
||||
if (!segment.dateTimeObject) {
|
||||
// Can't convert without an "anchor point" for the program time (i.e., a time that can
|
||||
// be used to map the start of a segment with a real world time).
|
||||
return null;
|
||||
}
|
||||
|
||||
const transmuxerPrependedSeconds = segment.videoTimingInfo.transmuxerPrependedSeconds;
|
||||
const transmuxedStart = segment.videoTimingInfo.transmuxedPresentationStart;
|
||||
|
||||
// get the start of the content from before old content is prepended
|
||||
const startOfSegment = transmuxedStart + transmuxerPrependedSeconds;
|
||||
const offsetFromSegmentStart = playerTime - startOfSegment;
|
||||
|
||||
return new Date(segment.dateTimeObject.getTime() + offsetFromSegmentStart * 1000);
|
||||
};
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
// Program Times:
|
||||
// segment1: 2018-11-10T00:00:30.1Z => 2018-11-10T00:00:32.1Z
|
||||
// segment2: 2018-11-10T00:00:32.1Z => 2018-11-10T00:00:34.1Z
|
||||
// segment3: 2018-11-10T00:00:34.1Z => 2018-11-10T00:00:36.1Z
|
||||
//
|
||||
// Player Times:
|
||||
// segment1: 0 => 2
|
||||
// segment2: 2 => 4
|
||||
// segment3: 4 => 6
|
||||
|
||||
const segment1 = {
|
||||
dateTimeObject: 2018-11-10T00:00:30.1Z
|
||||
videoTimingInfo: {
|
||||
transmuxerPrependedSeconds: 0,
|
||||
transmuxedPresentationStart: 0
|
||||
}
|
||||
};
|
||||
playerTimeToProgramTime(0.1, segment1);
|
||||
// startOfSegment = 0 + 0 = 0
|
||||
// offsetFromSegmentStart = 0.1 - 0 = 0.1
|
||||
// return 2018-11-10T00:00:30.1Z + 0.1 = 2018-11-10T00:00:30.2Z
|
||||
|
||||
const segment2 = {
|
||||
dateTimeObject: 2018-11-10T00:00:32.1Z
|
||||
videoTimingInfo: {
|
||||
transmuxerPrependedSeconds: 0.3,
|
||||
transmuxedPresentationStart: 1.7
|
||||
}
|
||||
};
|
||||
playerTimeToProgramTime(2.5, segment2);
|
||||
// startOfSegment = 1.7 + 0.3 = 2
|
||||
// offsetFromSegmentStart = 2.5 - 2 = 0.5
|
||||
// return 2018-11-10T00:00:32.1Z + 0.5 = 2018-11-10T00:00:32.6Z
|
||||
|
||||
const segment3 = {
|
||||
dateTimeObject: 2018-11-10T00:00:34.1Z
|
||||
videoTimingInfo: {
|
||||
transmuxerPrependedSeconds: 0.2,
|
||||
transmuxedPresentationStart: 3.8
|
||||
}
|
||||
};
|
||||
playerTimeToProgramTime(4, segment3);
|
||||
// startOfSegment = 3.8 + 0.2 = 4
|
||||
// offsetFromSegmentStart = 4 - 4 = 0
|
||||
// return 2018-11-10T00:00:34.1Z + 0 = 2018-11-10T00:00:34.1Z
|
||||
```
|
||||
|
||||
## Transmux Before Append Changes
|
||||
|
||||
Even though segment timing values are retained for transmux before append, the formula does not need to change, as all that matters for calculation is the offset from the transmuxed segment start, which can then be applied to the stream time start of segment, or the program time start of segment.
|
||||
|
||||
## Getting the Right Segment
|
||||
|
||||
In order to make use of the above calculation, the right segment must be chosen for a given player time. This time may be retrieved by simply using the times of the segment after transmuxing (as the start/end pts/dts values then reflect the player time it should slot into in the source buffer). These are included in `videoTimingInfo` as `transmuxedPresentationStart` and `transmuxedPresentationEnd`.
|
||||
|
||||
Although there may be a small amount of overlap due to `transmuxerPrependedSeconds`, as long as the search is sequential from the beginning of the playlist to the end, the right segment will be found, as the prepended times will only come from content from prior segments.
|
43
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/reload-source-on-error.md
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Using the reloadSourceOnError Plugin
|
||||
Call the plugin to activate it:
|
||||
|
||||
```js
|
||||
player.reloadSourceOnError()
|
||||
```
|
||||
Now if the player encounters a fatal error during playback, it will automatically
|
||||
attempt to reload the current source. If the error was caused by a transient
|
||||
browser or networking problem, this can allow playback to continue with a minimum
|
||||
of disruption to your viewers.
|
||||
|
||||
The plugin will only restart your player once in a 30 second time span so that your
|
||||
player doesn't get into a reload loop if it encounters non-transient errors. You
|
||||
can tweak the amount of time required between restarts by adjusting the
|
||||
`errorInterval` option.
|
||||
|
||||
If your video URLs are time-sensitive, the original source could be invalid by the
|
||||
time an error occurs. If that's the case, you can provide a `getSource` callback
|
||||
to regenerate a valid source object. In your callback, the `this` keyword is a
|
||||
reference to the player that errored. The first argument to `getSource` is a
|
||||
function. Invoke that function and pass in your new source object when you're ready.
|
||||
|
||||
```js
|
||||
player.reloadSourceOnError({
|
||||
|
||||
// getSource allows you to override the source object used when an error occurs
|
||||
getSource: function(reload) {
|
||||
console.log('Reloading because of an error');
|
||||
|
||||
// call reload() with a fresh source object
|
||||
// you can do this step asynchronously if you want (but the error dialog will
|
||||
// show up while you're waiting)
|
||||
reload({
|
||||
src: 'https://example.com/index.m3u8?token=abc123ef789',
|
||||
type: 'application/x-mpegURL'
|
||||
});
|
||||
},
|
||||
|
||||
// errorInterval specifies the minimum amount of seconds that must pass before
|
||||
// another reload will be attempted
|
||||
errorInterval: 5
|
||||
});
|
||||
```
|
289
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/supported-features.md
generated
vendored
Normal file
|
@ -0,0 +1,289 @@
|
|||
# Supported Features
|
||||
|
||||
## Browsers
|
||||
|
||||
Any browser that supports [MSE] (media source extensions). See
|
||||
https://caniuse.com/#feat=mediasource
|
||||
|
||||
Note that browsers with native HLS support may play content with the native player, unless
|
||||
the [overrideNative] option is used. Some notable browsers with native HLS players are:
|
||||
|
||||
* Safari (macOS and iOS)
|
||||
* Chrome Android
|
||||
* Firefox Android
|
||||
|
||||
However, due to the limited features offered by some of the native players, the only
|
||||
browser on which VHS defaults to using the native player is Safari (macOS and iOS).
|
||||
|
||||
## Streaming Formats and Media Types
|
||||
|
||||
### Streaming Formats
|
||||
|
||||
VHS aims to be mostly streaming format agnostic. So long as the manifest can be parsed to
|
||||
a common JSON representation, VHS should be able to play it. However, due to some large
|
||||
differences between the major streaming formats (HLS and DASH), some format specific code
|
||||
is included in VHS. If you have another format you would like supported, please reach out
|
||||
to us (e.g., file an issue).
|
||||
|
||||
* [HLS] (HTTP Live Streaming)
|
||||
* [MPEG-DASH] (Dynamic Adaptive Streaming over HTTP)
|
||||
|
||||
### Media Container Formats
|
||||
|
||||
* [TS] (MPEG Transport Stream)
|
||||
* [MP4] (MPEG-4 Part 14: MP4, M4A, M4V, M4S, MPA), ISOBMFF
|
||||
* [AAC] (Advanced Audio Coding)
|
||||
|
||||
### Codecs
|
||||
|
||||
If the content is packaged in an [MP4] container, then any codec supported by the browser
|
||||
is supported. If the content is packaged in a [TS] container, then the codec must be
|
||||
supported by [the transmuxer]. The following codecs are supported by the transmuxer:
|
||||
|
||||
* [AVC] (Advanced Video Coding, h.264)
|
||||
* [AVC1] (Advnced Video Coding, h.265)
|
||||
* [HE-AAC] (High Efficiency Advanced Audio Coding, mp4a.40.5)
|
||||
* LC-AAC (Low Complexity Advanced Audio Coding, mp4a.40.2)
|
||||
|
||||
## General Notable Features
|
||||
|
||||
The following is a list of some, but not all, common streaming features supported by VHS.
|
||||
It is meant to highlight some common use cases (and provide for easy searching), but is
|
||||
not meant serve as an exhaustive list.
|
||||
|
||||
* VOD (video on demand)
|
||||
* LIVE
|
||||
* Multiple audio tracks
|
||||
* Timed [ID3] Metadata is automatically translated into HTML5 metedata text tracks
|
||||
* Cross-domain credentials support with [CORS]
|
||||
* Any browser supported resolution (e.g., 4k)
|
||||
* Any browser supported framerate (e.g., 60fps)
|
||||
* [DRM] via [videojs-contrib-eme]
|
||||
* Audio only (non DASH)
|
||||
* Video only (non DASH)
|
||||
* In-manifest [WebVTT] subtitles are automatically translated into standard HTML5 subtitle
|
||||
tracks
|
||||
* [AES-128] segment encryption
|
||||
|
||||
## Notable Missing Features
|
||||
|
||||
Note that the following features have not yet been implemented or may work but are not
|
||||
currently suppported in browsers that do not rely on the native player. For browsers that
|
||||
use the native player (e.g., Safari for HLS), please refer to their documentation.
|
||||
|
||||
### Container Formats
|
||||
|
||||
* [WebM]
|
||||
* [WAV]
|
||||
* [MP3]
|
||||
* [OGG]
|
||||
|
||||
### Codecs
|
||||
|
||||
If the content is packaged within an [MP4] container and the browser supports the codec, it
|
||||
will play. However, the following are some codecs that are not routinely tested, or are not
|
||||
supported when packaged within [TS].
|
||||
|
||||
* [MP3]
|
||||
* [Vorbis]
|
||||
* [WAV]
|
||||
* [FLAC]
|
||||
* [Opus]
|
||||
* [VP8]
|
||||
* [VP9]
|
||||
* [Dolby Vision] (DVHE)
|
||||
* [Dolby Digital] Audio (AC-3)
|
||||
* [Dolby Digital Plus] (E-AC-3)
|
||||
|
||||
### HLS Missing Features
|
||||
|
||||
Note: features for low latency HLS in the [2nd edition of HTTP Live Streaming] are on the
|
||||
roadmap, but not currently available.
|
||||
|
||||
VHS strives to support all of the features in the HLS specification, however, some have
|
||||
not yet been implemented. VHS currently supports everything in the
|
||||
[HLS specification v7, revision 23], except the following:
|
||||
|
||||
* Use of [EXT-X-MAP] with [TS] segments
|
||||
* [EXT-X-MAP] is currently supported for [MP4] segments, but not yet for TS
|
||||
* I-Frame playlists via [EXT-X-I-FRAMES-ONLY] and [EXT-X-I-FRAME-STREAM-INF]
|
||||
* [MP3] Audio
|
||||
* [Dolby Digital] Audio (AC-3)
|
||||
* [Dolby Digital Plus] Audio (E-AC-3)
|
||||
* KEYFORMATVERSIONS of [EXT-X-KEY]
|
||||
* [EXT-X-DATERANGE]
|
||||
* [EXT-X-SESSION-DATA]
|
||||
* [EXT-X-SESSION-KEY]
|
||||
* [EXT-X-INDEPENDENT-SEGMENTS]
|
||||
* Use of [EXT-X-START] (value parsed but not used)
|
||||
* Alternate video via [EXT-X-MEDIA] of type video
|
||||
* ASSOC-LANGUAGE in [EXT-X-MEDIA]
|
||||
* CHANNELS in [EXT-X-MEDIA]
|
||||
* Use of AVERAGE-BANDWIDTH in [EXT-X-STREAM-INF] (value parsed but not used)
|
||||
* Use of FRAME-RATE in [EXT-X-STREAM-INF] (value parsed but not used)
|
||||
* Use of HDCP-LEVEL in [EXT-X-STREAM-INF]
|
||||
* SAMPLE-AES segment encryption
|
||||
|
||||
In the event of encoding changes within a playlist (see
|
||||
https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-6.3.3), the
|
||||
behavior will depend on the browser.
|
||||
|
||||
### DASH Missing Features
|
||||
|
||||
DASH support is more recent than HLS support in VHS, however, VHS strives to achieve as
|
||||
complete compatibility as possible with the DASH spec. The following are some notable
|
||||
features in the DASH specification that are not yet implemented in VHS:
|
||||
|
||||
Note that many of the following are parsed by [mpd-parser] but are either not yet used, or
|
||||
simply take on their default values (in the case where they have valid defaults).
|
||||
|
||||
* Audio and video only streams
|
||||
* Audio rendition switching
|
||||
* Each video rendition is paired with an audio rendition for the duration of playback.
|
||||
* MPD
|
||||
* @id
|
||||
* @profiles
|
||||
* @availabilityStartTime
|
||||
* @availabilityEndTime
|
||||
* @minBufferTime
|
||||
* @maxSegmentDuration
|
||||
* @maxSubsegmentDuration
|
||||
* ProgramInformation
|
||||
* Metrics
|
||||
* Period
|
||||
* @xlink:href
|
||||
* @xlink:actuate
|
||||
* @id
|
||||
* @duration
|
||||
* Normally used for determing the PeriodStart of the next period, VHS instead relies
|
||||
on segment durations to determine timing of each segment and timeline
|
||||
* @bitstreamSwitching
|
||||
* Subset
|
||||
* AdaptationSet
|
||||
* @xlink:href
|
||||
* @xlink:actuate
|
||||
* @id
|
||||
* @group
|
||||
* @par (picture aspect ratio)
|
||||
* @minBandwidth
|
||||
* @maxBandwidth
|
||||
* @minWidth
|
||||
* @maxWidth
|
||||
* @minHeight
|
||||
* @maxHeight
|
||||
* @minFrameRate
|
||||
* @maxFrameRate
|
||||
* @segmentAlignment
|
||||
* @bitstreamSwitching
|
||||
* @subsegmentAlignment
|
||||
* @subsegmentStartsWithSAP
|
||||
* Accessibility
|
||||
* Rating
|
||||
* Viewpoint
|
||||
* ContentComponent
|
||||
* Representation
|
||||
* @id (used for SegmentTemplate but not exposed otherwise)
|
||||
* @qualityRanking
|
||||
* @dependencyId (dependent representation)
|
||||
* @mediaStreamStructureId
|
||||
* SubRepresentation
|
||||
* CommonAttributesElements (for AdaptationSet, Representation and SubRepresentation elements)
|
||||
* @profiles
|
||||
* @sar
|
||||
* @frameRate
|
||||
* @audioSamplingRate
|
||||
* @segmentProfiles
|
||||
* @maximumSAPPeriod
|
||||
* @startWithSAP
|
||||
* @maxPlayoutRate
|
||||
* @codingDependency
|
||||
* @scanType
|
||||
* FramePacking
|
||||
* AudioChannelConfiguration
|
||||
* SegmentBase
|
||||
* @presentationTimeOffset
|
||||
* @indexRangeExact
|
||||
* RepresentationIndex
|
||||
* MultipleSegmentBaseInformation elements
|
||||
* SegmentList
|
||||
* @xlink:href
|
||||
* @xlink:actuate
|
||||
* MultipleSegmentBaseInformation
|
||||
* SegmentURL
|
||||
* @index
|
||||
* @indexRange
|
||||
* SegmentTemplate
|
||||
* MultipleSegmentBaseInformation
|
||||
* @index
|
||||
* @bitstreamSwitching
|
||||
* BaseURL
|
||||
* @serviceLocation
|
||||
* Template-based Segment URL construction
|
||||
* Live DASH assets that use $Time$ in a SegmentTemplate, and also have a SegmentTimeline
|
||||
where only the first S has a t and the rest only have a d do not update on playlist
|
||||
refreshes
|
||||
See: https://github.com/videojs/http-streaming#dash-assets-with-time-interpolation-and-segmenttimelines-with-no-t
|
||||
* ContentComponent elements
|
||||
* Right now manifests are assumed to have a single content component, with the properties
|
||||
described directly on the AdaptationSet element
|
||||
* SubRepresentation elements
|
||||
* Subset elements
|
||||
* Early Available Periods (may work, but has not been tested)
|
||||
* Access to subsegments via a subsegment index ('ssix')
|
||||
* The @profiles attribute is ignored (best support for all profiles is attempted, without
|
||||
consideration of the specific profile). For descriptions on profiles, see section 8 of
|
||||
the DASH spec.
|
||||
* Construction of byte range URLs via a BaseURL byteRange template (Annex E.2)
|
||||
* Multiperiod content where the representation sets are not the same across periods
|
||||
* In the event that an S element has a t attribute that is greater than what is expected,
|
||||
it is not treated as a discontinuity, but instead retains its segment value, and may
|
||||
result in a gap in the content
|
||||
|
||||
[MSE]: https://www.w3.org/TR/media-source/
|
||||
[HLS]: https://en.wikipedia.org/wiki/HTTP_Live_Streaming
|
||||
[MPEG-DASH]: https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP
|
||||
[TS]: https://en.wikipedia.org/wiki/MPEG_transport_stream
|
||||
[MP4]: https://en.wikipedia.org/wiki/MPEG-4_Part_14
|
||||
[AAC]: https://en.wikipedia.org/wiki/Advanced_Audio_Coding
|
||||
[AVC]: https://en.wikipedia.org/wiki/Advanced_Video_Coding
|
||||
[AVC1]: https://en.wikipedia.org/wiki/Advanced_Video_Coding
|
||||
[HE-AAC]: https://en.wikipedia.org/wiki/High-Efficiency_Advanced_Audio_Coding
|
||||
[ID3]: https://en.wikipedia.org/wiki/ID3
|
||||
[CORS]: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
|
||||
[DRM]: https://en.wikipedia.org/wiki/Digital_rights_management
|
||||
[WebVTT]: https://www.w3.org/TR/webvtt1/
|
||||
[AES-128]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
|
||||
[WebM]: https://en.wikipedia.org/wiki/WebM
|
||||
[WAV]: https://en.wikipedia.org/wiki/WAV
|
||||
[MP3]: https://en.wikipedia.org/wiki/MP3
|
||||
[OGG]: https://en.wikipedia.org/wiki/Ogg
|
||||
[Vorbis]: https://en.wikipedia.org/wiki/Vorbis
|
||||
[FLAC]: https://en.wikipedia.org/wiki/FLAC
|
||||
[Opus]: https://en.wikipedia.org/wiki/Opus_(audio_format)
|
||||
[VP8]: https://en.wikipedia.org/wiki/VP8
|
||||
[VP9]: https://en.wikipedia.org/wiki/VP9
|
||||
|
||||
[overrideNative]: https://github.com/videojs/http-streaming#overridenative
|
||||
[the transmuxer]: https://github.com/videojs/mux.js
|
||||
[videojs-contrib-eme]: https://github.com/videojs/videojs-contrib-eme
|
||||
|
||||
[2nd edition of HTTP Live Streaming]: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-07.html
|
||||
[HLS specification v7, revision 23]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23
|
||||
|
||||
[EXT-X-MAP]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.5
|
||||
[EXT-X-STREAM-INF]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.4.2
|
||||
[EXT-X-SESSION-DATA]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.4.4
|
||||
[EXT-X-DATERANGE]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.7
|
||||
[EXT-X-KEY]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.7
|
||||
[EXT-X-I-FRAMES-ONLY]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.3.6
|
||||
[EXT-X-I-FRAME-STREAM-INF]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.4.3
|
||||
[EXT-X-SESSION-KEY]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.4.5
|
||||
[EXT-X-INDEPENDENT-SEGMENTS]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.5.1
|
||||
[EXT-X-START]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.5.2
|
||||
[EXT-X-MEDIA]: https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.4.1
|
||||
|
||||
[Dolby Vision]: https://en.wikipedia.org/wiki/High-dynamic-range_video#Dolby_Vision
|
||||
[Dolby Digital]: https://en.wikipedia.org/wiki/Dolby_Digital
|
||||
[Dolby Digital Plus]: https://en.wikipedia.org/wiki/Dolby_Digital_Plus
|
||||
|
||||
[mpd-parser]: https://github.com/videojs/mpd-parser
|
67
node_modules/videojs-ima/node_modules/@videojs/http-streaming/docs/troubleshooting.md
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Troubleshooting Guide
|
||||
|
||||
## Other troubleshooting guides
|
||||
|
||||
For issues around data embedded into media segments (e.g., 608 captions), see the [mux.js troubleshooting guide](https://github.com/videojs/mux.js/blob/master/docs/troubleshooting.md).
|
||||
|
||||
## Tools
|
||||
|
||||
### Thumbcoil
|
||||
|
||||
Thumbcoil is a video inspector tool that can unpackage various media containers and inspect the bitstreams therein. Thumbcoil runs entirely within your browser so that none of your video data is ever transmitted to a server.
|
||||
|
||||
http://thumb.co.il<br/>
|
||||
http://beta.thumb.co.il<br/>
|
||||
https://github.com/videojs/thumbcoil<br/>
|
||||
|
||||
## Table of Contents
|
||||
- [Content plays on Mac but not on Windows](#content-plays-on-mac-but-not-windows)
|
||||
- ["No compatible source was found" on IE11 Win 7](#no-compatible-source-was-found-on-ie11-win-7)
|
||||
- [CORS: No Access-Control-Allow-Origin header](#cors-no-access-control-allow-origin-header)
|
||||
- [Desktop Safari/iOS Safari/Android Chrome/Edge exhibit different behavior from other browsers](#desktop-safariios-safariandroid-chromeedge-exhibit-different-behavior-from-other-browsers)
|
||||
- [MEDIA_ERR_DECODE error on Desktop Safari](#media_err_decode-error-on-desktop-safari)
|
||||
- [Network requests are still being made while paused](#network-requests-are-still-being-made-while-paused)
|
||||
|
||||
## Content plays on Mac but not Windows
|
||||
|
||||
Some browsers may not be able to play audio sample rates higher than 48 kHz. See https://docs.microsoft.com/en-gb/windows/desktop/medfound/aac-decoder#format-constraints
|
||||
|
||||
Potential solution: re-encode with a Windows supported audio sample rate
|
||||
|
||||
## "No compatible source was found" on IE11 Win 7
|
||||
|
||||
videojs-http-streaming does not support Flash HLS playback (like the videojs-contrib-hls plugin does)
|
||||
|
||||
Solution: include the FlasHLS source handler https://github.com/brightcove/videojs-flashls-source-handler#usage
|
||||
|
||||
## CORS: No Access-Control-Allow-Origin header
|
||||
|
||||
If you see an error along the lines of
|
||||
|
||||
```
|
||||
XMLHttpRequest cannot load ... No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ... is therefore not allowed access.
|
||||
```
|
||||
|
||||
you need to properly configure CORS on your server: https://github.com/videojs/http-streaming#hosting-considerations
|
||||
|
||||
## Desktop Safari/iOS Safari/Android Chrome/Edge exhibit different behavior from other browsers
|
||||
|
||||
Some browsers support native playback of certain streaming formats. By default, we defer to the native players. However, this means that features specific to videojs-http-streaming will not be available.
|
||||
|
||||
On Edge and mobile Chrome, 608 captions, ID3 tags or live streaming may not work as expected with native playback, it is recommended that `overrideNative` be used on those platforms if necessary.
|
||||
|
||||
Solution: use videojs-http-streaming based playback on those devices: https://github.com/videojs/http-streaming#overridenative
|
||||
|
||||
## MEDIA_ERR_DECODE error on Desktop Safari
|
||||
|
||||
This error may occur for a number of reasons, as it is particularly common for misconfigured content. One instance of misconfiguration is if the source manifest has `CLOSED-CAPTIONS=NONE` and an external text track is loaded into the player. Safari does not allow the inclusion any captions if the manifest indicates that captions will not be provided.
|
||||
|
||||
Solution: remove `CLOSED-CAPTIONS=NONE` from the manifest
|
||||
|
||||
## Network requests are still being made while paused
|
||||
|
||||
There are a couple of cases where network requests will still be made by VHS when the video is paused.
|
||||
|
||||
1) If the forward buffer (buffered content ahead of the playhead) has not reached the GOAL\_BUFFER\_LENGTH. For instance, if the playhead is at time 10 seconds, the buffered range goes from 5 seconds to 20 seconds, and the GOAL\_BUFFER\_LENGTH is set to 30 seconds, then segments will continue to be requested, even while paused, until the buffer ends at a time greater than or equal to 10 seconds (current time) + 30 seconds (GOAL\_BUFFER\_LENGTH) = 40 seconds. This is expected behavior in order to provide a better playback experience.
|
||||
|
||||
2) If the stream is LIVE, then the manifest will continue to be refreshed even while paused. This is because it is easier to keep playback in sync if we receieve manifest updates consistently.
|
256
node_modules/videojs-ima/node_modules/@videojs/http-streaming/index.html
generated
vendored
Normal file
|
@ -0,0 +1,256 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>videojs-http-streaming Demo</title>
|
||||
<link rel="icon" href="logo.svg">
|
||||
<link href="node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet">
|
||||
<link href="node_modules/videojs-http-source-selector/dist/videojs-http-source-selector.css" rel="stylesheet">
|
||||
<style>
|
||||
.form-check {
|
||||
background-color: hsl(0, 0%, 90%);
|
||||
margin-block: 0.5rem;
|
||||
padding: 0.25em 0.25em 0.25em 1.75em;
|
||||
width: 700px;
|
||||
width: fit-content;
|
||||
}
|
||||
#player-fixture {
|
||||
min-height: 250px;
|
||||
}
|
||||
#segment-metadata {
|
||||
list-style: none;
|
||||
}
|
||||
#segment-metadata pre {
|
||||
overflow: scroll;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="m-4">
|
||||
<script>
|
||||
// if we're on IE, load up the load index page
|
||||
var result = (/MSIE\s(\d+)\.\d/).exec(navigator.userAgent);
|
||||
var version = result && parseFloat(result[1]);
|
||||
|
||||
if (!version && (/Trident\/7.0/i).test(navigator.userAgent) && (/rv:11.0/).test(navigator.userAgent)) {
|
||||
// IE 11 has a different user agent string than other IE versions
|
||||
version = 11.0;
|
||||
}
|
||||
|
||||
if (version) {
|
||||
window.location.href = './old-index.html';
|
||||
}
|
||||
</script>
|
||||
|
||||
<header class="container-fluid">
|
||||
<a href="https://github.com/videojs/http-streaming" class="d-flex align-items-center pb-3 mb-5 border-bottom" style="height: 4em">
|
||||
<img src="./logo.svg" alt="VHS logo showcasing a VHS tape with the Video.js logo on the label" class="rounded mh-100">
|
||||
<span class="fs-1 ps-2">VHS: videojs-http-streaming</span>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<div id="player-fixture" class="container-fluid pb-3 mb-3"></div>
|
||||
|
||||
<ul class="nav nav-tabs container-fluid mb-3" id="myTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#sources" type="button" role="tab" aria-selected="true">Sources</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#options" type="button" role="tab" aria-selected="false">Options</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#levels" type="button" role="tab" aria-selected="false">Representations</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#player-stats" type="button" role="tab" aria-selected="false">Player Stats</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content container-fluid">
|
||||
|
||||
<div class="tab-pane active" id="sources" role="tabpanel">
|
||||
<div class="input-group mb-2">
|
||||
<span class="input-group-text"><label for=load-source>Preloaded Sources</label></span>
|
||||
<select id=load-source class="form-select">
|
||||
<optgroup label="hls">
|
||||
</optgroup>
|
||||
<optgroup label="dash">
|
||||
</optgroup>
|
||||
<optgroup label="drm">
|
||||
</optgroup>
|
||||
<optgroup label="live">
|
||||
</optgroup>
|
||||
<optgroup label="low latency live">
|
||||
</optgroup>
|
||||
<optgroup label="json manifest object">
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label for=url class="form-label">Source URL</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><label for=url>Url</label></span>
|
||||
<input id=url type=url class="form-control">
|
||||
</div>
|
||||
|
||||
<label for=type class="form-label">Source Type (uses url extension if blank, usually application/x-mpegURL or application/dash+xml)</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><label for=type>Type</label></span>
|
||||
<input id=type type=text class="form-control">
|
||||
</div>
|
||||
|
||||
<label for="keysystems" class="form-label">Optional Keystems JSON:</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><label for=keysystems>keySystems JSON</label></span>
|
||||
<textarea id=keysystems cols=100 rows=5 class="form-control"></textarea>
|
||||
</div>
|
||||
|
||||
<button id=load-url type=button class="btn btn-primary my-2">Load</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="options" role="tabpanel">
|
||||
<div class="options">
|
||||
<div class="form-check">
|
||||
<input id=minified type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="minified">Minified VHS (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=sync-workers type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="sync-workers">Synchronous Web Workers (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=liveui type="checkbox" class="form-check-input" checked>
|
||||
<label class="form-check-label" for="liveui">Enable the live UI (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=fluid type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="fluid">Fluid mode</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=debug type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="debug">Debug Logging</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=muted type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="muted">Muted</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=autoplay type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="autoplay">Autoplay</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=network-info type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="network-info">Use networkInfo API for bandwidth estimations (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=dts-offset type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="dts-offset">Use DTS instead of PTS for Timestamp Offset calculation (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=llhls type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="llhls">[EXPERIMENTAL] Enables support for ll-hls (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=buffer-water type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="buffer-water">[EXPERIMENTAL] Use Buffer Level for ABR (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=exact-manifest-timings type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="exact-manifest-timings">[EXPERIMENTAL] Use exact manifest timings for segment choices (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=pixel-diff-selector type="checkbox" class="form-check-input">
|
||||
<label class="form-check-label" for="pixel-diff-selector">[EXPERIMENTAL] Use the Pixel difference resolution selector (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=override-native type="checkbox" class="form-check-input" checked>
|
||||
<label class="form-check-label" for="override-native">Override Native (reloads player)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input id=mirror-source type="checkbox" class="form-check-input" checked>
|
||||
<label class="form-check-label" for="mirror-source">Mirror sources from player.src (reloads player, uses EXPERIMENTAL sourceset option)</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><label for=preload>Preload (reloads player)</label></span>
|
||||
<select id=preload class="form-select">
|
||||
<option selected>auto</option>
|
||||
<option>none</option>
|
||||
<option>metadata</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="levels" role="tabpanel">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><label for=representations>Representations</label></span>
|
||||
<select id='representations' class="form-select"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="player-stats" role="tabpanel">
|
||||
<div class="row">
|
||||
<div class="player-stats col-4">
|
||||
<dl>
|
||||
<dt>Current Time:</dt>
|
||||
<dd class="current-time-stat">0</dd>
|
||||
<dt>Buffered:</dt>
|
||||
<dd class="buffered-stat">-</dd>
|
||||
<dt>Video Buffered:</dt>
|
||||
<dd class="video-buffered-stat">-</dd>
|
||||
<dt>Audio Buffered:</dt>
|
||||
<dd class="audio-buffered-stat">-</dd>
|
||||
<dt>Seekable:</dt>
|
||||
<dd><span class="seekable-start-stat">-</span> - <span class="seekable-end-stat">-</span></dd>
|
||||
<dt>Video Bitrate:</dt>
|
||||
<dd class="video-bitrate-stat">0 kbps</dd>
|
||||
<dt>Measured Bitrate:</dt>
|
||||
<dd class="measured-bitrate-stat">0 kbps</dd>
|
||||
<dt>Video Timestamp Offset</dt>
|
||||
<dd class="video-timestampoffset">0</dd>
|
||||
<dt>Audio Timestamp Offset</dt>
|
||||
<dd class="audio-timestampoffset">0</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<ul id="segment-metadata" class="col-8"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="text-center p-3" id=unit-test-link>
|
||||
<a href="test/debug.html">Run unit tests</a>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
var unitTestLink = document.getElementById('unit-test-link');
|
||||
|
||||
// removal test run link on netlify, as we cannot run tests there.
|
||||
if ((/netlify.app/).test(window.location.host)) {
|
||||
unitTestLink.remove();
|
||||
}
|
||||
</script>
|
||||
<script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<script src="scripts/index.js"></script>
|
||||
<script>
|
||||
window.startDemo(function(player) {
|
||||
// do something with setup player
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
3715
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/CHANGELOG.md
generated
vendored
Normal file
13
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
Copyright Brightcove, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
160
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/README.md
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
![Video.js logo][logo]
|
||||
|
||||
# [Video.js - HTML5 Video Player][vjs]
|
||||
|
||||
[![Build Status][travis-icon]][travis-link]
|
||||
[![Coverage Status][coveralls-icon]][coveralls-link]
|
||||
[](https://greenkeeper.io/)
|
||||
[![Slack Status][slack-icon]][slack-link]
|
||||
|
||||
[![NPM][npm-icon]][npm-link]
|
||||
|
||||
> Video.js is a web video player built from the ground up for an HTML5 world. It supports HTML5 video and Media Source Extensions, as well as other playback techs like YouTube and Vimeo (through [plugins][plugins]). It supports video playback on desktops and mobile devices. This project was started mid 2010, and the player is now used on over ~~50,000~~ ~~100,000~~ ~~200,000~~ ~~400,000~~ [700,000 websites][builtwith].
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Quick Start](#quick-start)
|
||||
* [Contributing](#contributing)
|
||||
* [Code of Conduct](#code-of-conduct)
|
||||
* [License](#license)
|
||||
|
||||
## Quick Start
|
||||
|
||||
Thanks to the awesome folks over at [Fastly][fastly], there's a free, CDN hosted version of Video.js that anyone can use. Add these tags to your document's `<head>`:
|
||||
|
||||
```html
|
||||
<link href="//vjs.zencdn.net/7.10.2/video-js.min.css" rel="stylesheet">
|
||||
<script src="//vjs.zencdn.net/7.10.2/video.min.js"></script>
|
||||
```
|
||||
|
||||
> For the latest version of video.js and URLs to use, check out the [Getting Started][getting-started] page on our website.
|
||||
|
||||
Video.js version 7 (and newer) CDN builds do not send any data to Google Analytics.
|
||||
|
||||
In older versions of Video.js (6 and earlier), in the `vjs.zencdn.net` CDN-hosted versions we include a [stripped down Google Analytics pixel](https://github.com/videojs/cdn/blob/master/src/analytics.js) that tracks a random sampling (currently 1%) of players loaded from the CDN. This allows us to see (roughly) what browsers are in use in the wild, along with other useful metrics such as OS and device. If you'd like to disable analytics, you can simply include the following global before including Video.js via the free CDN:
|
||||
|
||||
```html
|
||||
<script>window.HELP_IMPROVE_VIDEOJS = false;</script>
|
||||
```
|
||||
|
||||
Alternatively, you can include Video.js by getting it from [npm](https://videojs.com/getting-started/#install-via-npm), downloading from [GitHub releases](https://github.com/videojs/video.js/releases) or by including it via [unpkg](https://unpkg.com) or another JavaScript CDN like CDNjs. These releases _do not_ include Google Analytics tracking at all.
|
||||
|
||||
```html
|
||||
<!-- unpkg : use the latest version of Video.js -->
|
||||
<link href="https://unpkg.com/video.js/dist/video-js.min.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
|
||||
|
||||
<!-- unpkg : use a specific version of Video.js (change the version numbers as necessary) -->
|
||||
<link href="https://unpkg.com/video.js@7.10.2/dist/video-js.min.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/video.js@7.10.2/dist/video.min.js"></script>
|
||||
|
||||
<!-- cdnjs : use a specific version of Video.js (change the version numbers as necessary) -->
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.10.2/video-js.min.css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.10.2/video.min.js"></script>
|
||||
```
|
||||
|
||||
Next, using Video.js is as simple as creating a `<video>` element, but with an additional `data-setup` attribute. At a minimum, this attribute must have a value of `'{}'`, but it can include any Video.js [options][options] - just make sure it contains valid JSON!
|
||||
|
||||
```html
|
||||
<video
|
||||
id="my-player"
|
||||
class="video-js"
|
||||
controls
|
||||
preload="auto"
|
||||
poster="//vjs.zencdn.net/v/oceans.png"
|
||||
data-setup='{}'>
|
||||
<source src="//vjs.zencdn.net/v/oceans.mp4" type="video/mp4"></source>
|
||||
<source src="//vjs.zencdn.net/v/oceans.webm" type="video/webm"></source>
|
||||
<source src="//vjs.zencdn.net/v/oceans.ogv" type="video/ogg"></source>
|
||||
<p class="vjs-no-js">
|
||||
To view this video please enable JavaScript, and consider upgrading to a
|
||||
web browser that
|
||||
<a href="https://videojs.com/html5-video-support/" target="_blank">
|
||||
supports HTML5 video
|
||||
</a>
|
||||
</p>
|
||||
</video>
|
||||
```
|
||||
|
||||
When the page loads, Video.js will find this element and automatically setup a player in its place.
|
||||
|
||||
If you don't want to use automatic setup, you can leave off the `data-setup` attribute and initialize a `<video>` element manually using the `videojs` function:
|
||||
|
||||
```js
|
||||
var player = videojs('my-player');
|
||||
```
|
||||
|
||||
The `videojs` function also accepts an `options` object and a callback to be invoked
|
||||
when the player is ready:
|
||||
|
||||
```js
|
||||
var options = {};
|
||||
|
||||
var player = videojs('my-player', options, function onPlayerReady() {
|
||||
videojs.log('Your player is ready!');
|
||||
|
||||
// In this context, `this` is the player that was created by Video.js.
|
||||
this.play();
|
||||
|
||||
// How about an event listener?
|
||||
this.on('ended', function() {
|
||||
videojs.log('Awww...over so soon?!');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
If you're ready to dive in, the [Getting Started][getting-started] page and [documentation][docs] are the best places to go for more information. If you get stuck, head over to our [Slack channel][slack-link]!
|
||||
|
||||
## Contributing
|
||||
|
||||
Video.js is a free and open source library, and we appreciate any help you're willing to give - whether it's fixing bugs, improving documentation, or suggesting new features. Check out the [contributing guide][contributing] for more!
|
||||
|
||||
_Video.js uses [BrowserStack][browserstack] for compatibility testing._
|
||||
|
||||
## [Code of Conduct][coc]
|
||||
|
||||
Please note that this project is released with a [Contributor Code of Conduct][coc]. By participating in this project you agree to abide by its terms.
|
||||
|
||||
## [License][license]
|
||||
|
||||
Video.js is [licensed][license] under the Apache License, Version 2.0.
|
||||
|
||||
[browserstack]: https://browserstack.com
|
||||
|
||||
[builtwith]: https://trends.builtwith.com/media/VideoJS
|
||||
|
||||
[contributing]: CONTRIBUTING.md
|
||||
|
||||
[coveralls-icon]: https://coveralls.io/repos/github/videojs/video.js/badge.svg?branch=main
|
||||
|
||||
[coveralls-link]: https://coveralls.io/github/videojs/video.js?branch=main
|
||||
|
||||
[docs]: https://docs.videojs.com
|
||||
|
||||
[fastly]: https://www.fastly.com/
|
||||
|
||||
[getting-started]: https://videojs.com/getting-started/
|
||||
|
||||
[license]: LICENSE
|
||||
|
||||
[logo]: https://videojs.com/logo-white.png
|
||||
|
||||
[npm-icon]: https://nodei.co/npm/video.js.png?downloads=true&downloadRank=true
|
||||
|
||||
[npm-link]: https://nodei.co/npm/video.js/
|
||||
|
||||
[options]: docs/guides/options.md
|
||||
|
||||
[plugins]: https://videojs.com/plugins/
|
||||
|
||||
[slack-icon]: http://slack.videojs.com/badge.svg
|
||||
|
||||
[slack-link]: http://slack.videojs.com
|
||||
|
||||
[travis-icon]: https://travis-ci.org/videojs/video.js.svg?branch=main
|
||||
|
||||
[travis-link]: https://travis-ci.org/videojs/video.js
|
||||
|
||||
[vjs]: https://videojs.com
|
||||
|
||||
[coc]: CODE_OF_CONDUCT.md
|
28655
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/core.es.js
generated
vendored
Normal file
28671
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/core.js
generated
vendored
Normal file
1770
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video-js-cdn.css
generated
vendored
Normal file
1
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video-js-cdn.min.css
generated
vendored
Normal file
31224
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video.core.js
generated
vendored
Normal file
20
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video.core.min.js
generated
vendored
Normal file
29351
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video.core.novtt.js
generated
vendored
Normal file
20
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video.core.novtt.min.js
generated
vendored
Normal file
67525
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video.debug.js
generated
vendored
Normal file
65649
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video.novtt.js
generated
vendored
Normal file
26
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/alt/video.novtt.min.js
generated
vendored
Normal file
330
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/captions.ar.vtt
generated
vendored
Normal file
|
@ -0,0 +1,330 @@
|
|||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.042 --> 00:00:18.625
|
||||
...إلى... إلى الشمال يمكن أن نرى
|
||||
...يمكن أن نرى الـ
|
||||
|
||||
2
|
||||
00:00:18.750 --> 00:00:20.958
|
||||
...إلى اليمين يمكن أن نرى الـ
|
||||
|
||||
3
|
||||
00:00:21.000 --> 00:00:23.125
|
||||
طاحنات الرؤوس...
|
||||
|
||||
4
|
||||
00:00:23.208 --> 00:00:25.208
|
||||
كل شيئ آمن
|
||||
آمن كلية
|
||||
|
||||
5
|
||||
00:00:26.333 --> 00:00:28.333
|
||||
إيمو ؟
|
||||
|
||||
6
|
||||
00:00:28.875 --> 00:00:30.958
|
||||
! حذاري
|
||||
|
||||
7
|
||||
00:00:47.125 --> 00:00:49.167
|
||||
هل أصبت ؟
|
||||
|
||||
8
|
||||
00:00:52.125 --> 00:00:54.833
|
||||
...لا أظن ذلك
|
||||
وأنت ؟
|
||||
|
||||
9
|
||||
00:00:55.625 --> 00:00:57.625
|
||||
أنا بخير
|
||||
|
||||
10
|
||||
00:00:57.667 --> 00:01:01.667
|
||||
،قم يا إيمو
|
||||
المكان هنا غير آمن
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:04.083
|
||||
لنذهب
|
||||
|
||||
12
|
||||
00:01:04.167 --> 00:01:06.167
|
||||
وماذا بعد ؟
|
||||
|
||||
13
|
||||
00:01:06.167 --> 00:01:08.583
|
||||
...سترى... سترى
|
||||
|
||||
14
|
||||
00:01:16.167 --> 00:01:18.375
|
||||
إيمو، من هنا
|
||||
|
||||
15
|
||||
00:01:34.958 --> 00:01:37.000
|
||||
! إتبعني
|
||||
|
||||
16
|
||||
00:02:11.125 --> 00:02:13.625
|
||||
! أسرع يا إيمو
|
||||
|
||||
17
|
||||
00:02:48.375 --> 00:02:50.375
|
||||
! لست منتبها
|
||||
|
||||
18
|
||||
00:02:50.750 --> 00:02:54.500
|
||||
...أريد فقط أن أجيب الـ
|
||||
الهاتف...
|
||||
|
||||
19
|
||||
00:02:55.000 --> 00:02:58.500
|
||||
،إيمو، أنظر
|
||||
أقصد أنصت
|
||||
|
||||
20
|
||||
00:02:59.750 --> 00:03:03.292
|
||||
عليك أن تتعلم الإصغاء
|
||||
|
||||
21
|
||||
00:03:03.625 --> 00:03:05.917
|
||||
هذا ليس ضربا من اللهو
|
||||
|
||||
22
|
||||
00:03:06.083 --> 00:03:09.958
|
||||
...إنك
|
||||
أقصد إننا قد نموت بسهولة في هذا المكان
|
||||
|
||||
23
|
||||
00:03:10.208 --> 00:03:14.125
|
||||
...أنصت
|
||||
أنصت إلى أصوات الآلة
|
||||
|
||||
24
|
||||
00:03:18.333 --> 00:03:20.417
|
||||
أنصت إلى نَفَسِك
|
||||
|
||||
25
|
||||
00:04:27.208 --> 00:04:29.250
|
||||
ألا تمل أبدا من هذا ؟
|
||||
|
||||
26
|
||||
00:04:29.583 --> 00:04:31.583
|
||||
أمل ؟!؟
|
||||
نعم -
|
||||
|
||||
27
|
||||
00:04:31.750 --> 00:04:34.667
|
||||
إيمو؛ الآلة في دقتها... مثل الساعة
|
||||
|
||||
28
|
||||
00:04:35.500 --> 00:04:37.708
|
||||
...حركة ناشزة واحدة قد
|
||||
|
||||
29
|
||||
00:04:37.833 --> 00:04:39.875
|
||||
تطرحك معجونا
|
||||
|
||||
30
|
||||
00:04:41.042 --> 00:04:43.083
|
||||
...أو ليست
|
||||
|
||||
31
|
||||
00:04:43.125 --> 00:04:46.542
|
||||
! عجينة يا إيمو
|
||||
أ هذا ما تريد ؟ أن تصبح عجينة ؟
|
||||
|
||||
32
|
||||
00:04:48.083 --> 00:04:50.083
|
||||
أيمو، أ هذا هدفك في الحياة ؟
|
||||
|
||||
33
|
||||
00:04:50.583 --> 00:04:52.667
|
||||
أن تصير عجينة ؟
|
||||
|
||||
34
|
||||
00:05:41.833 --> 00:05:43.875
|
||||
إيمو، أغمض عينيك
|
||||
|
||||
35
|
||||
00:05:44.917 --> 00:05:47.000
|
||||
لماذا ؟
|
||||
! الآن -
|
||||
|
||||
36
|
||||
00:05:53.750 --> 00:05:56.042
|
||||
حسن
|
||||
|
||||
37
|
||||
00:05:59.542 --> 00:06:02.792
|
||||
ماذا ترى إلى شمالك يا إيمو ؟
|
||||
|
||||
38
|
||||
00:06:04.417 --> 00:06:06.500
|
||||
لا شيئ
|
||||
حقا ؟ -
|
||||
|
||||
39
|
||||
00:06:06.542 --> 00:06:08.625
|
||||
لا، لا شيئ البتة
|
||||
|
||||
40
|
||||
00:06:08.625 --> 00:06:12.417
|
||||
وماذا ترى إلى جهتك اليمنى يا إيمو ؟
|
||||
|
||||
41
|
||||
00:06:13.667 --> 00:06:17.833
|
||||
،نفس الشيئ يا بروغ
|
||||
! نفس الشيئ بالضبط؛ لا شيئ
|
||||
|
||||
42
|
||||
00:06:17.875 --> 00:06:19.917
|
||||
عظيم
|
||||
|
||||
43
|
||||
00:06:40.625 --> 00:06:42.958
|
||||
أنصت يا بروغ ! هل تسمع ذلك ؟
|
||||
|
||||
44
|
||||
00:06:43.625 --> 00:06:45.625
|
||||
هل نستطيع الذهاب إلى هناك ؟
|
||||
|
||||
45
|
||||
00:06:45.708 --> 00:06:47.792
|
||||
هناك ؟
|
||||
نعم -
|
||||
|
||||
46
|
||||
00:06:47.833 --> 00:06:49.833
|
||||
إنه غير آمن يا إيمو
|
||||
|
||||
47
|
||||
00:06:49.917 --> 00:06:52.500
|
||||
صدقني، إنه غير آمن
|
||||
|
||||
48
|
||||
00:06:53.292 --> 00:06:55.375
|
||||
...لكن لعلي أستطيع
|
||||
|
||||
49
|
||||
00:06:55.417 --> 00:06:57.417
|
||||
...لكن
|
||||
! لا -
|
||||
|
||||
50
|
||||
00:06:57.667 --> 00:06:59.667
|
||||
! لا
|
||||
|
||||
51
|
||||
00:07:00.875 --> 00:07:03.750
|
||||
هل من أسئلة أخرى يا إيمو ؟
|
||||
|
||||
52
|
||||
00:07:04.250 --> 00:07:06.333
|
||||
لا
|
||||
|
||||
53
|
||||
00:07:09.458 --> 00:07:11.542
|
||||
...إيمو
|
||||
نعم -
|
||||
|
||||
54
|
||||
00:07:11.875 --> 00:07:13.958
|
||||
...لماذا يا إيمو... لماذا
|
||||
|
||||
55
|
||||
00:07:15.292 --> 00:07:18.792
|
||||
لماذا لا تستطيع أن ترى حُسْن هذا المكان
|
||||
|
||||
56
|
||||
00:07:18.833 --> 00:07:20.833
|
||||
...والطريقة التي يعمل بها
|
||||
|
||||
57
|
||||
00:07:20.875 --> 00:07:24.000
|
||||
وكيف... وكيف أنه غاية في الكمال
|
||||
|
||||
58
|
||||
00:07:24.083 --> 00:07:27.417
|
||||
! لا يا بروغ، لا أرى ذلك
|
||||
|
||||
59
|
||||
00:07:27.542 --> 00:07:30.333
|
||||
لا أرى ذلك لأنه لا يوجد شيئ هناك
|
||||
|
||||
60
|
||||
00:07:31.500 --> 00:07:35.333
|
||||
ثم لماذا يجب علي أن أسلم حياتي
|
||||
لشيئ لا وجود له ؟
|
||||
|
||||
61
|
||||
00:07:35.583 --> 00:07:37.625
|
||||
هل يمكنك أن تخبرني ؟
|
||||
|
||||
62
|
||||
00:07:37.708 --> 00:07:39.750
|
||||
! أجبني
|
||||
|
||||
63
|
||||
00:07:43.208 --> 00:07:47.333
|
||||
...بروغ
|
||||
! أنت معتوه يا هذا
|
||||
|
||||
64
|
||||
00:07:47.375 --> 00:07:49.417
|
||||
! إبعد عني
|
||||
|
||||
65
|
||||
00:07:52.583 --> 00:07:55.083
|
||||
! لا يا إيمو ! إنه فخ
|
||||
|
||||
66
|
||||
00:07:55.833 --> 00:07:57.875
|
||||
...إنه فخ
|
||||
|
||||
67
|
||||
00:07:57.917 --> 00:08:01.750
|
||||
إلى جنبك الأيسر يمكنك أن ترى
|
||||
حدائق بابل المعلقة
|
||||
|
||||
68
|
||||
00:08:02.250 --> 00:08:04.292
|
||||
هل تعجبك كفخ ؟
|
||||
|
||||
69
|
||||
00:08:05.458 --> 00:08:07.542
|
||||
لا يا أيمو
|
||||
|
||||
70
|
||||
00:08:09.417 --> 00:08:12.792
|
||||
...إلى جنبك الأيمن يمكنك رؤية
|
||||
حزر ماذا ؟
|
||||
|
||||
71
|
||||
00:08:13.000 --> 00:08:15.042
|
||||
! عملاق رودس
|
||||
|
||||
72
|
||||
00:08:15.125 --> 00:08:16.417
|
||||
! لا
|
||||
|
||||
73
|
||||
00:08:16.458 --> 00:08:20.500
|
||||
،عملاق رودس
|
||||
وهو هنا خصيصا من أجلك يا بروغ
|
||||
|
||||
74
|
||||
00:08:20.583 --> 00:08:22.583
|
||||
فقط من أجلك
|
||||
|
||||
75
|
||||
00:08:51.333 --> 00:08:53.375
|
||||
إنه هناك
|
||||
|
||||
76
|
||||
00:08:53.417 --> 00:08:55.500
|
||||
أنا أؤكد لك... إيمو
|
||||
|
||||
77
|
||||
00:08:57.333 --> 00:09:00.000
|
||||
...إنه
|
334
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/captions.en.vtt
generated
vendored
Normal file
|
@ -0,0 +1,334 @@
|
|||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.000 --> 00:00:17.951
|
||||
At the left we can see...
|
||||
|
||||
2
|
||||
00:00:18.166 --> 00:00:20.083
|
||||
At the right we can see the...
|
||||
|
||||
3
|
||||
00:00:20.119 --> 00:00:21.962
|
||||
...the head-snarlers
|
||||
|
||||
4
|
||||
00:00:21.999 --> 00:00:24.368
|
||||
Everything is safe.
|
||||
Perfectly safe.
|
||||
|
||||
5
|
||||
00:00:24.582 --> 00:00:27.035
|
||||
Emo?
|
||||
|
||||
6
|
||||
00:00:28.206 --> 00:00:29.996
|
||||
Watch out!
|
||||
|
||||
7
|
||||
00:00:47.037 --> 00:00:48.494
|
||||
Are you hurt?
|
||||
|
||||
8
|
||||
00:00:51.994 --> 00:00:53.949
|
||||
I don't think so.
|
||||
You?
|
||||
|
||||
9
|
||||
00:00:55.160 --> 00:00:56.985
|
||||
I'm Ok.
|
||||
|
||||
10
|
||||
00:00:57.118 --> 00:01:01.111
|
||||
Get up.
|
||||
Emo. it's not safe here.
|
||||
|
||||
11
|
||||
00:01:02.034 --> 00:01:03.573
|
||||
Let's go.
|
||||
|
||||
12
|
||||
00:01:03.610 --> 00:01:05.114
|
||||
What's next?
|
||||
|
||||
13
|
||||
00:01:05.200 --> 00:01:09.146
|
||||
You'll see!
|
||||
|
||||
14
|
||||
00:01:16.032 --> 00:01:18.022
|
||||
Emo.
|
||||
This way.
|
||||
|
||||
15
|
||||
00:01:34.237 --> 00:01:35.481
|
||||
Follow me!
|
||||
|
||||
16
|
||||
00:02:11.106 --> 00:02:12.480
|
||||
Hurry Emo!
|
||||
|
||||
17
|
||||
00:02:48.059 --> 00:02:49.930
|
||||
You're not paying attention!
|
||||
|
||||
18
|
||||
00:02:50.142 --> 00:02:54.052
|
||||
I just want to answer the...
|
||||
...phone.
|
||||
|
||||
19
|
||||
00:02:54.974 --> 00:02:57.972
|
||||
Emo. look.
|
||||
I mean listen.
|
||||
|
||||
20
|
||||
00:02:59.140 --> 00:03:02.008
|
||||
You have to learn to listen.
|
||||
|
||||
21
|
||||
00:03:03.140 --> 00:03:04.965
|
||||
This is not some game.
|
||||
|
||||
22
|
||||
00:03:05.056 --> 00:03:09.345
|
||||
You. I mean we.
|
||||
we could easily die out here.
|
||||
|
||||
23
|
||||
00:03:10.014 --> 00:03:13.959
|
||||
Listen.
|
||||
listen to the sounds of the machine.
|
||||
|
||||
24
|
||||
00:03:18.054 --> 00:03:20.009
|
||||
Listen to your breathing.
|
||||
|
||||
25
|
||||
00:04:27.001 --> 00:04:28.956
|
||||
Well. don't you ever get tired of this?
|
||||
|
||||
26
|
||||
00:04:29.084 --> 00:04:30.909
|
||||
Tired?!?
|
||||
|
||||
27
|
||||
00:04:31.126 --> 00:04:34.491
|
||||
Emo. the machine is like clockwork.
|
||||
|
||||
28
|
||||
00:04:35.083 --> 00:04:37.074
|
||||
One move out of place...
|
||||
|
||||
29
|
||||
00:04:37.166 --> 00:04:39.121
|
||||
...and you're ground to a pulp.
|
||||
|
||||
30
|
||||
00:04:40.958 --> 00:04:42.004
|
||||
But isn't it -
|
||||
|
||||
31
|
||||
00:04:42.041 --> 00:04:46.034
|
||||
Pulp. Emo!
|
||||
Is that what you want. pulp?
|
||||
|
||||
32
|
||||
00:04:47.040 --> 00:04:48.995
|
||||
Emo. your goal in life...
|
||||
|
||||
33
|
||||
00:04:50.081 --> 00:04:51.953
|
||||
...pulp?
|
||||
|
||||
34
|
||||
00:05:41.156 --> 00:05:43.028
|
||||
Emo. close your eyes.
|
||||
|
||||
35
|
||||
00:05:44.156 --> 00:05:46.027
|
||||
Why?
|
||||
- Now!
|
||||
|
||||
36
|
||||
00:05:51.155 --> 00:05:52.102
|
||||
Ok.
|
||||
|
||||
37
|
||||
00:05:53.113 --> 00:05:54.688
|
||||
Good.
|
||||
|
||||
38
|
||||
00:05:59.070 --> 00:06:02.103
|
||||
What do you see at your left side. Emo?
|
||||
|
||||
39
|
||||
00:06:04.028 --> 00:06:05.899
|
||||
Nothing.
|
||||
- Really?
|
||||
|
||||
40
|
||||
00:06:06.027 --> 00:06:07.105
|
||||
No. nothing at all.
|
||||
|
||||
41
|
||||
00:06:07.944 --> 00:06:11.984
|
||||
And at your right.
|
||||
what do you see at your right side. Emo?
|
||||
|
||||
42
|
||||
00:06:13.151 --> 00:06:16.102
|
||||
The same Proog. exactly the same...
|
||||
|
||||
43
|
||||
00:06:16.942 --> 00:06:19.098
|
||||
...nothing!
|
||||
- Great.
|
||||
|
||||
44
|
||||
00:06:40.105 --> 00:06:42.724
|
||||
Listen Proog! Do you hear that!
|
||||
|
||||
45
|
||||
00:06:43.105 --> 00:06:44.894
|
||||
Can we go here?
|
||||
|
||||
46
|
||||
00:06:44.979 --> 00:06:47.894
|
||||
There?
|
||||
It isn't safe. Emo.
|
||||
|
||||
47
|
||||
00:06:49.145 --> 00:06:52.013
|
||||
But...
|
||||
- Trust me. it's not.
|
||||
|
||||
48
|
||||
00:06:53.020 --> 00:06:54.145
|
||||
Maybe I could...
|
||||
|
||||
49
|
||||
00:06:54.181 --> 00:06:55.969
|
||||
No.
|
||||
|
||||
50
|
||||
00:06:57.102 --> 00:06:59.934
|
||||
NO!
|
||||
|
||||
51
|
||||
00:07:00.144 --> 00:07:03.058
|
||||
Any further questions. Emo?
|
||||
|
||||
52
|
||||
00:07:03.976 --> 00:07:05.090
|
||||
No.
|
||||
|
||||
53
|
||||
00:07:09.059 --> 00:07:10.089
|
||||
Emo?
|
||||
|
||||
54
|
||||
00:07:11.142 --> 00:07:13.058
|
||||
Emo. why...
|
||||
|
||||
55
|
||||
00:07:13.095 --> 00:07:14.022
|
||||
Emo...
|
||||
|
||||
56
|
||||
00:07:14.058 --> 00:07:18.003
|
||||
...why can't you see
|
||||
the beauty of this place?
|
||||
|
||||
57
|
||||
00:07:18.141 --> 00:07:20.048
|
||||
The way it works.
|
||||
|
||||
58
|
||||
00:07:20.140 --> 00:07:23.895
|
||||
How perfect it is.
|
||||
|
||||
59
|
||||
00:07:23.932 --> 00:07:26.964
|
||||
No. Proog. I don't see.
|
||||
|
||||
60
|
||||
00:07:27.056 --> 00:07:29.970
|
||||
I don't see because there's nothing there.
|
||||
|
||||
61
|
||||
00:07:31.055 --> 00:07:34.965
|
||||
And why should I trust my
|
||||
life to something that isn't there?
|
||||
|
||||
62
|
||||
00:07:35.055 --> 00:07:36.926
|
||||
Well can you tell me that?
|
||||
|
||||
63
|
||||
00:07:37.054 --> 00:07:38.926
|
||||
Answer me!
|
||||
|
||||
64
|
||||
00:07:42.970 --> 00:07:44.000
|
||||
Proog...
|
||||
|
||||
65
|
||||
00:07:45.053 --> 00:07:46.985
|
||||
...you're a sick man!
|
||||
|
||||
66
|
||||
00:07:47.022 --> 00:07:48.918
|
||||
Stay away from me!
|
||||
|
||||
67
|
||||
00:07:52.052 --> 00:07:54.884
|
||||
No! Emo! It's a trap!
|
||||
|
||||
68
|
||||
00:07:55.135 --> 00:07:56.931
|
||||
Hah. it's a trap.
|
||||
|
||||
69
|
||||
00:07:56.968 --> 00:08:01.043
|
||||
At the left side you can see
|
||||
the hanging gardens of Babylon!
|
||||
|
||||
70
|
||||
00:08:01.967 --> 00:08:03.957
|
||||
How's that for a trap?
|
||||
|
||||
71
|
||||
00:08:05.050 --> 00:08:06.922
|
||||
No. Emo.
|
||||
|
||||
72
|
||||
00:08:09.008 --> 00:08:12.088
|
||||
At the right side you can see...
|
||||
...well guess what...
|
||||
|
||||
73
|
||||
00:08:12.924 --> 00:08:14.665
|
||||
...the colossus of Rhodes!
|
||||
|
||||
74
|
||||
00:08:15.132 --> 00:08:16.053
|
||||
No!
|
||||
|
||||
75
|
||||
00:08:16.090 --> 00:08:21.919
|
||||
The colossus of Rhodes
|
||||
and it is here just for you Proog.
|
||||
|
||||
76
|
||||
00:08:51.001 --> 00:08:52.923
|
||||
It is there...
|
||||
|
||||
77
|
||||
00:08:52.959 --> 00:08:56.040
|
||||
I'm telling you.
|
||||
Emo...
|
||||
|
||||
78
|
||||
00:08:57.000 --> 00:08:59.867
|
||||
...it is.
|
326
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/captions.ja.vtt
generated
vendored
Normal file
|
@ -0,0 +1,326 @@
|
|||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.042 --> 00:00:18.042
|
||||
左に見えるのは…
|
||||
|
||||
2
|
||||
00:00:18.750 --> 00:00:20.333
|
||||
右に見えるのは…
|
||||
|
||||
3
|
||||
00:00:20.417 --> 00:00:21.917
|
||||
…首刈り機
|
||||
|
||||
4
|
||||
00:00:22.000 --> 00:00:24.625
|
||||
すべて安全
|
||||
完璧に安全だ
|
||||
|
||||
5
|
||||
00:00:26.333 --> 00:00:27.333
|
||||
イーモ?
|
||||
|
||||
6
|
||||
00:00:28.875 --> 00:00:30.250
|
||||
危ない!
|
||||
|
||||
7
|
||||
00:00:47.125 --> 00:00:48.250
|
||||
ケガはないか?
|
||||
|
||||
8
|
||||
00:00:51.917 --> 00:00:53.917
|
||||
ええ、多分…
|
||||
あなたは?
|
||||
|
||||
9
|
||||
00:00:55.625 --> 00:00:57.125
|
||||
わしは平気だ
|
||||
|
||||
10
|
||||
00:00:57.583 --> 00:01:01.667
|
||||
起きてくれイーモ
|
||||
ここは危ない
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:03.667
|
||||
行こう
|
||||
|
||||
12
|
||||
00:01:03.750 --> 00:01:04.917
|
||||
どこに?
|
||||
|
||||
13
|
||||
00:01:05.875 --> 00:01:07.875
|
||||
すぐにわかるさ!
|
||||
|
||||
14
|
||||
00:01:16.167 --> 00:01:18.375
|
||||
イーモ、こっちだ
|
||||
|
||||
15
|
||||
00:01:34.958 --> 00:01:36.958
|
||||
ついて来るんだ!
|
||||
|
||||
16
|
||||
00:02:11.583 --> 00:02:12.792
|
||||
イーモ、早く!
|
||||
|
||||
17
|
||||
00:02:48.375 --> 00:02:50.083
|
||||
むやみにさわるな!
|
||||
|
||||
18
|
||||
00:02:50.750 --> 00:02:54.500
|
||||
僕はただ、電話に
|
||||
…出ようと
|
||||
|
||||
19
|
||||
00:02:55.000 --> 00:02:58.208
|
||||
イーモ、見るんだ…
|
||||
いや、聞いてくれ
|
||||
|
||||
20
|
||||
00:02:59.750 --> 00:03:02.292
|
||||
君は「聞き方」を知る必要がある
|
||||
|
||||
21
|
||||
00:03:03.625 --> 00:03:05.125
|
||||
これは遊びじゃない
|
||||
|
||||
22
|
||||
00:03:06.167 --> 00:03:10.417
|
||||
我々はここでは
|
||||
たやすく死ぬ
|
||||
|
||||
23
|
||||
00:03:11.208 --> 00:03:14.125
|
||||
機械の声を聞くんだ
|
||||
|
||||
24
|
||||
00:03:18.333 --> 00:03:22.417
|
||||
君の息づかいを聞くんだ
|
||||
|
||||
25
|
||||
00:04:27.208 --> 00:04:29.250
|
||||
そんなことして疲れない?
|
||||
|
||||
26
|
||||
00:04:29.583 --> 00:04:31.083
|
||||
疲れる?!
|
||||
|
||||
27
|
||||
00:04:31.750 --> 00:04:34.667
|
||||
この機械は非常に正確で
|
||||
|
||||
28
|
||||
00:04:35.500 --> 00:04:37.708
|
||||
一つ間違えば…
|
||||
|
||||
29
|
||||
00:04:37.833 --> 00:04:40.792
|
||||
…地面に落ちてバラバラだ
|
||||
|
||||
30
|
||||
00:04:41.042 --> 00:04:42.375
|
||||
え、でも―
|
||||
|
||||
31
|
||||
00:04:42.417 --> 00:04:46.542
|
||||
バラバラだぞ、イーモ!
|
||||
それでいいのか?
|
||||
|
||||
32
|
||||
00:04:48.083 --> 00:04:50.000
|
||||
バラバラで死ぬんだぞ?
|
||||
|
||||
33
|
||||
00:04:50.583 --> 00:04:52.250
|
||||
バラバラだ!
|
||||
|
||||
34
|
||||
00:05:41.833 --> 00:05:43.458
|
||||
イーモ、目を閉じるんだ
|
||||
|
||||
35
|
||||
00:05:44.917 --> 00:05:46.583
|
||||
なぜ?
|
||||
―早く!
|
||||
|
||||
36
|
||||
00:05:53.750 --> 00:05:56.042
|
||||
それでいい
|
||||
|
||||
37
|
||||
00:05:59.542 --> 00:06:03.792
|
||||
左に見えるものは何だ、イーモ?
|
||||
|
||||
38
|
||||
00:06:04.417 --> 00:06:06.000
|
||||
え…何も
|
||||
―本当か?
|
||||
|
||||
39
|
||||
00:06:06.333 --> 00:06:07.917
|
||||
全く何も
|
||||
|
||||
40
|
||||
00:06:08.042 --> 00:06:12.833
|
||||
では右は
|
||||
何か見えるか、イーモ?
|
||||
|
||||
41
|
||||
00:06:13.875 --> 00:06:16.917
|
||||
同じだよプルーグ、全く同じ…
|
||||
|
||||
42
|
||||
00:06:17.083 --> 00:06:18.583
|
||||
何もない!
|
||||
|
||||
43
|
||||
00:06:40.625 --> 00:06:43.208
|
||||
プルーグ!何か聞こえない?
|
||||
|
||||
44
|
||||
00:06:43.625 --> 00:06:45.042
|
||||
あそこに行かないか?
|
||||
|
||||
45
|
||||
00:06:45.208 --> 00:06:48.042
|
||||
あそこ?
|
||||
…安全じゃない
|
||||
|
||||
46
|
||||
00:06:49.917 --> 00:06:52.500
|
||||
でも…
|
||||
―本当に危ないぞ
|
||||
|
||||
47
|
||||
00:06:53.292 --> 00:06:54.792
|
||||
大丈夫だよ…
|
||||
|
||||
48
|
||||
00:06:54.833 --> 00:06:56.333
|
||||
だめだ
|
||||
|
||||
49
|
||||
00:06:57.667 --> 00:07:00.167
|
||||
だめだ!
|
||||
|
||||
50
|
||||
00:07:00.875 --> 00:07:03.750
|
||||
まだ続ける気か、イーモ?
|
||||
|
||||
51
|
||||
00:07:04.250 --> 00:07:05.917
|
||||
いいえ…
|
||||
|
||||
52
|
||||
00:07:09.458 --> 00:07:10.833
|
||||
イーモ?
|
||||
|
||||
53
|
||||
00:07:11.875 --> 00:07:13.542
|
||||
イーモ、なぜ…
|
||||
|
||||
54
|
||||
00:07:13.583 --> 00:07:14.458
|
||||
イーモ…
|
||||
|
||||
55
|
||||
00:07:14.500 --> 00:07:18.500
|
||||
…なぜここの美しさが
|
||||
見えない?
|
||||
|
||||
56
|
||||
00:07:18.833 --> 00:07:20.750
|
||||
仕組みがこんなに…
|
||||
|
||||
57
|
||||
00:07:20.875 --> 00:07:24.000
|
||||
こんなに完全なのに
|
||||
|
||||
58
|
||||
00:07:24.083 --> 00:07:27.417
|
||||
もういいよ!プルーグ!
|
||||
|
||||
59
|
||||
00:07:27.542 --> 00:07:30.333
|
||||
そこには何もないんだから
|
||||
|
||||
60
|
||||
00:07:31.500 --> 00:07:35.333
|
||||
なぜ命を「ない」物に
|
||||
ゆだねなきゃ?
|
||||
|
||||
61
|
||||
00:07:35.583 --> 00:07:37.125
|
||||
教えてくれないか?
|
||||
|
||||
62
|
||||
00:07:37.500 --> 00:07:39.167
|
||||
さあ!
|
||||
|
||||
63
|
||||
00:07:43.208 --> 00:07:44.583
|
||||
プルーグ…
|
||||
|
||||
64
|
||||
00:07:45.500 --> 00:07:47.333
|
||||
あなたは病気なんだ
|
||||
|
||||
65
|
||||
00:07:47.375 --> 00:07:49.208
|
||||
僕から離れてくれ
|
||||
|
||||
66
|
||||
00:07:52.583 --> 00:07:55.083
|
||||
いかん!イーモ!ワナだ!
|
||||
|
||||
67
|
||||
00:07:55.833 --> 00:07:57.167
|
||||
ワナだ? ふーん
|
||||
|
||||
68
|
||||
00:07:57.208 --> 00:08:01.750
|
||||
左に何が見える?
|
||||
バビロンの空中庭園!
|
||||
|
||||
69
|
||||
00:08:02.250 --> 00:08:04.292
|
||||
これがワナとでも?
|
||||
|
||||
70
|
||||
00:08:05.458 --> 00:08:07.125
|
||||
だめだ、イーモ
|
||||
|
||||
71
|
||||
00:08:09.417 --> 00:08:12.792
|
||||
右にあるのは…
|
||||
…すごい!…
|
||||
|
||||
72
|
||||
00:08:13.000 --> 00:08:14.750
|
||||
…ロードス島の巨像だ!
|
||||
|
||||
73
|
||||
00:08:15.833 --> 00:08:16.708
|
||||
やめろ!
|
||||
|
||||
74
|
||||
00:08:16.750 --> 00:08:22.167
|
||||
この巨像はあなたの物
|
||||
プルーグ、あなたのだよ
|
||||
|
||||
75
|
||||
00:08:51.333 --> 00:08:53.167
|
||||
いってるじゃないか…
|
||||
|
||||
76
|
||||
00:08:53.208 --> 00:08:55.500
|
||||
そこにあるって、イーモ…
|
||||
|
||||
77
|
||||
00:08:57.333 --> 00:09:00.000
|
||||
…あるって
|
356
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/captions.ru.vtt
generated
vendored
Normal file
|
@ -0,0 +1,356 @@
|
|||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:14.958 --> 00:00:17.833
|
||||
Слева мы видим...
|
||||
|
||||
2
|
||||
00:00:18.458 --> 00:00:20.208
|
||||
справа мы видим...
|
||||
|
||||
3
|
||||
00:00:20.333 --> 00:00:21.875
|
||||
...голово-клацов.
|
||||
|
||||
4
|
||||
00:00:22.000 --> 00:00:24.583
|
||||
всё в порядке.
|
||||
в полном порядке.
|
||||
|
||||
5
|
||||
00:00:26.333 --> 00:00:27.333
|
||||
Имо?
|
||||
|
||||
6
|
||||
00:00:28.833 --> 00:00:30.250
|
||||
Осторожно!
|
||||
|
||||
7
|
||||
00:00:47.125 --> 00:00:48.250
|
||||
Ты не ранен?
|
||||
|
||||
8
|
||||
00:00:51.875 --> 00:00:53.875
|
||||
Вроде нет...
|
||||
а ты?
|
||||
|
||||
9
|
||||
00:00:55.583 --> 00:00:57.125
|
||||
Я в порядке.
|
||||
|
||||
10
|
||||
00:00:57.542 --> 00:01:01.625
|
||||
Вставай.
|
||||
Имо. здесь не безопасно.
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:03.625
|
||||
Пойдём.
|
||||
|
||||
12
|
||||
00:01:03.708 --> 00:01:05.708
|
||||
Что дальше?
|
||||
|
||||
13
|
||||
00:01:05.833 --> 00:01:07.833
|
||||
Ты увидишь!
|
||||
|
||||
14
|
||||
00:01:08.000 --> 00:01:08.833
|
||||
Ты увидишь...
|
||||
|
||||
15
|
||||
00:01:16.167 --> 00:01:18.375
|
||||
Имо. сюда.
|
||||
|
||||
16
|
||||
00:01:34.917 --> 00:01:35.750
|
||||
За мной!
|
||||
|
||||
17
|
||||
00:02:11.542 --> 00:02:12.750
|
||||
Имо. быстрее!
|
||||
|
||||
18
|
||||
00:02:48.375 --> 00:02:50.083
|
||||
Ты не обращаешь внимания!
|
||||
|
||||
19
|
||||
00:02:50.708 --> 00:02:54.500
|
||||
Я только хотел ответить на ...
|
||||
...звонок.
|
||||
|
||||
20
|
||||
00:02:55.000 --> 00:02:58.208
|
||||
Имо. смотри.
|
||||
то есть слушай...
|
||||
|
||||
21
|
||||
00:02:59.708 --> 00:03:02.292
|
||||
Ты должен учиться слушать.
|
||||
|
||||
22
|
||||
00:03:03.250 --> 00:03:05.333
|
||||
Это не какая-нибудь игра.
|
||||
|
||||
23
|
||||
00:03:06.000 --> 00:03:08.833
|
||||
Ты. вернее мы. легко можем погибнуть здесь.
|
||||
|
||||
24
|
||||
00:03:10.000 --> 00:03:11.167
|
||||
Слушай...
|
||||
|
||||
25
|
||||
00:03:11.667 --> 00:03:14.125
|
||||
слушай звуки машины.
|
||||
|
||||
26
|
||||
00:03:18.333 --> 00:03:20.417
|
||||
Слушай своё дыхание.
|
||||
|
||||
27
|
||||
00:04:27.208 --> 00:04:29.250
|
||||
И не надоест тебе это?
|
||||
|
||||
28
|
||||
00:04:29.542 --> 00:04:31.083
|
||||
Надоест?!?
|
||||
|
||||
29
|
||||
00:04:31.708 --> 00:04:34.625
|
||||
Имо! Машина -
|
||||
она как часовой механизм.
|
||||
|
||||
30
|
||||
00:04:35.500 --> 00:04:37.667
|
||||
Одно движение не туда...
|
||||
|
||||
31
|
||||
00:04:37.792 --> 00:04:39.750
|
||||
...и тебя размелют в месиво!
|
||||
|
||||
32
|
||||
00:04:41.042 --> 00:04:42.375
|
||||
А разве это не -
|
||||
|
||||
33
|
||||
00:04:42.417 --> 00:04:46.500
|
||||
Месиво. Имо!
|
||||
ты этого хочешь? месиво?
|
||||
|
||||
34
|
||||
00:04:48.083 --> 00:04:50.000
|
||||
Имо. твоя цель в жизни?
|
||||
|
||||
35
|
||||
00:04:50.542 --> 00:04:52.250
|
||||
Месиво!
|
||||
|
||||
36
|
||||
00:05:41.792 --> 00:05:43.458
|
||||
Имо. закрой глаза.
|
||||
|
||||
37
|
||||
00:05:44.875 --> 00:05:46.542
|
||||
Зачем?
|
||||
- Ну же!
|
||||
|
||||
38
|
||||
00:05:51.500 --> 00:05:52.333
|
||||
Ладно.
|
||||
|
||||
39
|
||||
00:05:53.708 --> 00:05:56.042
|
||||
Хорошо.
|
||||
|
||||
40
|
||||
00:05:59.500 --> 00:06:02.750
|
||||
Что ты видишь слева от себя. Имо?
|
||||
|
||||
41
|
||||
00:06:04.417 --> 00:06:06.000
|
||||
Ничего.
|
||||
- Точно?
|
||||
|
||||
42
|
||||
00:06:06.333 --> 00:06:07.875
|
||||
да. совсем ничего.
|
||||
|
||||
43
|
||||
00:06:08.042 --> 00:06:12.708
|
||||
А справа от себя.
|
||||
что ты видишь справа от себя. Имо?
|
||||
|
||||
44
|
||||
00:06:13.833 --> 00:06:16.875
|
||||
Да то же Пруг. в точности то же...
|
||||
|
||||
45
|
||||
00:06:17.042 --> 00:06:18.500
|
||||
Ничего!
|
||||
|
||||
46
|
||||
00:06:18.667 --> 00:06:19.500
|
||||
Прекрасно...
|
||||
|
||||
47
|
||||
00:06:40.583 --> 00:06:42.917
|
||||
Прислушайся. Пруг! Ты слышишь это?
|
||||
|
||||
48
|
||||
00:06:43.583 --> 00:06:45.042
|
||||
Может. мы пойдём туда?
|
||||
|
||||
49
|
||||
00:06:45.208 --> 00:06:48.042
|
||||
Туда?
|
||||
Это не безопасно. Имо.
|
||||
|
||||
50
|
||||
00:06:49.875 --> 00:06:52.500
|
||||
Но...
|
||||
- Поверь мне. это так.
|
||||
|
||||
51
|
||||
00:06:53.292 --> 00:06:54.750
|
||||
Может я бы ...
|
||||
|
||||
52
|
||||
00:06:54.792 --> 00:06:56.333
|
||||
Нет.
|
||||
|
||||
53
|
||||
00:06:57.625 --> 00:06:59.583
|
||||
- Но...
|
||||
- НЕТ!
|
||||
|
||||
54
|
||||
00:06:59.708 --> 00:07:00.833
|
||||
Нет!
|
||||
|
||||
55
|
||||
00:07:00.833 --> 00:07:03.708
|
||||
Ещё вопросы. Имо?
|
||||
|
||||
56
|
||||
00:07:04.250 --> 00:07:05.875
|
||||
Нет.
|
||||
|
||||
57
|
||||
00:07:09.458 --> 00:07:10.792
|
||||
Имо?
|
||||
|
||||
58
|
||||
00:07:11.833 --> 00:07:13.500
|
||||
Имо. почему...
|
||||
|
||||
59
|
||||
00:07:13.542 --> 00:07:14.458
|
||||
Имо...
|
||||
|
||||
60
|
||||
00:07:14.500 --> 00:07:18.500
|
||||
...почему? почему ты не видишь
|
||||
красоты этого места?
|
||||
|
||||
61
|
||||
00:07:18.792 --> 00:07:20.708
|
||||
То как оно работает.
|
||||
|
||||
62
|
||||
00:07:20.833 --> 00:07:24.000
|
||||
Как совершенно оно.
|
||||
|
||||
63
|
||||
00:07:24.083 --> 00:07:27.417
|
||||
Нет. Пруг. я не вижу.
|
||||
|
||||
64
|
||||
00:07:27.500 --> 00:07:30.333
|
||||
Я не вижу. потому что здесь ничего нет.
|
||||
|
||||
65
|
||||
00:07:31.375 --> 00:07:35.333
|
||||
И почему я должен доверять свою жизнь
|
||||
чему-то. чего здесь нет?
|
||||
|
||||
66
|
||||
00:07:35.542 --> 00:07:37.125
|
||||
это ты мне можешь сказать?
|
||||
|
||||
67
|
||||
00:07:37.500 --> 00:07:39.167
|
||||
Ответь мне!
|
||||
|
||||
68
|
||||
00:07:43.208 --> 00:07:44.542
|
||||
Пруг...
|
||||
|
||||
69
|
||||
00:07:45.500 --> 00:07:47.333
|
||||
Ты просто больной!
|
||||
|
||||
70
|
||||
00:07:47.375 --> 00:07:48.500
|
||||
Отстань от меня.
|
||||
|
||||
71
|
||||
00:07:48.625 --> 00:07:49.917
|
||||
Имо...
|
||||
|
||||
72
|
||||
00:07:52.542 --> 00:07:55.083
|
||||
Нет! Имо! Это ловушка!
|
||||
|
||||
73
|
||||
00:07:55.792 --> 00:07:57.167
|
||||
Это ловушка!
|
||||
|
||||
74
|
||||
00:07:57.208 --> 00:08:01.708
|
||||
Слева от себя вы можете увидеть
|
||||
Висящие сады Семирамиды!
|
||||
|
||||
75
|
||||
00:08:02.250 --> 00:08:04.292
|
||||
Сойдёт за ловушку?
|
||||
|
||||
76
|
||||
00:08:05.458 --> 00:08:07.125
|
||||
Нет. Имо.
|
||||
|
||||
77
|
||||
00:08:09.417 --> 00:08:12.750
|
||||
Справа от себя вы можете увидеть...
|
||||
...угадай кого...
|
||||
|
||||
78
|
||||
00:08:13.000 --> 00:08:14.708
|
||||
...Колосса Родосского!
|
||||
|
||||
79
|
||||
00:08:15.500 --> 00:08:16.625
|
||||
Нет!
|
||||
|
||||
80
|
||||
00:08:16.667 --> 00:08:21.125
|
||||
Колосс Родосский!
|
||||
И он здесь специально для тебя. Пруг.
|
||||
|
||||
81
|
||||
00:08:21.167 --> 00:08:22.208
|
||||
Специально для тебя...
|
||||
|
||||
82
|
||||
00:08:51.333 --> 00:08:53.167
|
||||
Она здесь есть!
|
||||
|
||||
83
|
||||
00:08:53.208 --> 00:08:55.500
|
||||
Говорю тебе.
|
||||
Имо...
|
||||
|
||||
84
|
||||
00:08:57.333 --> 00:09:00.000
|
||||
...она есть... есть...
|
349
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/captions.sv.vtt
generated
vendored
Normal file
|
@ -0,0 +1,349 @@
|
|||
WEBVTT
|
||||
|
||||
1
|
||||
00:00:15.042 --> 00:00:18.250
|
||||
Till vänster kan vi se...
|
||||
Ser vi...
|
||||
|
||||
2
|
||||
00:00:18.708 --> 00:00:20.333
|
||||
Till höger ser vi...
|
||||
|
||||
3
|
||||
00:00:20.417 --> 00:00:21.958
|
||||
...huvudkaparna.
|
||||
|
||||
4
|
||||
00:00:22.000 --> 00:00:24.792
|
||||
Allt är säkert.
|
||||
alldeles ofarligt.
|
||||
|
||||
5
|
||||
00:00:24.917 --> 00:00:26.833
|
||||
Emo?
|
||||
|
||||
6
|
||||
00:00:28.750 --> 00:00:30.167
|
||||
Se upp!
|
||||
|
||||
7
|
||||
00:00:46.708 --> 00:00:48.750
|
||||
Är du skadad?
|
||||
|
||||
8
|
||||
00:00:51.875 --> 00:00:54.458
|
||||
Jag tror inte det...
|
||||
Är du?
|
||||
|
||||
9
|
||||
00:00:55.292 --> 00:00:57.333
|
||||
Jag är ok.
|
||||
|
||||
10
|
||||
00:00:57.542 --> 00:01:01.625
|
||||
Res dig upp Emo.
|
||||
Det är inte säkert här.
|
||||
|
||||
11
|
||||
00:01:02.208 --> 00:01:03.625
|
||||
Kom så går vi.
|
||||
|
||||
12
|
||||
00:01:03.708 --> 00:01:05.708
|
||||
Vad nu då?
|
||||
|
||||
13
|
||||
00:01:05.833 --> 00:01:07.833
|
||||
Du får se...
|
||||
|
||||
14
|
||||
00:01:08.042 --> 00:01:10.417
|
||||
Du får se.
|
||||
|
||||
15
|
||||
00:01:15.958 --> 00:01:18.375
|
||||
Emo. den här vägen.
|
||||
|
||||
16
|
||||
00:01:34.417 --> 00:01:36.750
|
||||
Följ efter mig!
|
||||
|
||||
17
|
||||
00:02:11.250 --> 00:02:13.250
|
||||
Skynda dig. Emo!
|
||||
|
||||
18
|
||||
00:02:48.375 --> 00:02:50.583
|
||||
Du är inte uppmärksam!
|
||||
|
||||
19
|
||||
00:02:50.708 --> 00:02:54.500
|
||||
Jag vill bara svara...
|
||||
... i telefonen.
|
||||
|
||||
20
|
||||
00:02:54.500 --> 00:02:58.208
|
||||
Emo. se här...
|
||||
Lyssna menar jag.
|
||||
|
||||
21
|
||||
00:02:59.708 --> 00:03:02.292
|
||||
Du måste lära dig att lyssna.
|
||||
|
||||
22
|
||||
00:03:03.292 --> 00:03:05.208
|
||||
Det här är ingen lek.
|
||||
|
||||
23
|
||||
00:03:05.250 --> 00:03:08.917
|
||||
Du... Jag menar vi.
|
||||
vi skulle kunna dö här ute.
|
||||
|
||||
24
|
||||
00:03:09.917 --> 00:03:11.417
|
||||
Lyssna...
|
||||
|
||||
25
|
||||
00:03:11.708 --> 00:03:14.833
|
||||
Lyssna på ljuden från maskinen.
|
||||
|
||||
26
|
||||
00:03:18.125 --> 00:03:21.417
|
||||
Lyssna på dina andetag.
|
||||
|
||||
27
|
||||
00:04:26.625 --> 00:04:29.250
|
||||
Tröttnar du aldrig på det här?
|
||||
|
||||
28
|
||||
00:04:29.542 --> 00:04:31.083
|
||||
Tröttnar!?
|
||||
|
||||
29
|
||||
00:04:31.208 --> 00:04:33.458
|
||||
Emo. maskinen är som...
|
||||
|
||||
30
|
||||
00:04:33.458 --> 00:04:35.333
|
||||
Som ett urverk.
|
||||
|
||||
31
|
||||
00:04:35.417 --> 00:04:37.167
|
||||
Ett felsteg...
|
||||
|
||||
32
|
||||
00:04:37.208 --> 00:04:39.750
|
||||
...och du blir krossad.
|
||||
|
||||
33
|
||||
00:04:41.042 --> 00:04:42.292
|
||||
Men är det inte -
|
||||
|
||||
34
|
||||
00:04:42.292 --> 00:04:47.000
|
||||
Krossad. Emo!
|
||||
Är det vad du vill bli? Krossad till mos?
|
||||
|
||||
35
|
||||
00:04:47.500 --> 00:04:50.542
|
||||
Emo. är det ditt mål i livet?
|
||||
|
||||
36
|
||||
00:04:50.667 --> 00:04:53.250
|
||||
Att bli mos!?
|
||||
|
||||
37
|
||||
00:05:41.375 --> 00:05:43.458
|
||||
Emo. blunda.
|
||||
|
||||
38
|
||||
00:05:44.375 --> 00:05:46.542
|
||||
Varför då?
|
||||
- Blunda!
|
||||
|
||||
39
|
||||
00:05:51.292 --> 00:05:55.042
|
||||
Ok.
|
||||
- Bra.
|
||||
|
||||
40
|
||||
00:05:59.500 --> 00:06:02.750
|
||||
Vad ser du till vänster om dig Emo?
|
||||
|
||||
41
|
||||
00:06:04.125 --> 00:06:06.292
|
||||
Ingenting.
|
||||
- Säker?
|
||||
|
||||
42
|
||||
00:06:06.333 --> 00:06:07.958
|
||||
Ingenting alls.
|
||||
|
||||
43
|
||||
00:06:08.042 --> 00:06:12.625
|
||||
Jaså. och till höger om dig...
|
||||
Vad ser du där. Emo?
|
||||
|
||||
44
|
||||
00:06:13.750 --> 00:06:15.583
|
||||
Samma där Proog...
|
||||
|
||||
45
|
||||
00:06:15.583 --> 00:06:18.083
|
||||
Exakt samma där. ingenting!
|
||||
|
||||
46
|
||||
00:06:18.083 --> 00:06:19.667
|
||||
Perfekt.
|
||||
|
||||
47
|
||||
00:06:40.500 --> 00:06:42.917
|
||||
Lyssna Proog! Hör du?
|
||||
|
||||
48
|
||||
00:06:43.500 --> 00:06:45.125
|
||||
Kan vi gå dit?
|
||||
|
||||
49
|
||||
00:06:45.208 --> 00:06:48.125
|
||||
Gå dit?
|
||||
Det är inte tryggt.
|
||||
|
||||
50
|
||||
00:06:49.583 --> 00:06:52.583
|
||||
Men. men...
|
||||
- Tro mig. det inte säkert.
|
||||
|
||||
51
|
||||
00:06:53.000 --> 00:06:54.292
|
||||
Men kanske om jag -
|
||||
|
||||
52
|
||||
00:06:54.292 --> 00:06:56.333
|
||||
Nej.
|
||||
|
||||
53
|
||||
00:06:57.208 --> 00:07:00.167
|
||||
Men -
|
||||
- Nej. NEJ!
|
||||
|
||||
54
|
||||
00:07:00.917 --> 00:07:03.792
|
||||
Några fler frågor Emo?
|
||||
|
||||
55
|
||||
00:07:04.250 --> 00:07:05.875
|
||||
Nej.
|
||||
|
||||
56
|
||||
00:07:09.542 --> 00:07:11.375
|
||||
Emo?
|
||||
- Ja?
|
||||
|
||||
57
|
||||
00:07:11.542 --> 00:07:15.667
|
||||
Emo. varför...
|
||||
|
||||
58
|
||||
00:07:15.792 --> 00:07:18.583
|
||||
Varför kan du inte se skönheten i det här?
|
||||
|
||||
59
|
||||
00:07:18.792 --> 00:07:21.708
|
||||
Hur det fungerar.
|
||||
|
||||
60
|
||||
00:07:21.833 --> 00:07:24.000
|
||||
Hur perfekt det är.
|
||||
|
||||
61
|
||||
00:07:24.083 --> 00:07:27.333
|
||||
Nej Proog. jag kan inte se det.
|
||||
|
||||
62
|
||||
00:07:27.333 --> 00:07:30.333
|
||||
Jag ser det inte. för det finns inget där.
|
||||
|
||||
63
|
||||
00:07:31.292 --> 00:07:35.333
|
||||
Och varför skulle jag lägga mitt liv
|
||||
i händerna på något som inte finns?
|
||||
|
||||
64
|
||||
00:07:35.333 --> 00:07:37.083
|
||||
Kan du berätta det för mig?
|
||||
- Emo...
|
||||
|
||||
65
|
||||
00:07:37.083 --> 00:07:39.167
|
||||
Svara mig!
|
||||
|
||||
66
|
||||
00:07:43.500 --> 00:07:45.208
|
||||
Proog...
|
||||
|
||||
67
|
||||
00:07:45.208 --> 00:07:47.083
|
||||
Du är inte frisk!
|
||||
|
||||
68
|
||||
00:07:47.167 --> 00:07:49.292
|
||||
Håll dig borta från mig!
|
||||
|
||||
69
|
||||
00:07:52.292 --> 00:07:55.083
|
||||
Nej! Emo!
|
||||
Det är en fälla!
|
||||
|
||||
70
|
||||
00:07:55.375 --> 00:07:57.208
|
||||
Heh. det är en fälla.
|
||||
|
||||
71
|
||||
00:07:57.208 --> 00:08:01.708
|
||||
På vänster sida ser vi...
|
||||
Babylons hängande trädgårdar!
|
||||
|
||||
72
|
||||
00:08:01.958 --> 00:08:04.000
|
||||
Vad sägs om den fällan?
|
||||
|
||||
73
|
||||
00:08:05.458 --> 00:08:07.333
|
||||
Nej. Emo.
|
||||
|
||||
74
|
||||
00:08:08.917 --> 00:08:12.667
|
||||
Till höger ser vi...
|
||||
Gissa!
|
||||
|
||||
75
|
||||
00:08:12.750 --> 00:08:15.125
|
||||
Rhodos koloss!
|
||||
|
||||
76
|
||||
00:08:15.375 --> 00:08:16.500
|
||||
Nej!
|
||||
|
||||
77
|
||||
00:08:16.500 --> 00:08:20.250
|
||||
Kolossen på Rhodos!
|
||||
Och den är här för din skull. Proog...
|
||||
|
||||
78
|
||||
00:08:20.250 --> 00:08:23.250
|
||||
Bara för din skull.
|
||||
|
||||
79
|
||||
00:08:50.917 --> 00:08:53.250
|
||||
Den är där...
|
||||
|
||||
80
|
||||
00:08:53.625 --> 00:08:56.417
|
||||
Tro mig.
|
||||
Emo...
|
||||
|
||||
81
|
||||
00:08:57.000 --> 00:09:00.000
|
||||
Det är den.
|
||||
Det är den...
|
44
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/chapters.en.vtt
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
WEBVTT
|
||||
|
||||
NOTE Created by Owen Edwards 2015. http://creativecommons.org/licenses/by/2.5/
|
||||
NOTE Based on 'finalbreakdown.rtf', part of the prepoduction notes, which are:
|
||||
NOTE (c) Copyright 2006, Blender Foundation /
|
||||
NOTE Netherlands Media Art Institute /
|
||||
NOTE www.elephantsdream.org
|
||||
|
||||
1
|
||||
00:00:00.000 --> 00:00:27.500
|
||||
Prologue
|
||||
|
||||
2
|
||||
00:00:27.500 --> 00:01:10.000
|
||||
Switchboard trap
|
||||
|
||||
3
|
||||
00:01:10.000 --> 00:03:25.000
|
||||
Telephone/Lecture
|
||||
|
||||
4
|
||||
00:03:25.000 --> 00:04:52.000
|
||||
Typewriter
|
||||
|
||||
5
|
||||
00:04:52.000 --> 00:06:19.500
|
||||
Proog shows Emo stuff
|
||||
|
||||
6
|
||||
00:06:19.500 --> 00:07:09.000
|
||||
Which way
|
||||
|
||||
7
|
||||
00:07:09.000 --> 00:07:45.000
|
||||
Emo flips out
|
||||
|
||||
8
|
||||
00:07:45.000 --> 00:09:25.000
|
||||
Emo creates
|
||||
|
||||
9
|
||||
00:09:25.000 --> 00:10:53.000
|
||||
Closing credits
|
||||
|
280
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/descriptions.en.vtt
generated
vendored
Normal file
|
@ -0,0 +1,280 @@
|
|||
WEBVTT
|
||||
License: CC BY 4.0 http://creativecommons.org/licenses/by/4.0/
|
||||
Author: Silvia Pfeiffer
|
||||
|
||||
1
|
||||
00:00:00.000 --> 00:00:05.000
|
||||
The orange open movie project presents
|
||||
|
||||
2
|
||||
00:00:05.010 --> 00:00:12.000
|
||||
Introductory titles are showing on the background of a water pool with fishes swimming and mechanical objects lying on a stone floor.
|
||||
|
||||
3
|
||||
00:00:12.010 --> 00:00:14.800
|
||||
elephants dream
|
||||
|
||||
4
|
||||
00:00:26.100 --> 00:00:28.206
|
||||
Two people stand on a small bridge.
|
||||
|
||||
5
|
||||
00:00:30.010 --> 00:00:40.000
|
||||
The old man, Proog, shoves the younger and less experienced Emo on the ground to save him from being mowed down by a barrage of jack plugs that whir back and forth between the two massive switch-board-like walls.
|
||||
|
||||
6
|
||||
00:00:40.000 --> 00:00:47.000
|
||||
The plugs are oblivious of the two, endlessly channeling streams of bizarre sounds and data.
|
||||
|
||||
7
|
||||
00:00:48.494 --> 00:00:51.994
|
||||
Emo sits on the bridge and checks his limbs.
|
||||
|
||||
8
|
||||
00:01:09.150 --> 00:01:16.030
|
||||
After the squealing plugs move on, Proog makes sure that Emo is unharmed and urges him onwards through a crack in one of the plug-walls.
|
||||
|
||||
9
|
||||
00:01:18.050 --> 00:01:24.000
|
||||
They walk through the narrow hall into a massive room that fades away into blackness on all sides.
|
||||
|
||||
10
|
||||
00:01:24.050 --> 00:01:34.200
|
||||
Only one path is visible, suspended in mid-air that runs between thousands of dangling electric cables on which sit crowds of robin-like robotic birds.
|
||||
|
||||
11
|
||||
00:01:36.000 --> 00:01:40.000
|
||||
As Proog and Emo enter the room, the birds begin to wake up and notice them.
|
||||
|
||||
12
|
||||
00:01:42.000 --> 00:01:50.000
|
||||
Realizing the danger, Proog grabs Emo by the arm.
|
||||
|
||||
13
|
||||
00:01:50.050 --> 00:02:00.000
|
||||
They run along the increasingly bizarre path as the birds begin to swarm.
|
||||
|
||||
14
|
||||
00:02:00.050 --> 00:02:11.000
|
||||
All sound is blocked out by the birds which are making the same noises as the jack-plugs, garbled screaming and obscure sentences and static.
|
||||
|
||||
15
|
||||
00:02:12.600 --> 00:02:17.000
|
||||
The path dead-ends, stopping in the middle of no-where above the infinite drop.
|
||||
|
||||
16
|
||||
00:02:17.600 --> 00:02:22.000
|
||||
Proog turns around as the birds reach them and begin to dive-bomb at them.
|
||||
|
||||
17
|
||||
00:02:22.600 --> 00:02:28.000
|
||||
At the last moment, Proog takes out an old candlestick phone and the birds dive into the speaker piece.
|
||||
|
||||
18
|
||||
00:02:28.600 --> 00:02:31.000
|
||||
The screen cuts to black.
|
||||
|
||||
19
|
||||
00:02:31.600 --> 00:02:38.000
|
||||
In the next scene, Proog stands at one end of a room, suspiciously watching what is probably the same candlestick phone, which is ringing.
|
||||
|
||||
20
|
||||
00:02:38.500 --> 00:02:41.000
|
||||
Emo watches from the other side of the room.
|
||||
|
||||
21
|
||||
00:02:41.500 --> 00:02:43.000
|
||||
The phone continues to ring.
|
||||
|
||||
22
|
||||
00:02:43.500 --> 00:02:48.000
|
||||
After a while Emo approaches it to answer it, but Proog slaps his hand away.
|
||||
|
||||
23
|
||||
00:02:57.972 --> 00:02:59.100
|
||||
Proog takes the ear-piece off the hook.
|
||||
|
||||
24
|
||||
00:03:13.500 --> 00:03:18.054
|
||||
The phone speaker revealed a mass of clawed, fleshy polyps which scream and gibber obscenely.
|
||||
|
||||
25
|
||||
00:03:25.000 --> 00:03:33.000
|
||||
There is a solemn silence as Emo looks around the room and the technical objects therein.
|
||||
|
||||
26
|
||||
00:03:38.000 --> 00:03:44.000
|
||||
Emo laughs disbelievingly and Proog walks away.
|
||||
|
||||
27
|
||||
00:03:46.000 --> 00:03:54.000
|
||||
In the next scene, the two enter another massive black room.
|
||||
|
||||
28
|
||||
00:03:54.500 --> 00:04:04.000
|
||||
There is no path, the entry platform is the only structure that seems to be there except for another exit, lit distantly at the far side.
|
||||
|
||||
29
|
||||
00:04:04.500 --> 00:04:14.000
|
||||
Proog takes a step forward into the void, and his feet are suddenly caught by giant typewriter arms that rocket up out of the blackness to catch his feet as he dances across mid-air.
|
||||
|
||||
30
|
||||
00:04:14.500 --> 00:04:22.000
|
||||
Emo follows Proog with somewhat less enthusiasm as the older man leads the way.
|
||||
|
||||
31
|
||||
00:04:52.000 --> 00:04:58.000
|
||||
They reach the end of the room and go through a hall into a small compartment.
|
||||
|
||||
32
|
||||
00:05:02.000 --> 00:05:06.000
|
||||
Proog presses a button, and the door shuts.
|
||||
|
||||
33
|
||||
00:05:06.500 --> 00:05:09.000
|
||||
It is an elevator.
|
||||
|
||||
34
|
||||
00:05:09.500 --> 00:05:24.000
|
||||
The elevator lurches suddenly as it is grabbed by a giant mechanical arm and thrown upwards, rushing up through an ever-widening tunnel.
|
||||
|
||||
35
|
||||
00:05:26.500 --> 00:05:32.000
|
||||
When it begins to slow down, another arm grabs the capsule and throws it even further up.
|
||||
|
||||
36
|
||||
00:05:32.500 --> 00:05:40.000
|
||||
As it moves up, the walls unlock and fall away, leaving only the floor with the two on it, rushing higher and higher.
|
||||
|
||||
37
|
||||
00:05:54.500 --> 00:05:59.000
|
||||
They exit the tunnel into a black sky and the platform reaches the peak of its arc.
|
||||
|
||||
38
|
||||
00:06:19.500 --> 00:06:26.000
|
||||
The elevator begins to drop down another shaft, coming to rest as it slams into the floor of another room and bringing the two to a level stop.
|
||||
|
||||
39
|
||||
00:06:26.500 --> 00:06:28.000
|
||||
A camera briefly illumiates.
|
||||
|
||||
40
|
||||
00:06:28.010 --> 00:06:34.000
|
||||
They are in a large, dingy room filled with strange, generator-like devices and dotted with boxy holographic projectors.
|
||||
|
||||
41
|
||||
00:06:34.500 --> 00:06:38.000
|
||||
One of them is projecting a portion of wall with a door in it right beside them.
|
||||
|
||||
42
|
||||
00:06:38.500 --> 00:06:40.000
|
||||
The door seems harmless enough.
|
||||
|
||||
43
|
||||
00:06:42.800 --> 00:06:45.100
|
||||
From behind the door comes light music.
|
||||
|
||||
44
|
||||
00:06:56.000 --> 00:07:00.100
|
||||
Proog presses a button on his cane, which changes the holograph to another wall.
|
||||
|
||||
45
|
||||
00:07:05.100 --> 00:07:11.000
|
||||
Proog finishes the wall, and boxes them into a Safe Room, out of the view of anything outside.
|
||||
|
||||
46
|
||||
00:07:39.000 --> 00:07:42.500
|
||||
Proog slaps him, trying to bring him to his senses.
|
||||
|
||||
47
|
||||
00:07:45.000 --> 00:07:52.000
|
||||
Emo storms away down the length of the room towards a wall he apparently cannot see and the wall begins to move, extending the length of the room.
|
||||
|
||||
48
|
||||
00:08:00.000 --> 00:08:07.000
|
||||
The walls begin to discolour and mechanical roots start tearing through the walls to his left.
|
||||
|
||||
49
|
||||
00:08:07.010 --> 00:08:09.000
|
||||
The roots move forwards toward Proog.
|
||||
|
||||
50
|
||||
00:08:22.000 --> 00:08:31.000
|
||||
The rest of the safety wall crumples away as a pair of massive hands heave out of the ground and begin to attack.
|
||||
|
||||
51
|
||||
00:08:31.010 --> 00:08:37.000
|
||||
Proog is knocked down by the shockwave, while Emo turns and begins to walk away, waving his finger around his temple in the 'crazy' sign.
|
||||
|
||||
52
|
||||
00:08:37.010 --> 00:08:44.000
|
||||
In a last effort, Proog extricates himself from the tentacle roots, and cracks Emo over the back of the head with his cane.
|
||||
|
||||
53
|
||||
00:08:44.500 --> 00:08:51.000
|
||||
As Emo collapses, everything falls away, and Proog and Emo are left in one tiny patch of light in the middle of blackness.
|
||||
|
||||
54
|
||||
00:09:00.000 --> 00:09:20.000
|
||||
The scene fades to black while panning over a pile of tentacle roots lying on the ground.
|
||||
|
||||
55
|
||||
00:09:26.000 --> 00:09:28.000
|
||||
Credits begin:
|
||||
|
||||
56
|
||||
00:09:28.500 --> 00:09:35.000
|
||||
Orange Open Movie Team
|
||||
Director: Bassum Kurdali
|
||||
Art Director: Andreas Goralczyk
|
||||
|
||||
57
|
||||
00:09:35.500 --> 00:09:39.000
|
||||
Music and Sound Design: Jan Morgenstern
|
||||
|
||||
58
|
||||
00:09:39.500 --> 00:09:44.000
|
||||
Emo: Cas Jansen
|
||||
Proog: Tygo Gernandt
|
||||
|
||||
59
|
||||
00:09:44.500 --> 00:09:50.000
|
||||
Screenplay: Pepijn Zwanenberg
|
||||
Original Concept & Scenario: Andreas Goralczyk, Bassam Kurdali, Ton Roosendaal
|
||||
|
||||
60
|
||||
00:09:50.500 --> 00:10:24.000
|
||||
More people for
|
||||
Additional Artwork and Animation
|
||||
Texture Photography
|
||||
Software Development
|
||||
3D Modelling, Animation, Rendering, Compiling Software
|
||||
Special Thanks to Open Source Projects
|
||||
Rendering Services Provided
|
||||
Hardware Sponsored
|
||||
Casting
|
||||
Sound FX, Foley, Dialogue Editing, Audio Mix and Post
|
||||
Voice Recording
|
||||
HDCam conversion
|
||||
Netherlands Media Art Institute Staff
|
||||
Blender Foundation Staff
|
||||
|
||||
61
|
||||
00:10:24.500 --> 00:10:30.000
|
||||
Many Thanks to our Donation and DVD sponsors
|
||||
|
||||
62
|
||||
00:10:30.500 --> 00:10:47.000
|
||||
Elephants Dream has been realised with financial support from
|
||||
The Netherlands Film Fund
|
||||
Mondriaan Foundation
|
||||
VSBfonds
|
||||
Uni-Verse / EU Sixth Framework Programme
|
||||
|
||||
63
|
||||
00:10:47.500 --> 00:10:53.000
|
||||
Produced By
|
||||
Ton Roosendaal
|
||||
Copyright 2006
|
||||
Netherlands Media Art Institute / Montevideo
|
||||
Blender Foundation
|
41
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/elephantsdream/index.html
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<title>Video.js Text Descriptions, Chapters & Captions Example</title>
|
||||
|
||||
<link href="http://vjs.zencdn.net/7.0/video-js.min.css" rel="stylesheet">
|
||||
<script src="http://vjs.zencdn.net/7.0/video.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NOTE: we have to disable native Text Track support for the HTML5 tech,
|
||||
since even HTML5 video players with native Text Track support
|
||||
don't currently support 'description' text tracks in any
|
||||
useful way! Currently this means that iOS will not display
|
||||
ANY text tracks -->
|
||||
<video id="example_video_1" class="video-js" controls preload="none" width="640" height="360"
|
||||
data-setup='{ "html5" : { "nativeTextTracks" : false } }'
|
||||
poster="http://d2zihajmogu5jn.cloudfront.net/elephantsdream/poster.png">
|
||||
|
||||
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.mp4" type="video/mp4">
|
||||
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.ogg" type="video/ogg">
|
||||
|
||||
<track kind="captions" src="captions.en.vtt" srclang="en" label="English" default>
|
||||
<track kind="captions" src="captions.sv.vtt" srclang="sv" label="Swedish">
|
||||
<track kind="captions" src="captions.ru.vtt" srclang="ru" label="Russian">
|
||||
<track kind="captions" src="captions.ja.vtt" srclang="ja" label="Japanese">
|
||||
<track kind="captions" src="captions.ar.vtt" srclang="ar" label="Arabic">
|
||||
|
||||
<track kind="descriptions" src="descriptions.en.vtt" srclang="en" label="English">
|
||||
|
||||
<track kind="chapters" src="chapters.en.vtt" srclang="en" label="English">
|
||||
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
18
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/index.html
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Index of video.js examples</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Index of video.js examples</h1>
|
||||
<ul>
|
||||
<li><a href="simple-embed">Video.js HTML5 video player simple example</a></li>
|
||||
<li><a href="elephantsdream">Elephants Dream video with text descriptions, chapters & captions example</a></li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
41
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/shared/example-captions.vtt
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
WEBVTT
|
||||
|
||||
00:00.700 --> 00:04.110
|
||||
Captions describe all relevant audio for the hearing impaired.
|
||||
[ Heroic music playing for a seagull ]
|
||||
|
||||
00:04.500 --> 00:05.000
|
||||
[ Splash!!! ]
|
||||
|
||||
00:05.100 --> 00:06.000
|
||||
[ Sploosh!!! ]
|
||||
|
||||
00:08.000 --> 00:09.225
|
||||
[ Splash...splash...splash splash splash ]
|
||||
|
||||
00:10.525 --> 00:11.255
|
||||
[ Splash, Sploosh again ]
|
||||
|
||||
00:13.500 --> 00:14.984
|
||||
Dolphin: eeeEEEEEeeee!
|
||||
|
||||
00:14.984 --> 00:16.984
|
||||
Dolphin: Squawk! eeeEEE?
|
||||
|
||||
00:25.000 --> 00:28.284
|
||||
[ A whole ton of splashes ]
|
||||
|
||||
00:29.500 --> 00:31.000
|
||||
Mine. Mine. Mine.
|
||||
|
||||
00:34.300 --> 00:36.000
|
||||
Shark: Chomp
|
||||
|
||||
00:36.800 --> 00:37.900
|
||||
Shark: CHOMP!!!
|
||||
|
||||
00:37.861 --> 00:41.193
|
||||
EEEEEEOOOOOOOOOOWHALENOISE
|
||||
|
||||
00:42.593 --> 00:45.611
|
||||
[ BIG SPLASH ]
|
23
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/examples/simple-embed/index.html
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<title>Video.js | HTML5 Video Player</title>
|
||||
<link href="http://vjs.zencdn.net/7.0/video-js.min.css" rel="stylesheet">
|
||||
<script src="http://vjs.zencdn.net/7.0/video.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<video id="example_video_1" class="video-js" controls preload="none" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png" data-setup="{}">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
|
||||
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg">
|
||||
<track kind="captions" src="../shared/example-captions.vtt" srclang="en" label="English">
|
||||
<track kind="subtitles" src="../shared/example-captions.vtt" srclang="en" label="English">
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
114
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/font/VideoJS.svg
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<font id="VideoJS" horiz-adv-x="1792">
|
||||
<font-face font-family="VideoJS"
|
||||
units-per-em="1792" ascent="1792"
|
||||
descent="0" />
|
||||
<missing-glyph horiz-adv-x="0" />
|
||||
<glyph glyph-name="play"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M597.3333333333334 1418.6666666666665V373.3333333333333L1418.6666666666667 896z" />
|
||||
<glyph glyph-name="play-circle"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M746.6666666666667 560L1194.6666666666667 896L746.6666666666667 1232V560zM896 1642.6666666666667C483.4666666666667 1642.6666666666667 149.3333333333334 1308.5333333333333 149.3333333333334 896S483.4666666666667 149.3333333333333 896 149.3333333333333S1642.6666666666667 483.4666666666667 1642.6666666666667 896S1308.5333333333333 1642.6666666666667 896 1642.6666666666667zM896 298.6666666666665C566.72 298.6666666666665 298.6666666666667 566.7199999999998 298.6666666666667 896S566.72 1493.3333333333333 896 1493.3333333333333S1493.3333333333335 1225.28 1493.3333333333335 896S1225.2800000000002 298.6666666666665 896 298.6666666666665z" />
|
||||
<glyph glyph-name="pause"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M448 373.3333333333333H746.6666666666667V1418.6666666666665H448V373.3333333333333zM1045.3333333333335 1418.6666666666665V373.3333333333333H1344V1418.6666666666665H1045.3333333333335z" />
|
||||
<glyph glyph-name="volume-mute"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1232 896C1232 1027.7866666666666 1155.8400000000001 1141.6533333333332 1045.3333333333335 1196.5333333333333V1031.52L1228.6399999999999 848.2133333333334C1230.88 863.8933333333334 1232 879.9466666666667 1232 896.0000000000001zM1418.6666666666667 896C1418.6666666666667 825.8133333333333 1403.3600000000001 759.7333333333333 1378.3466666666668 698.8799999999999L1491.466666666667 585.7599999999998C1540 678.72 1568 783.9999999999999 1568 896C1568 1215.5733333333333 1344.3733333333334 1482.88 1045.3333333333335 1550.8266666666666V1396.6399999999999C1261.1200000000001 1332.4266666666667 1418.6666666666667 1132.6933333333332 1418.6666666666667 896zM319.2000000000001 1568L224 1472.8L576.8 1120H224V672H522.6666666666667L896 298.6666666666665V800.8L1213.7066666666667 483.0933333333332C1163.68 444.6399999999999 1107.3066666666666 413.6533333333332 1045.3333333333335 394.9866666666665V240.7999999999998C1148 264.32 1241.7066666666667 311.3599999999997 1320.48 375.9466666666663L1472.8000000000002 224L1568 319.1999999999998L896 991.1999999999998L319.2000000000001 1568zM896 1493.3333333333333L739.9466666666667 1337.28L896 1181.2266666666667V1493.3333333333333z" />
|
||||
<glyph glyph-name="volume-low"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M522.6666666666667 1120V672H821.3333333333334L1194.6666666666667 298.6666666666665V1493.3333333333333L821.3333333333334 1120H522.6666666666667z" />
|
||||
<glyph glyph-name="volume-mid"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1381.3333333333335 896C1381.3333333333335 1027.7866666666666 1305.1733333333334 1141.6533333333332 1194.6666666666667 1196.5333333333333V595.0933333333332C1305.1733333333334 650.3466666666666 1381.3333333333335 764.2133333333331 1381.3333333333335 896zM373.3333333333334 1120V672H672L1045.3333333333335 298.6666666666665V1493.3333333333333L672 1120H373.3333333333334z" />
|
||||
<glyph glyph-name="volume-high"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M224 1120V672H522.6666666666667L896 298.6666666666665V1493.3333333333333L522.6666666666667 1120H224zM1232 896C1232 1027.7866666666666 1155.8400000000001 1141.6533333333332 1045.3333333333335 1196.5333333333333V595.0933333333332C1155.8400000000001 650.3466666666666 1232 764.2133333333331 1232 896zM1045.3333333333335 1550.8266666666666V1396.6399999999999C1261.1200000000001 1332.4266666666667 1418.6666666666667 1132.6933333333332 1418.6666666666667 896S1261.1200000000001 459.5733333333333 1045.3333333333335 395.3600000000002V241.1733333333332C1344.3733333333334 309.1199999999999 1568 576.0533333333333 1568 896S1344.3733333333334 1482.88 1045.3333333333335 1550.8266666666666z" />
|
||||
<glyph glyph-name="fullscreen-enter"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M522.6666666666667 746.6666666666665H373.3333333333334V373.3333333333333H746.6666666666667V522.6666666666665H522.6666666666667V746.6666666666665zM373.3333333333334 1045.3333333333333H522.6666666666667V1269.3333333333333H746.6666666666667V1418.6666666666665H373.3333333333334V1045.3333333333333zM1269.3333333333335 522.6666666666665H1045.3333333333335V373.3333333333333H1418.6666666666667V746.6666666666665H1269.3333333333335V522.6666666666665zM1045.3333333333335 1418.6666666666665V1269.3333333333333H1269.3333333333335V1045.3333333333333H1418.6666666666667V1418.6666666666665H1045.3333333333335z" />
|
||||
<glyph glyph-name="fullscreen-exit"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M373.3333333333334 597.3333333333333H597.3333333333334V373.3333333333333H746.6666666666667V746.6666666666665H373.3333333333334V597.3333333333333zM597.3333333333334 1194.6666666666665H373.3333333333334V1045.3333333333333H746.6666666666667V1418.6666666666665H597.3333333333334V1194.6666666666665zM1045.3333333333335 373.3333333333333H1194.6666666666667V597.3333333333333H1418.6666666666667V746.6666666666665H1045.3333333333335V373.3333333333333zM1194.6666666666667 1194.6666666666665V1418.6666666666665H1045.3333333333335V1045.3333333333333H1418.6666666666667V1194.6666666666665H1194.6666666666667z" />
|
||||
<glyph glyph-name="square"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1344 1493.3333333333333H448C365.4933333333334 1493.3333333333333 298.6666666666667 1426.5066666666667 298.6666666666667 1344V448C298.6666666666667 365.4933333333331 365.4933333333334 298.6666666666665 448 298.6666666666665H1344C1426.506666666667 298.6666666666665 1493.3333333333335 365.4933333333331 1493.3333333333335 448V1344C1493.3333333333335 1426.5066666666667 1426.506666666667 1493.3333333333333 1344 1493.3333333333333zM1344 448H448V1344H1344V448z" />
|
||||
<glyph glyph-name="spinner"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M701.8666666666668 1008L1057.6533333333334 1624.3733333333334C1005.7600000000002 1635.9466666666667 951.6266666666666 1642.6666666666667 896 1642.6666666666667C716.8000000000001 1642.6666666666667 552.9066666666668 1579.5733333333333 424.1066666666667 1474.2933333333333L697.76 1000.5333333333334L701.8666666666666 1008zM1608.32 1120C1539.6266666666666 1338.4 1373.1200000000001 1512.7466666666667 1160.6933333333332 1593.3866666666668L887.4133333333334 1120H1608.32zM1627.7333333333336 1045.3333333333333H1068.48L1090.1333333333334 1008L1445.92 392C1567.6266666666668 524.9066666666668 1642.6666666666667 701.4933333333333 1642.6666666666667 896C1642.6666666666667 947.1466666666666 1637.44 997.1733333333332 1627.7333333333336 1045.3333333333333zM637.2800000000001 896L346.08 1400C224.3733333333333 1267.0933333333332 149.3333333333334 1090.5066666666667 149.3333333333334 896C149.3333333333334 844.8533333333332 154.56 794.8266666666666 164.2666666666667 746.6666666666665H723.5200000000001L637.2800000000002 896zM183.68 672C252.3733333333334 453.5999999999999 418.88 279.2533333333334 631.3066666666667 198.6133333333332L904.5866666666668 672H183.68zM1025.1733333333334 672L733.9733333333334 167.6266666666666C786.24 156.0533333333333 840.3733333333334 149.3333333333333 896 149.3333333333333C1075.2 149.3333333333333 1239.0933333333332 212.4266666666665 1367.8933333333334 317.7066666666665L1094.24 791.4666666666666L1025.1733333333334 672z" />
|
||||
<glyph glyph-name="subtitles"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1493.3333333333335 1493.3333333333333H298.6666666666667C216.16 1493.3333333333333 149.3333333333334 1426.5066666666667 149.3333333333334 1344V448C149.3333333333334 365.4933333333331 216.16 298.6666666666665 298.6666666666667 298.6666666666665H1493.3333333333335C1575.8400000000001 298.6666666666665 1642.6666666666667 365.4933333333331 1642.6666666666667 448V1344C1642.6666666666667 1426.5066666666667 1575.8400000000001 1493.3333333333333 1493.3333333333335 1493.3333333333333zM298.6666666666667 896H597.3333333333334V746.6666666666665H298.6666666666667V896zM1045.3333333333335 448H298.6666666666667V597.3333333333333H1045.3333333333335V448zM1493.3333333333335 448H1194.6666666666667V597.3333333333333H1493.3333333333335V448zM1493.3333333333335 746.6666666666665H746.6666666666667V896H1493.3333333333335V746.6666666666665z" />
|
||||
<glyph glyph-name="captions"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1418.6666666666667 1493.3333333333333H373.3333333333334C290.8266666666667 1493.3333333333333 224 1426.5066666666667 224 1344V448C224 365.4933333333331 290.8266666666667 298.6666666666665 373.3333333333334 298.6666666666665H1418.6666666666667C1501.1733333333334 298.6666666666665 1568 365.4933333333331 1568 448V1344C1568 1426.5066666666667 1501.1733333333334 1493.3333333333333 1418.6666666666667 1493.3333333333333zM821.3333333333334 970.6666666666666H709.3333333333334V1008H560V783.9999999999999H709.3333333333334V821.3333333333333H821.3333333333334V746.6666666666665C821.3333333333334 705.5999999999999 788.1066666666667 672 746.6666666666667 672H522.6666666666667C481.2266666666667 672 448 705.5999999999999 448 746.6666666666665V1045.3333333333333C448 1086.4 481.2266666666667 1120 522.6666666666667 1120H746.6666666666667C788.1066666666667 1120 821.3333333333334 1086.4 821.3333333333334 1045.3333333333333V970.6666666666666zM1344 970.6666666666666H1232V1008H1082.6666666666667V783.9999999999999H1232V821.3333333333333H1344V746.6666666666665C1344 705.5999999999999 1310.7733333333333 672 1269.3333333333335 672H1045.3333333333335C1003.8933333333334 672 970.6666666666669 705.5999999999999 970.6666666666669 746.6666666666665V1045.3333333333333C970.6666666666669 1086.4 1003.8933333333334 1120 1045.3333333333335 1120H1269.3333333333335C1310.7733333333333 1120 1344 1086.4 1344 1045.3333333333333V970.6666666666666z" />
|
||||
<glyph glyph-name="chapters"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M224 821.3333333333333H373.3333333333334V970.6666666666666H224V821.3333333333333zM224 522.6666666666665H373.3333333333334V672H224V522.6666666666665zM224 1120H373.3333333333334V1269.3333333333333H224V1120zM522.6666666666667 821.3333333333333H1568V970.6666666666666H522.6666666666667V821.3333333333333zM522.6666666666667 522.6666666666665H1568V672H522.6666666666667V522.6666666666665zM522.6666666666667 1269.3333333333333V1120H1568V1269.3333333333333H522.6666666666667z" />
|
||||
<glyph glyph-name="share"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1344 590.9866666666665C1287.2533333333333 590.9866666666665 1236.1066666666668 568.9599999999998 1197.2800000000002 533.4933333333331L665.2800000000001 843.7333333333333C669.3866666666667 860.5333333333333 672 878.08 672 896S669.3866666666667 931.4666666666666 665.2800000000001 948.2666666666667L1191.68 1255.52C1231.6266666666668 1218.1866666666665 1285.0133333333335 1195.04 1344 1195.04C1467.5733333333335 1195.04 1568 1295.4666666666665 1568 1419.04S1467.5733333333335 1643.04 1344 1643.04S1120 1542.6133333333332 1120 1419.04C1120 1401.12 1122.6133333333335 1383.5733333333333 1126.72 1366.773333333333L600.3199999999999 1059.5199999999998C560.3733333333333 1096.853333333333 506.9866666666666 1119.9999999999998 448 1119.9999999999998C324.4266666666666 1119.9999999999998 224 1019.5733333333332 224 895.9999999999998S324.4266666666666 671.9999999999998 448 671.9999999999998C506.9866666666666 671.9999999999998 560.3733333333333 695.1466666666665 600.3199999999999 732.4799999999998L1132.32 422.2399999999998C1128.5866666666666 406.5599999999997 1126.3466666666666 390.133333333333 1126.3466666666666 373.3333333333331C1126.3466666666666 253.1199999999997 1223.7866666666669 155.6799999999996 1344 155.6799999999996S1561.6533333333334 253.1199999999997 1561.6533333333334 373.3333333333331S1464.2133333333334 590.9866666666662 1344 590.9866666666662z" />
|
||||
<glyph glyph-name="cog"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1450.7733333333333 823.1999999999999C1453.76 847.0933333333334 1456 871.3599999999999 1456 896S1453.76 944.9066666666666 1450.7733333333333 968.8L1608.6933333333336 1092.3733333333332C1622.8800000000003 1103.5733333333333 1626.986666666667 1123.7333333333331 1617.6533333333336 1140.1599999999999L1468.3200000000004 1398.8799999999999C1458.986666666667 1414.9333333333334 1439.5733333333335 1421.6533333333332 1422.7733333333338 1414.9333333333334L1236.8533333333337 1339.8933333333332C1198.4000000000003 1369.3866666666668 1156.2133333333338 1394.3999999999999 1110.6666666666672 1413.44L1082.6666666666667 1611.3066666666666C1079.3066666666668 1628.8533333333332 1064 1642.6666666666667 1045.3333333333335 1642.6666666666667H746.6666666666667C728 1642.6666666666667 712.6933333333334 1628.8533333333332 709.7066666666668 1611.3066666666666L681.7066666666668 1413.44C636.1600000000002 1394.4 593.9733333333335 1369.76 555.5200000000001 1339.8933333333332L369.6 1414.9333333333334C352.8000000000001 1421.28 333.3866666666667 1414.9333333333334 324.0533333333334 1398.88L174.72 1140.1599999999999C165.3866666666667 1124.1066666666666 169.4933333333334 1103.9466666666667 183.68 1092.3733333333332L341.2266666666667 968.8C338.2400000000001 944.9066666666666 336 920.64 336 896S338.2400000000001 847.0933333333334 341.2266666666667 823.1999999999999L183.68 699.6266666666668C169.4933333333334 688.4266666666667 165.3866666666667 668.2666666666667 174.72 651.8399999999999L324.0533333333334 393.1199999999999C333.3866666666667 377.0666666666666 352.8 370.3466666666666 369.6 377.0666666666666L555.5200000000001 452.1066666666666C593.9733333333334 422.6133333333333 636.16 397.5999999999999 681.7066666666668 378.56L709.7066666666668 180.6933333333334C712.6933333333334 163.1466666666668 728 149.3333333333333 746.6666666666667 149.3333333333333H1045.3333333333335C1064 149.3333333333333 1079.3066666666668 163.1466666666665 1082.2933333333333 180.6933333333334L1110.2933333333333 378.56C1155.84 397.5999999999999 1198.0266666666666 422.24 1236.48 452.1066666666666L1422.3999999999999 377.0666666666666C1439.2 370.7199999999998 1458.6133333333332 377.0666666666666 1467.9466666666665 393.1199999999999L1617.2799999999997 651.8399999999999C1626.6133333333332 667.8933333333332 1622.5066666666664 688.0533333333333 1608.3199999999997 699.6266666666668L1450.773333333333 823.1999999999999zM896 634.6666666666665C751.52 634.6666666666665 634.6666666666667 751.52 634.6666666666667 896S751.52 1157.3333333333333 896 1157.3333333333333S1157.3333333333335 1040.48 1157.3333333333335 896S1040.48 634.6666666666665 896 634.6666666666665z" />
|
||||
<glyph glyph-name="circle"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M149.3333333333334 896C149.3333333333334 483.6273867930074 483.6273867930075 149.3333333333333 896 149.3333333333333C1308.3726132069926 149.3333333333333 1642.6666666666667 483.6273867930074 1642.6666666666667 896C1642.6666666666667 1308.3726132069926 1308.3726132069926 1642.6666666666667 896 1642.6666666666667C483.6273867930075 1642.6666666666667 149.3333333333334 1308.3726132069926 149.3333333333334 896z" />
|
||||
<glyph glyph-name="circle-outline"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M896 1642.6666666666667C483.4666666666667 1642.6666666666667 149.3333333333334 1308.5333333333333 149.3333333333334 896S483.4666666666667 149.3333333333333 896 149.3333333333333S1642.6666666666667 483.4666666666667 1642.6666666666667 896S1308.5333333333333 1642.6666666666667 896 1642.6666666666667zM896 298.6666666666665C566.72 298.6666666666665 298.6666666666667 566.7199999999998 298.6666666666667 896S566.72 1493.3333333333333 896 1493.3333333333333S1493.3333333333335 1225.28 1493.3333333333335 896S1225.2800000000002 298.6666666666665 896 298.6666666666665z" />
|
||||
<glyph glyph-name="circle-inner-circle"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M896 1642.6666666666667C484.2133333333334 1642.6666666666667 149.3333333333334 1307.7866666666666 149.3333333333334 896S484.2133333333334 149.3333333333333 896 149.3333333333333S1642.6666666666667 484.2133333333331 1642.6666666666667 896S1307.7866666666669 1642.6666666666667 896 1642.6666666666667zM896 298.6666666666665C566.72 298.6666666666665 298.6666666666667 566.7199999999998 298.6666666666667 896S566.72 1493.3333333333333 896 1493.3333333333333S1493.3333333333335 1225.28 1493.3333333333335 896S1225.2800000000002 298.6666666666665 896 298.6666666666665zM1120 896C1120 772.4266666666666 1019.5733333333334 672 896 672S672 772.4266666666666 672 896S772.4266666666667 1120 896 1120S1120 1019.5733333333332 1120 896z" />
|
||||
<glyph glyph-name="hd"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1418.6666666666667 1568H373.3333333333334C290.4533333333333 1568 224 1500.8 224 1418.6666666666665V373.3333333333333C224 291.1999999999998 290.4533333333334 224 373.3333333333334 224H1418.6666666666667C1500.8000000000002 224 1568 291.1999999999998 1568 373.3333333333333V1418.6666666666665C1568 1500.8 1500.8000000000002 1568 1418.6666666666667 1568zM821.3333333333334 672H709.3333333333334V821.3333333333333H560V672H448V1120H560V933.3333333333331H709.3333333333334V1120H821.3333333333334V672zM970.6666666666669 1120H1269.3333333333335C1310.4 1120 1344 1086.4 1344 1045.3333333333333V746.6666666666665C1344 705.5999999999999 1310.4 672 1269.3333333333335 672H970.6666666666669V1120zM1082.6666666666667 783.9999999999999H1232V1008H1082.6666666666667V783.9999999999999z" />
|
||||
<glyph glyph-name="cancel"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M896 1642.6666666666667C483.4666666666667 1642.6666666666667 149.3333333333334 1308.5333333333333 149.3333333333334 896S483.4666666666667 149.3333333333333 896 149.3333333333333S1642.6666666666667 483.4666666666667 1642.6666666666667 896S1308.5333333333333 1642.6666666666667 896 1642.6666666666667zM1269.3333333333335 628.3199999999999L1163.68 522.6666666666665L896 790.3466666666667L628.3199999999999 522.6666666666665L522.6666666666667 628.3199999999999L790.3466666666668 896L522.6666666666667 1163.68L628.3199999999999 1269.3333333333333L896 1001.6533333333332L1163.68 1269.3333333333333L1269.3333333333335 1163.68L1001.6533333333334 896L1269.3333333333335 628.3199999999999z" />
|
||||
<glyph glyph-name="replay"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M896 1418.6666666666665V1717.3333333333333L522.6666666666667 1344L896 970.6666666666666V1269.3333333333333C1143.52 1269.3333333333333 1344 1068.8533333333332 1344 821.3333333333333S1143.52 373.3333333333333 896 373.3333333333333S448 573.813333333333 448 821.3333333333333H298.6666666666667C298.6666666666667 491.3066666666664 565.9733333333334 224 896 224S1493.3333333333335 491.3066666666664 1493.3333333333335 821.3333333333333S1226.0266666666669 1418.6666666666665 896 1418.6666666666665z" />
|
||||
<glyph glyph-name="facebook"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1343 1780V1516H1186Q1100 1516 1070 1480T1040 1372V1183H1333L1294 887H1040V128H734V887H479V1183H734V1401Q734 1587 838 1689.5T1115 1792Q1262 1792 1343 1780z" />
|
||||
<glyph glyph-name="gplus"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M799 996Q799 960 831 925.5T908.5 857.5T999 784T1076 680T1108 538Q1108 448 1060 365Q988 243 849 185.5T551 128Q419 128 304.5 169.5T133 307Q96 367 96 438Q96 519 140.5 588T259 703Q390 785 663 803Q631 845 615.5 877T600 950Q600 986 621 1035Q575 1031 553 1031Q405 1031 303.5 1127.5T202 1372Q202 1454 238 1531T337 1662Q414 1728 519.5 1760T737 1792H1155L1017 1704H886Q960 1641 998 1571T1036 1411Q1036 1339 1011.5 1281.5T952.5 1188.5T883 1123.5T823.5 1062T799 996zM653 1092Q691 1092 731 1108.5T797 1152Q850 1209 850 1311Q850 1369 833 1436T784.5 1565.5T700 1669T583 1710Q541 1710 500.5 1690.5T435 1638Q388 1579 388 1478Q388 1432 398 1380.5T429.5 1277.5T481.5 1185T556.5 1118T653 1092zM655 219Q713 219 766.5 232T865.5 271T938.5 344T966 453Q966 478 959 502T944.5 544T917.5 585.5T888 620.5T849.5 655T813 684T771.5 714T735 740Q719 742 687 742Q634 742 582 735T474.5 710T377.5 664T309 589.5T282 484Q282 414 317 360.5T408.5 277.5T527.5 233.5T655 219zM1465 1095H1678V987H1465V768H1360V987H1148V1095H1360V1312H1465V1095z" />
|
||||
<glyph glyph-name="linkedin"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M477 1167V176H147V1167H477zM498 1473Q499 1400 447.5 1351T312 1302H310Q228 1302 178 1351T128 1473Q128 1547 179.5 1595.5T314 1644T447 1595.5T498 1473zM1664 744V176H1335V706Q1335 811 1294.5 870.5T1168 930Q1105 930 1062.5 895.5T999 810Q988 780 988 729V176H659Q661 575 661 823T660 1119L659 1167H988V1023H986Q1006 1055 1027 1079T1083.5 1131T1170.5 1174.5T1285 1190Q1456 1190 1560 1076.5T1664 744z" />
|
||||
<glyph glyph-name="twitter"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1684 1384Q1617 1286 1522 1217Q1523 1203 1523 1175Q1523 1045 1485 915.5T1369.5 667T1185 456.5T927 310.5T604 256Q333 256 108 401Q143 397 186 397Q411 397 587 535Q482 537 399 599.5T285 759Q318 754 346 754Q389 754 431 765Q319 788 245.5 876.5T172 1082V1086Q240 1048 318 1045Q252 1089 213 1160T174 1314Q174 1402 218 1477Q339 1328 512.5 1238.5T884 1139Q876 1177 876 1213Q876 1347 970.5 1441.5T1199 1536Q1339 1536 1435 1434Q1544 1455 1640 1512Q1603 1397 1498 1334Q1591 1344 1684 1384z" />
|
||||
<glyph glyph-name="tumblr"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1328 463L1408 226Q1385 191 1297 160T1120 128Q1016 126 929.5 154T787 228T692 334T636.5 454T620 572V1116H452V1331Q524 1357 581 1400.5T672 1490.5T730 1592.5T764 1691.5T779 1780Q780 1785 783.5 1788.5T791 1792H1035V1368H1368V1116H1034V598Q1034 568 1040.5 542T1063 489.5T1112.5 448T1194 434Q1272 436 1328 463z" />
|
||||
<glyph glyph-name="pinterest"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1664 896Q1664 687 1561 510.5T1281.5 231T896 128Q785 128 678 160Q737 253 756 324Q765 358 810 535Q830 496 883 467.5T997 439Q1118 439 1213 507.5T1360 696T1412 966Q1412 1080 1352.5 1180T1180 1343T925 1406Q820 1406 729 1377T574.5 1300T465.5 1189.5T398.5 1060T377 926Q377 822 417 743T534 632Q564 620 572 652Q574 659 580 683T588 713Q594 736 577 756Q526 817 526 907Q526 1058 630.5 1166.5T904 1275Q1055 1275 1139.5 1193T1224 980Q1224 810 1155.5 691T980 572Q919 572 882 615.5T859 720Q867 755 885.5 813.5T915.5 916.5T927 992Q927 1042 900 1075T823 1108Q761 1108 718 1051T675 909Q675 836 700 787L601 369Q584 299 588 192Q382 283 255 473T128 896Q128 1105 231 1281.5T510.5 1561T896 1664T1281.5 1561T1561 1281.5T1664 896z" />
|
||||
<glyph glyph-name="audio-description"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M795.5138904615 457.270933L795.5138904615 1221.5248286325C971.84576475 1225.085121904 1107.39330415 1232.12360523 1207.223857 1161.5835220499998C1303.033991 1093.8857027 1377.7922305 962.20560625 1364.3373135 792.9476205000001C1350.102593 613.9029365000001 1219.6655764999998 463.4600215 1050.12389545 448.2843645000001C965.8259268 440.7398275000001 798.21890505 448.2843645000001 798.21890505 448.2843645000001C798.21890505 448.2843645000001 795.2791410655 453.016494 795.5138904615 457.270933M966.1564647 649.0863960000001C1076.16084135 644.6767075 1152.385591 707.3020429999999 1163.8910079999998 807.9351875C1179.2994744999999 942.71878505 1089.73043585 1030.3691748 960.74508635 1020.7227954L960.74508635 658.08043C960.6196169500002 652.9482330000001 962.7606933 650.3134680000001 966.1564647 649.0863960000001 M1343.2299685 457.3517725000002C1389.9059734 444.3690160000001 1404.0840274999998 496.0596970000001 1424.48294065 532.2791494999999C1469.0084255 611.2788500000001 1502.5101322 712.8584189999999 1503.0416912 828.9881705C1503.8147453000001 995.5680973 1438.8404296 1117.7973688000002 1378.4383305 1200.62456881045L1348.652139905 1200.62456881045C1346.6001063899998 1187.06858424 1356.44474056 1175.024791325 1362.18395859 1164.6588891000001C1408.2649952 1081.49431985 1450.96645015 966.7230041 1451.57490975 834.9817034999999C1452.27106325 683.8655425000002 1402.00636065 557.5072264999999 1343.2299685 457.3517725000002 M1488.0379675 457.3517725000002C1534.7139723999999 444.3690160000001 1548.8825828 496.0671625 1569.29093965 532.2791494999999C1613.8164245 611.2788500000001 1647.3113856500001 712.8584189999999 1647.8496902000002 828.9881705C1648.6227442999998 995.5680973 1583.6484286 1117.7973688000002 1523.2463295 1200.62456881045L1493.460138905 1200.62456881045C1491.40810539 1187.06858424 1501.250041305 1175.021805755 1506.9919575899999 1164.6588891000001C1553.0729942 1081.49431985 1595.7757984 966.7230041 1596.3829087499998 834.9817034999999C1597.07906225 683.8655425000002 1546.8143596500001 557.5072264999999 1488.0379675 457.3517725000002 M1631.9130380000001 457.3517725000002C1678.5890429 444.3690160000001 1692.7576533 496.0671625 1713.1660101500001 532.2791494999999C1757.691495 611.2788500000001 1791.1864561500001 712.8584189999999 1791.7247607000002 828.9881705C1792.4978148 995.5680973 1727.5234991000002 1117.7973688000002 1667.1214 1200.62456881045L1637.3352094050001 1200.62456881045C1635.28317589 1187.06858424 1645.1251118050002 1175.02329854 1650.86702809 1164.6588891000001C1696.9480647 1081.49431985 1739.64951965 966.7230041 1740.25797925 834.9817034999999C1740.95413275 683.8655425000002 1690.6894301500001 557.5072264999999 1631.9130380000001 457.3517725000002 M15.66796875 451.481947L254.03034755 451.481947L319.0356932 551.1747990000001L543.6261075 551.6487970000001C543.6261075 551.6487970000001 543.8541115 483.7032095 543.8541115 451.481947L714.4993835 451.481947L714.4993835 1230.9210795L508.643051 1230.9210795C488.8579955 1197.5411595 15.66796875 451.481947 15.66796875 451.481947L15.66796875 451.481947zM550.0048155000001 959.9708615L550.0048155000001 710.916297L408.4199 711.8642895L550.0048155000001 959.9708615L550.0048155000001 959.9708615z" />
|
||||
<glyph glyph-name="audio"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M896 1717.3333333333333C524.9066666666668 1717.3333333333333 224 1416.4266666666667 224 1045.3333333333333V522.6666666666665C224 399.0933333333333 324.4266666666667 298.6666666666665 448 298.6666666666665H672V896H373.3333333333334V1045.3333333333333C373.3333333333334 1333.92 607.4133333333334 1568 896 1568S1418.6666666666667 1333.92 1418.6666666666667 1045.3333333333333V896H1120V298.6666666666665H1344C1467.5733333333335 298.6666666666665 1568 399.0933333333333 1568 522.6666666666665V1045.3333333333333C1568 1416.4266666666667 1267.0933333333332 1717.3333333333333 896 1717.3333333333333z" />
|
||||
<glyph glyph-name="next-item"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M448 448L1082.6666666666667 896L448 1344V448zM1194.6666666666667 1344V448H1344V1344H1194.6666666666667z" />
|
||||
<glyph glyph-name="previous-item"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M448 1344H597.3333333333334V448H448zM709.3333333333334 896L1344 448V1344z" />
|
||||
<glyph glyph-name="picture-in-picture-enter"
|
||||
unicode=""
|
||||
horiz-adv-x="1792" d=" M1418.6666666666667 970.6666666666666H821.3333333333334V523.0399999999997H1418.6666666666667V970.6666666666666zM1717.3333333333335 373.3333333333333V1420.1599999999999C1717.3333333333335 1502.2933333333333 1650.1333333333334 1568 1568 1568H224C141.8666666666667 1568 74.6666666666667 1502.2933333333333 74.6666666666667 1420.1599999999999V373.3333333333333C74.6666666666667 291.1999999999998 141.8666666666667 224 224 224H1568C1650.1333333333334 224 1717.3333333333335 291.1999999999998 1717.3333333333335 373.3333333333333zM1568 371.8399999999999H224V1420.9066666666668H1568V371.8399999999999z" />
|
||||
<glyph glyph-name="picture-in-picture-exit"
|
||||
unicode=""
|
||||
horiz-adv-x="2190.222222222222" d=" M1792 1393.7777777777778H398.2222222222223V398.2222222222222H1792V1393.7777777777778zM2190.222222222222 199.1111111111111V1594.88C2190.222222222222 1704.391111111111 2100.6222222222223 1792 1991.1111111111113 1792H199.1111111111111C89.6 1792 0 1704.391111111111 0 1594.88V199.1111111111111C0 89.5999999999999 89.6 0 199.1111111111111 0H1991.1111111111113C2100.6222222222223 0 2190.222222222222 89.5999999999999 2190.222222222222 199.1111111111111zM1991.1111111111113 197.1200000000001H199.1111111111111V1595.8755555555556H1991.1111111111113V197.1200000000001z" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 28 KiB |
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/font/VideoJS.ttf
generated
vendored
Normal file
BIN
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/font/VideoJS.woff
generated
vendored
Normal file
90
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/lang/ar.js
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
videojs.addLanguage('ar', {
|
||||
"Play": "تشغيل",
|
||||
"Pause": "إيقاف",
|
||||
"Current Time": "الوقت الحالي",
|
||||
"Duration": "مدة",
|
||||
"Remaining Time": "الوقت المتبقي",
|
||||
"Stream Type": "نوع التيار",
|
||||
"LIVE": "مباشر",
|
||||
"Loaded": "تم التحميل",
|
||||
"Progress": "التقدم",
|
||||
"Fullscreen": "ملء الشاشة",
|
||||
"Non-Fullscreen": "تعطيل ملء الشاشة",
|
||||
"Mute": "صامت",
|
||||
"Unmute": "غير الصامت",
|
||||
"Playback Rate": "معدل التشغيل",
|
||||
"Subtitles": "الترجمة",
|
||||
"subtitles off": "إيقاف الترجمة",
|
||||
"Captions": "التعليقات",
|
||||
"captions off": "إيقاف التعليقات",
|
||||
"Chapters": "فصول",
|
||||
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
|
||||
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
|
||||
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
|
||||
"Play Video": "تشغيل الفيديو",
|
||||
"Close": "أغلق",
|
||||
"Modal Window": "نافذة مشروطة",
|
||||
"This is a modal window": "هذه نافذة مشروطة",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
|
||||
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
|
||||
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
|
||||
", selected": ", مختار",
|
||||
"Audio Player": "مشغل الصوت",
|
||||
"Video Player": "مشغل الفيديو",
|
||||
"Replay": "إعادة التشغيل",
|
||||
"Seek to live, currently behind live": "ذهاب إلى نقطة البث المباشر، متأخر عن البث المباشر حاليًا",
|
||||
"Seek to live, currently playing live": "ذهاب إلى نقطة البث المباشر، البث المباشر قيد التشغيل حاليًا",
|
||||
"Progress Bar": "شريط التقدم",
|
||||
"progress bar timing: currentTime={1} duration={2}": "{1} من {2}",
|
||||
"Descriptions": "الأوصاف",
|
||||
"descriptions off": "إخفاء الأوصاف",
|
||||
"Audio Track": "المسار الصوتي",
|
||||
"Volume Level": "مستوى الصوت",
|
||||
"The media is encrypted and we do not have the keys to decrypt it.": "الوسائط مشفرة وليس لدينا الرموز اللازمة لفك شفرتها.",
|
||||
"Close Modal Dialog": "إغلاق مربع الحوار المشروط",
|
||||
", opens descriptions settings dialog": "، يفتح مربع حوار إعدادات الأوصاف",
|
||||
"captions settings": "إعدادات التعليقات التوضيحية",
|
||||
"subtitles settings": "إعدادات الترجمات",
|
||||
"descriptions settings": "إعدادات الأوصاف",
|
||||
"Text": "النص",
|
||||
"White": "أبيض",
|
||||
"Black": "أسود",
|
||||
"Red": "أحمر",
|
||||
"Green": "أخضر",
|
||||
"Blue": "أزرق",
|
||||
"Yellow": "أصفر",
|
||||
"Magenta": "أرجواني",
|
||||
"Cyan": "أزرق سماوي",
|
||||
"Background": "الخلفية",
|
||||
"Window": "نافذة",
|
||||
"Transparent": "شفاف",
|
||||
"Semi-Transparent": "نصف شفاف",
|
||||
"Opaque": "معتم",
|
||||
"Font Size": "حجم الخط",
|
||||
"Text Edge Style": "نمط حواف النص",
|
||||
"None": "لا شيء",
|
||||
"Raised": "بارز",
|
||||
"Depressed": "منخفض",
|
||||
"Uniform": "منتظم",
|
||||
"Dropshadow": "ظل خلفي",
|
||||
"Font Family": "عائلة الخطوط",
|
||||
"Proportional Sans-Serif": "Proportional Sans-Serif",
|
||||
"Monospace Sans-Serif": "Monospace Sans-Serif",
|
||||
"Proportional Serif": "Proportional Serif",
|
||||
"Monospace Serif": "Monospace Serif",
|
||||
"Casual": "Casual",
|
||||
"Script": "Script",
|
||||
"Small Caps": "Small Caps",
|
||||
"Reset": "إعادة الضبط",
|
||||
"restore all settings to the default values": "استعادة كل الإعدادات إلى القيم الافتراضية",
|
||||
"Done": "تم",
|
||||
"Caption Settings Dialog": "مربع حوار إعدادات التعليقات التوضيحية",
|
||||
"Beginning of dialog window. Escape will cancel and close the window.": "بداية نافذة مربع حوار. الضغط على زر \"Escape\" سيؤدي إلى الإلغاء وإغلاق النافذة.",
|
||||
"End of dialog window.": "نهاية نافذة مربع حوار.",
|
||||
"{1} is loading.": "{1} قيد التحميل.",
|
||||
"Exit Picture-in-Picture": "خرج من وضع صورة داخل صورة",
|
||||
"Picture-in-Picture": "صورة داخل صورة",
|
||||
"No content": "لا يوجد محتوى"
|
||||
});
|
90
node_modules/videojs-ima/node_modules/@videojs/http-streaming/node_modules/video.js/dist/lang/ar.json
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"Play": "تشغيل",
|
||||
"Pause": "إيقاف",
|
||||
"Current Time": "الوقت الحالي",
|
||||
"Duration": "مدة",
|
||||
"Remaining Time": "الوقت المتبقي",
|
||||
"Stream Type": "نوع التيار",
|
||||
"LIVE": "مباشر",
|
||||
"Loaded": "تم التحميل",
|
||||
"Progress": "التقدم",
|
||||
"Fullscreen": "ملء الشاشة",
|
||||
"Non-Fullscreen": "تعطيل ملء الشاشة",
|
||||
"Mute": "صامت",
|
||||
"Unmute": "غير الصامت",
|
||||
"Playback Rate": "معدل التشغيل",
|
||||
"Subtitles": "الترجمة",
|
||||
"subtitles off": "إيقاف الترجمة",
|
||||
"Captions": "التعليقات",
|
||||
"captions off": "إيقاف التعليقات",
|
||||
"Chapters": "فصول",
|
||||
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
|
||||
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
|
||||
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
|
||||
"Play Video": "تشغيل الفيديو",
|
||||
"Close": "أغلق",
|
||||
"Modal Window": "نافذة مشروطة",
|
||||
"This is a modal window": "هذه نافذة مشروطة",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
|
||||
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
|
||||
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
|
||||
", selected": ", مختار",
|
||||
"Audio Player": "مشغل الصوت",
|
||||
"Video Player": "مشغل الفيديو",
|
||||
"Replay": "إعادة التشغيل",
|
||||
"Seek to live, currently behind live": "ذهاب إلى نقطة البث المباشر، متأخر عن البث المباشر حاليًا",
|
||||
"Seek to live, currently playing live": "ذهاب إلى نقطة البث المباشر، البث المباشر قيد التشغيل حاليًا",
|
||||
"Progress Bar": "شريط التقدم",
|
||||
"progress bar timing: currentTime={1} duration={2}": "{1} من {2}",
|
||||
"Descriptions": "الأوصاف",
|
||||
"descriptions off": "إخفاء الأوصاف",
|
||||
"Audio Track": "المسار الصوتي",
|
||||
"Volume Level": "مستوى الصوت",
|
||||
"The media is encrypted and we do not have the keys to decrypt it.": "الوسائط مشفرة وليس لدينا الرموز اللازمة لفك شفرتها.",
|
||||
"Close Modal Dialog": "إغلاق مربع الحوار المشروط",
|
||||
", opens descriptions settings dialog": "، يفتح مربع حوار إعدادات الأوصاف",
|
||||
"captions settings": "إعدادات التعليقات التوضيحية",
|
||||
"subtitles settings": "إعدادات الترجمات",
|
||||
"descriptions settings": "إعدادات الأوصاف",
|
||||
"Text": "النص",
|
||||
"White": "أبيض",
|
||||
"Black": "أسود",
|
||||
"Red": "أحمر",
|
||||
"Green": "أخضر",
|
||||
"Blue": "أزرق",
|
||||
"Yellow": "أصفر",
|
||||
"Magenta": "أرجواني",
|
||||
"Cyan": "أزرق سماوي",
|
||||
"Background": "الخلفية",
|
||||
"Window": "نافذة",
|
||||
"Transparent": "شفاف",
|
||||
"Semi-Transparent": "نصف شفاف",
|
||||
"Opaque": "معتم",
|
||||
"Font Size": "حجم الخط",
|
||||
"Text Edge Style": "نمط حواف النص",
|
||||
"None": "لا شيء",
|
||||
"Raised": "بارز",
|
||||
"Depressed": "منخفض",
|
||||
"Uniform": "منتظم",
|
||||
"Dropshadow": "ظل خلفي",
|
||||
"Font Family": "عائلة الخطوط",
|
||||
"Proportional Sans-Serif": "Proportional Sans-Serif",
|
||||
"Monospace Sans-Serif": "Monospace Sans-Serif",
|
||||
"Proportional Serif": "Proportional Serif",
|
||||
"Monospace Serif": "Monospace Serif",
|
||||
"Casual": "Casual",
|
||||
"Script": "Script",
|
||||
"Small Caps": "Small Caps",
|
||||
"Reset": "إعادة الضبط",
|
||||
"restore all settings to the default values": "استعادة كل الإعدادات إلى القيم الافتراضية",
|
||||
"Done": "تم",
|
||||
"Caption Settings Dialog": "مربع حوار إعدادات التعليقات التوضيحية",
|
||||
"Beginning of dialog window. Escape will cancel and close the window.": "بداية نافذة مربع حوار. الضغط على زر \"Escape\" سيؤدي إلى الإلغاء وإغلاق النافذة.",
|
||||
"End of dialog window.": "نهاية نافذة مربع حوار.",
|
||||
"{1} is loading.": "{1} قيد التحميل.",
|
||||
"Exit Picture-in-Picture": "خرج من وضع صورة داخل صورة",
|
||||
"Picture-in-Picture": "صورة داخل صورة",
|
||||
"No content": "لا يوجد محتوى"
|
||||
}
|