### Getting Started Source: https://github.com/xqq/mpegts.js/blob/master/README.md Basic usage of mpegts.js to play a live stream. ```html ``` -------------------------------- ### Installation Source: https://github.com/xqq/mpegts.js/blob/master/README.md Install mpegts.js using npm. ```bash npm install --save mpegts.js ``` -------------------------------- ### Local Storage Functions Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html Helper functions for getting and setting demo settings in local storage. ```javascript function ls_get(key, def) { try { var ret = localStorage.getItem('mpegts_demo.' + key); if (ret === null) { ret = def; } return ret; } catch (e) {} return def; } function ls_set(key, value) { try { localStorage.setItem('mpegts_demo.' + key, value); } catch (e) {} } ``` -------------------------------- ### Debug Commands Source: https://github.com/xqq/mpegts.js/blob/master/README.md Commands for installing dependencies, build tools, and building the project for debugging. ```bash npm install # install dev-dependencies npm install -g webpack-cli # install build tool npm run build:debug # packaged & minimized js will be emitted in dist folder ``` -------------------------------- ### CORS Header Example Source: https://github.com/xqq/mpegts.js/blob/master/docs/cors.md Example of an Access-Control-Allow-Origin header for a specific origin. ```http Access-Control-Allow-Origin: http://flvplayback.com ``` -------------------------------- ### Sample Input for Multipart Playback Source: https://github.com/xqq/mpegts.js/blob/master/docs/multipart.md An example of a JSON input conforming to the MediaDataSource structure for multipart FLV playback, demonstrating the expected format for 'type', 'duration', and 'segments' with specific values for duration, filesize, and URL. ```json { "type": "flv", "duration": 1373161, "segments": [ { "duration": 333438, "filesize": 60369190, "url": "http://127.0.0.1/flv/7182741-1.flv" },{ "duration": 390828, "filesize": 75726439, "url": "http://127.0.0.1/flv/7182741-2.flv" },{ "duration": 434453, "filesize": 103453988, "url": "http://127.0.0.1/flv/7182741-3.flv" },{ "duration": 214442, "filesize": 44189200, "url": "http://127.0.0.1/flv/7182741-4.flv" } ] } ``` -------------------------------- ### Local Storage Functions Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html Functions to get and set items in local storage for persisting demo settings. ```javascript function ls_get(key, def) { try { var ret = localStorage.getItem('mpegts_demo.' + key); if (ret === null) { ret = def; } return ret; } catch (e) {} return def; } function ls_set(key, value) { try { localStorage.setItem('mpegts_demo.' + key, value); } catch (e) {} } ``` -------------------------------- ### Build Source: https://github.com/xqq/mpegts.js/blob/master/README.md Steps to build the project. ```bash npm install # install dev-dependencies npm install -g webpack-cli # install build tool npm run build # packaged & minimized js will be emitted in dist folder ``` -------------------------------- ### DOM Content Loaded Event Listener Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html Initializes the demo by loading settings, showing the version, and loading the player when the DOM is ready. ```javascript document.addEventListener('DOMContentLoaded', function () { streamURL = document.getElementById('streamURL'); mediaSourceURL = document.getElementById('mediaSourceURL'); loadSettings(); showVersion(); player_load(); }); ``` -------------------------------- ### Settings Saving and Loading Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html Functions to save the current demo settings to local storage and load them on initialization. ```javascript function saveSettings() { if (mediaSourceURL.className === '') { ls_set('inputMode', 'MediaDataSource'); } else { ls_set('inputMode', 'StreamURL'); } var i; for (i = 0; i < checkBoxFields.length; i++) { var field = checkBoxFields[i]; /** @type {HTMLInputElement} */ var checkbox = document.getElementById(field); ls_set(field, checkbox.checked ? '1' : '0'); } var msURL = document.getElementById('msURL'); var sURL = document.getElementById('sURL'); ls_set('msURL', msURL.value); ls_set('sURL', sURL.value); console.log('save'); } function loadSettings() { var i; for (i = 0; i < checkBoxFields.length; i++) { var field = checkBoxFields[i]; /** @type {HTMLInputElement} */ var checkbox = document.getElementById(field); var c = ls_get(field, checkbox.checked ? '1' : '0'); checkbox.checked = c === '1' ? true : false; } var msURL = document.getElementById('msURL'); var sURL = document.getElementById('sURL'); msURL.value = ls_get('msURL', msURL.value); sURL.value = ls_get('sURL', sURL.value); if (ls_get('inputMode', 'StreamURL') === 'StreamURL') { switch_url(); } else { switch_mds(); } } ``` -------------------------------- ### Sample HTTP FLV source Source: https://github.com/xqq/mpegts.js/blob/master/docs/livestream.md Configuration for an HTTP FLV livestream. ```json { // HTTP FLV "type": "flv", "isLive": true, "url": "http://127.0.0.1:8080/live/livestream.flv" } ``` -------------------------------- ### Sample WebSocket source Source: https://github.com/xqq/mpegts.js/blob/master/docs/livestream.md Configuration for an MPEG2-TS/FLV over WebSocket livestream. ```json { // MPEG2-TS/FLV over WebSocket "type": "mse", "isLive": true, "url": "ws://127.0.0.1:9090/live/livestream.flv" } ``` -------------------------------- ### DOM Content Loaded Event Listener Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html Initializes settings, shows version, and loads the player when the DOM is fully loaded. ```javascript document.addEventListener('DOMContentLoaded', function () { streamURL = document.getElementById('streamURL'); mediaSourceURL = document.getElementById('mediaSourceURL'); loadSettings(); showVersion(); player_load(); }); ``` -------------------------------- ### URL and MediaDataSource Switching Functions Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html Functions to switch between stream URL input and MediaDataSource JSON input modes. ```javascript function switch_url() { streamURL.className = ''; mediaSourceURL.className = 'hidden'; saveSettings(); } function switch_mds() { streamURL.className = 'hidden'; mediaSourceURL.className = ''; saveSettings(); } ``` -------------------------------- ### Player Control Functions Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html JavaScript functions for loading, playing, pausing, destroying, and seeking within the media player. ```javascript function player_load() { console.log('isSupported: ' + mpegts.isSupported()); if (mediaSourceURL.className === '') { var url = document.getElementById('msURL').value; var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = function (e) { var mediaDataSource = JSON.parse(xhr.response); player_load_mds(mediaDataSource); } xhr.send(); } else { var i; var mediaDataSource = { type: 'mse' }; for (i = 0; i < checkBoxFields.length; i++) { var field = checkBoxFields[i]; /** @type {HTMLInputElement} */ var checkbox = document.getElementById(field); mediaDataSource[field] = checkbox.checked; } mediaDataSource['url'] = document.getElementById('sURL').value; console.log('MediaDataSource', mediaDataSource); player_load_mds(mediaDataSource); } } function player_load_mds(mediaDataSource) { var element = document.getElementsByName('videoElement')[0]; if (typeof player !== "undefined") { if (player != null) { player.unload(); player.detachMediaElement(); player.destroy(); player = null; } } player = mpegts.createPlayer(mediaDataSource, { enableWorker: true, lazyLoadMaxDuration: 3 * 60, seekType: 'range', liveBufferLatencyChasing: document.getElementById('liveBufferLatencyChasing').checked, }); player.attachMediaElement(element); player.load(); } function player_start() { player.play(); } function player_pause() { player.pause(); } function player_destroy() { player.pause(); player.unload(); player.detachMediaElement(); player.destroy(); player = null; } function player_seekto() { var input = document.getElementsByName('seekpoint')[0]; player.currentTime = parseFloat(input.value); } ``` -------------------------------- ### Sample MPEG2-TS over HTTP source Source: https://github.com/xqq/mpegts.js/blob/master/docs/livestream.md Configuration for an MPEG2-TS over HTTP livestream. ```json { // MPEG2-TS over HTTP "type": "mpegts", "isLive": true, "url": "http://127.0.0.1:8080/live/livestream.ts" } ``` -------------------------------- ### Show Version Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html Updates the document title to include the mpegts.js version. ```javascript function showVersion() { var version = mpegts.version; document.title = document.title + " (v" + version + ")"; } ``` -------------------------------- ### isSupported() Source: https://github.com/xqq/mpegts.js/blob/master/docs/api.md Checks if basic playback is supported in the current browser. ```javascript function isSupported(): boolean; ``` -------------------------------- ### URL and Settings Switching Functions Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html JavaScript functions to switch between stream URL and media source URL inputs, and to save settings. ```javascript function switch_url() { streamURL.className = ''; mediaSourceURL.className = 'hidden'; saveSettings(); } function switch_mds() { streamURL.className = 'hidden'; mediaSourceURL.className = ''; saveSettings(); } ``` -------------------------------- ### Log Listener Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html Adds a listener to capture and display mpegts.js logs in a textarea. ```javascript var logcatbox = document.getElementsByName('logcatbox')[0]; mpegts.LoggingControl.addLogListener(function(type, str) { logcatbox.value = logcatbox.value + str + '\n'; logcatbox.scrollTop = logcatbox.scrollHeight; }); ``` -------------------------------- ### Event Listener for Stream URL Input Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html Handles Enter key press on the stream URL input to save settings and reload the player. ```javascript var sURL = document.getElementById('sURL'); sURL.onkeyup = function(event) { if (event.key === 'Enter' || event.keyCode === 13) { saveSettings() if (player != null) { player.unload(); player.detachMediaElement(); player.destroy(); player = null; } player_load(); } }; ``` -------------------------------- ### Version Display Source: https://github.com/xqq/mpegts.js/blob/master/demo/index.html Function to display the mpegts.js version on the page title. ```javascript function showVersion() { var version = mpegts.version; document.title = document.title + " (v" + version + ")"; } ``` -------------------------------- ### Save and Load Settings Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html Functions to save the current ARIB caption transmit mode and input mode to local storage, and to load them back. ```javascript function saveSettings() { if (document.getElementById('radio_private_stream_1').checked) { arib_caption_transmit_mode = 'private_stream_1'; ls_set('aribCaptionTransmitMode', 'private_stream_1'); } else if (document.getElementById('radio_timed_id3').checked) { arib_caption_transmit_mode = 'timed_id3'; ls_set('aribCaptionTransmitMode', 'timed_id3'); } if (mediaSourceURL.className === '') { ls_set('inputMode', 'MediaDataSource'); } else { ls_set('inputMode', 'StreamURL'); } var i; for (i = 0; i < checkBoxFields.length; i++) { var field = checkBoxFields[i]; /** @type {HTMLInputElement} */ var checkbox = document.getElementById(field); ls_set(field, checkbox.checked ? '1' : '0'); } var msURL = document.getElementById('msURL'); var sURL = document.getElementById('sURL'); ls_set('msURL', msURL.value); ls_set('sURL', sURL.value); console.log('save'); } function loadSettings() { arib_caption_transmit_mode = ls_get('aribCaptionTransmitMode', 'private_stream_1'); if (arib_caption_transmit_mode == "timed_id3") { document.getElementById('radio_private_stream_1').checked = false; document.getElementById('radio_timed_id3').checked = true; } var i; for (i = 0; i < checkBoxFields.length; i++) { var field = checkBoxFields[i]; /** @type {HTMLInputElement} */ var checkbox = document.getElementById(field); var c = ls_get(field, checkbox.checked ? '1' : '0'); checkbox.checked = c === '1' ? true : false; } var msURL = document.getElementById('msURL'); var sURL = document.getElementById('sURL'); msURL.value = ls_get('msURL', msURL.value); sURL.value = ls_get('sURL', sURL.value); if (ls_get('inputMode', 'StreamURL') === 'StreamURL') { switch_url(); } else { switch_mds(); } } ``` -------------------------------- ### Static File Playback Header Source: https://github.com/xqq/mpegts.js/blob/master/docs/cors.md Recommended header for static MPEG2-TS/FLV file playback to expose Content-Length. ```http Access-Control-Expose-Headers: Content-Length ``` -------------------------------- ### MSEPlayer Interface Source: https://github.com/xqq/mpegts.js/blob/master/docs/api.md Interface for MSE (Media Source Extensions) player. ```typescript interface MSEPlayer extends Player {} ``` -------------------------------- ### ARIB Caption and Superimposition Logic Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html JavaScript code demonstrating how to handle private stream data for ARIB captions and superimposition, including parsing malformed PES packets and rendering them using aribb24.js. ```javascript var checkBoxFields = ['isLive', 'withCredentials', 'liveSync']; var streamURL, mediaSourceURL; var arib_caption_transmit_mode; function parseMalformedPES(data) { var PES_scrambling_control = (data[0] & 0x30) >>> 4; var PTS_DTS_flags = (data[1] & 0xC0) >>> 6; var PES_header_data_length = data[2]; var payload_start_index = 3 + PES_header_data_length; var payload_length = data.byteLength - payload_start_index; var payload = data.subarray(payload_start_index, payload_start_index + payload_length); return payload; } function player_load() { console.log('isSupported: ' + mpegts.getFeatureList().mseLivePlayback); if (mediaSourceURL.className === '') { var url = document.getElementById('msURL').value; var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = function (e) { var mediaDataSource = JSON.parse(xhr.response); player_load_mds(mediaDataSource); } xhr.send(); } else { var i; var mediaDataSource = { type: 'mse' }; for (i = 0; i < checkBoxFields.length; i++) { var field = checkBoxFields[i]; /** @type {HTMLInputElement} */ var checkbox = document.getElementById(field); mediaDataSource[field] = checkbox.checked; } mediaDataSource['url'] = document.getElementById('sURL').value; console.log('MediaDataSource', mediaDataSource); player_load_mds(mediaDataSource); } } function player_load_mds(mediaDataSource) { var element = document.getElementsByName('videoElement')[0]; if (typeof player !== "undefined") { if (player != null) { player.unload(); player.detachMediaElement(); player.destroy(); player = null; } if (captionRenderer != null) { captionRenderer.dispose(); captionRenderer = null; } if (superimposeRenderer != null) { superimposeRenderer.dispose(); superimposeRenderer = null; } } player = mpegts.createPlayer(mediaDataSource, { enableWorker: true, enableWorkerForMSE: true, liveSync: document.getElementById('liveSync').checked, }); player.attachMediaElement(element); player.load(); captionRenderer = new aribb24js.CanvasRenderer({ data_identifer: 0x80, forceStrokeColor: 'black', normalFont: '"Windows TV MaruGothic", "Hiragino Maru Gothic Pro", "HGMaruGothicMPRO", "Yu Gothic Medium", sans-serif', gaijiFont: '"Windows TV MaruGothic", "Hiragino Maru Gothic Pro", "HGMaruGothicMPRO", "Yu Gothic Medium", sans-serif', drcsReplacement: true, useStrokeText: true, }); captionRenderer.attachMedia(element); captionRenderer.show(); superimposeRenderer = new aribb24js.CanvasRenderer({ data_identifer: 0x81, forceStrokeColor: 'black', normalFont: '"Windows TV MaruGothic", "Hiragino Maru Gothic Pro", "HGMaruGothicMPRO", "Yu Gothic Medium", sans-serif', gaijiFont: '"Windows TV MaruGothic", "Hiragino Maru Gothic Pro", "HGMaruGothicMPRO", "Yu Gothic Medium", sans-serif', drcsReplacement: true, useStrokeText: true, }); superimposeRenderer.attachMedia(element); superimposeRenderer.show(); player.on(mpegts.Events.PES_PRIVATE_DATA_ARRIVED, function(data) { if (arib_caption_transmit_mode !== 'private_stream_1') { return; } if (data.stream_id === 0xBD && data.data[0] === 0x80) { // private_stream_1, caption captionRenderer.pushData(data.pid, data.data, data.pts / 1000); } else if (data.stream_id === 0xBF) { // private_stream_2, superimpose var payload = data.data; if (payload[0] !== 0x81) { payload = parseMalformedPES(data.data); } if (payload[0] !== 0x81) { return; } superimposeRenderer.pushData(data.pid, payload, data.nearest_pts / 1000); } }); /* var process = []; player.on(mpegts.Events.SMPTE2038_METADATA_ARRIVED, function(data) { const pts = data.pts; for (const ancillary of data.ancillaries) { const { user_data } = ancillary; // header 4 byte const end_packet_flag = (user_data[2] & 0x20) !== 0; const start_packet_flag = (user_data[2] & 0x40) !== 0; // timing 12 byte if (start_packet_flag && end_packet_flag) { const offset = 16; const packet = user_data.slice(offset, offset + 188); const header = 4; const adaptation_field_length = packet[header]; const pes = packet.slice(header + 1 + adaptation_field_length); const pes_header = 6; const pes_offset = pes_header + 3 + pes[pes_header + 2]; const data = pes.slice(pes_offset); captionRenderer.pushData(data.pid, data, pts / 1000); console.log(pts, Array.from(data).map((e) => e.toString(16))) } } }); */ player.on(mpegts.Events.TIMED_ID3_METADATA_ARRIVED, function(data) { if (arib_caption_transmit_mode !== 'timed_id3') { return; } captionRenderer.pushID3v2Data(data.pts / 1000, data.data); }); player.on(mpegts.Events.ASYNCHRONOUS_KLV_METADATA_ARRIVED, function(data) { console.log('sync', data); }) player.on(mpegts.Events.PES_PRIVATE_DATA_DESCRIPTOR, function ``` -------------------------------- ### Player Interface (abstract) Source: https://github.com/xqq/mpegts.js/blob/master/docs/api.md Abstract interface defining the core player functionalities. ```typescript interface Player { constructor(mediaDataSource: MediaDataSource, config?: Config): Player; destroy(): void; on(event: string, listener: Function): void; off(event: string, listener: Function): void; attachMediaElement(mediaElement: HTMLMediaElement): void; detachMediaElement(): void; load(): void; unload(): void; play(): Promise; pause(): void; type: string; buffered: TimeRanges; duration: number; volume: number; muted: boolean; currentTime: number; mediaInfo: Object; statisticsInfo: Object; } ``` -------------------------------- ### Player Control Functions Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html JavaScript functions for controlling the media player, including play, pause, destroy, and seek. ```javascript function player_start() { player.play(); } function player_pause() { player.pause(); } function player_destroy() { player.pause(); player.unload(); player.detachMediaElement(); player.destroy(); player = null; } function player_seekto() { var input = document.getElementsByName('seekpoint')[0]; player.currentTime = parseFloat(input.value); } ``` -------------------------------- ### createPlayer Function Signature Source: https://github.com/xqq/mpegts.js/blob/master/docs/api.md The function signature for mpegts.createPlayer, which creates a player instance. ```typescript function createPlayer(mediaDataSource: MediaDataSource, config?: Config): Player; ``` -------------------------------- ### Stream URL Key Up Handler Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html Handles the Enter key press on the stream URL input to save settings and reload the player. ```javascript var sURL = document.getElementById('sURL'); sURL.onkeyup = function(event) { if (event.key === 'Enter' || event.keyCode === 13) { saveSettings() if (player != null) { player.unload(); player.detachMediaElement(); player.destroy(); player = null; } player_load(); } }; ``` -------------------------------- ### getFeatureList() Source: https://github.com/xqq/mpegts.js/blob/master/docs/api.md Retrieves a list of supported features and their status. ```javascript function getFeatureList(): FeatureList; ``` -------------------------------- ### Log Listener Source: https://github.com/xqq/mpegts.js/blob/master/demo/arib.html Adds a listener to mpegts.LoggingControl to display log messages in a textarea. ```javascript var logcatbox = document.getElementsByName('logcatbox')[0]; mpegts.LoggingControl.addLogListener(function(type, str) { logcatbox.value = logcatbox.value + str + '\n'; logcatbox.scrollTop = logcatbox.scrollHeight; }); ``` -------------------------------- ### NativePlayer Interface Source: https://github.com/xqq/mpegts.js/blob/master/docs/api.md Interface for native browser player wrapper, useful for single-part MP4 playback. ```typescript interface NativePlayer extends Player {} ``` -------------------------------- ### Wildcard CORS Header Source: https://github.com/xqq/mpegts.js/blob/master/docs/cors.md Using a wildcard value for Access-Control-Allow-Origin to allow any request origin. ```http Access-Control-Allow-Origin: * ``` -------------------------------- ### Preflight OPTIONS Response Headers Source: https://github.com/xqq/mpegts.js/blob/master/docs/cors.md Required CORS headers for the server's response to an OPTIONS request for Range seek. ```http Access-Control-Allow-Origin: | * Access-Control-Allow-Methods: GET, OPTIONS Access-Control-Allow-Headers: range ``` -------------------------------- ### Basic CORS Header Source: https://github.com/xqq/mpegts.js/blob/master/docs/cors.md The server must respond with an Access-Control-Allow-Origin header when playing streams from another Origin. ```http Access-Control-Allow-Origin: | * ``` -------------------------------- ### MediaDataSource Structure for Multipart Playback Source: https://github.com/xqq/mpegts.js/blob/master/docs/multipart.md This JSON structure defines the format for providing a playlist for MediaDataSource when using FLV type for multipart playback. It includes details about the stream type, duration, CORS settings, audio/video presence, and a list of segments with their respective durations, file sizes, and URLs. ```json { // Required "type": "flv", // Only flv type supports multipart playback // Optional "duration": 12345678, // total duration, in milliseconds "cors": true, "withCredentials": false, // Optional // true by default, do not indicate unless you have to deal with audio-only or video-only stream "hasAudio": true, "hasVideo": true, // Required "segments": [ { "duration": 1234, // in milliseconds "filesize": 5678, // in bytes "url": "http://cdn.flvplayback.com/segments-1.flv" }, { "duration": 2345, "filesize": 6789, "url": "http://cdn.flvplayback.com/segments-2.flv" }, { "duration": 4567, "filesize": 7890, "url": "http://cdn.flvplayback.com/segments-3.flv" } // more segments... ] } ``` -------------------------------- ### LoggingControl Interface Source: https://github.com/xqq/mpegts.js/blob/master/docs/api.md Global interface for controlling mpegts.js log verbosity levels. ```typescript interface LoggingControl { forceGlobalTag: boolean; globalTag: string; enableAll: boolean; enableDebug: boolean; enableVerbose: boolean; enableInfo: boolean; enableWarn: boolean; enableError: boolean; getConfig(): Object; applyConfig(config: Object): void; addLogListener(listener: Function): void; removeLogListener(listener: Function): void; } ``` -------------------------------- ### CORS with 301/302 Redirect Source: https://github.com/xqq/mpegts.js/blob/master/docs/cors.md Required CORS header for the redirection's response when a 3xx redirection occurs. ```http Access-Control-Allow-Origin: null | * ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.