diff --git a/src/components/VideoPlayer.vue b/src/components/VideoPlayer.vue index 148fb0db..7ae1926e 100644 --- a/src/components/VideoPlayer.vue +++ b/src/components/VideoPlayer.vue @@ -283,9 +283,10 @@ export default { mime = "application/x-mpegURL"; } else if (this.video.audioStreams.length > 0 && !lbry && MseSupport) { if (!this.video.dash) { - const dash = ( - await import("@/utils/DashUtils.js").then(mod => mod.default) - ).generate_dash_file_from_formats(streams, this.video.duration); + const dash = (await import("../utils/DashUtils.js")).generate_dash_file_from_formats( + streams, + this.video.duration, + ); uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(dash); } else { diff --git a/src/utils/DashUtils.js b/src/utils/DashUtils.js index 0cba5885..f0d6dcde 100644 --- a/src/utils/DashUtils.js +++ b/src/utils/DashUtils.js @@ -4,201 +4,204 @@ import { Buffer } from "buffer"; window.Buffer = Buffer; import { json2xml } from "xml-js"; -const DashUtils = { - generate_dash_file_from_formats(VideoFormats, VideoLength) { - const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength); - return json2xml(generatedJSON); - }, - generate_xmljs_json_from_data(VideoFormatArray, VideoLength) { - const convertJSON = { - declaration: { - attributes: { - version: "1.0", - encoding: "utf-8", - }, +export function generate_dash_file_from_formats(VideoFormats, VideoLength) { + const generatedJSON = generate_xmljs_json_from_data(VideoFormats, VideoLength); + return json2xml(generatedJSON); +} + +function generate_xmljs_json_from_data(VideoFormatArray, VideoLength) { + const convertJSON = { + declaration: { + attributes: { + version: "1.0", + encoding: "utf-8", }, - elements: [ - { - type: "element", - name: "MPD", - attributes: { - xmlns: "urn:mpeg:dash:schema:mpd:2011", - profiles: "urn:mpeg:dash:profile:full:2011", - minBufferTime: "PT1.5S", - type: "static", - mediaPresentationDuration: `PT${VideoLength}S`, - }, - elements: [ - { - type: "element", - name: "Period", - elements: this.generate_adaptation_set(VideoFormatArray), - }, - ], + }, + elements: [ + { + type: "element", + name: "MPD", + attributes: { + xmlns: "urn:mpeg:dash:schema:mpd:2011", + profiles: "urn:mpeg:dash:profile:full:2011", + minBufferTime: "PT1.5S", + type: "static", + mediaPresentationDuration: `PT${VideoLength}S`, }, - ], - }; - return convertJSON; - }, - generate_adaptation_set(VideoFormatArray) { - const adaptationSets = []; + elements: [ + { + type: "element", + name: "Period", + elements: generate_adaptation_set(VideoFormatArray), + }, + ], + }, + ], + }; + return convertJSON; +} - let mimeAudioObjs = []; +function generate_adaptation_set(VideoFormatArray) { + const adaptationSets = []; - VideoFormatArray.forEach(videoFormat => { - // the dual formats should not be used - if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) { + let mimeAudioObjs = []; + + VideoFormatArray.forEach(videoFormat => { + // the dual formats should not be used + if ( + (videoFormat.mimeType.includes("video") && !videoFormat.videoOnly) || + videoFormat.mimeType.includes("application") + ) { + return; + } + + const audioTrackId = videoFormat.audioTrackId; + const mimeType = videoFormat.mimeType; + + for (let i = 0; i < mimeAudioObjs.length; i++) { + const mimeAudioObj = mimeAudioObjs[i]; + + if (mimeAudioObj.audioTrackId == audioTrackId && mimeAudioObj.mimeType == mimeType) { + mimeAudioObj.videoFormats.push(videoFormat); return; } + } - const audioTrackId = videoFormat.audioTrackId; - const mimeType = videoFormat.mimeType; - - for (let i = 0; i < mimeAudioObjs.length; i++) { - const mimeAudioObj = mimeAudioObjs[i]; - - if (mimeAudioObj.audioTrackId == audioTrackId && mimeAudioObj.mimeType == mimeType) { - mimeAudioObj.videoFormats.push(videoFormat); - return; - } - } - - mimeAudioObjs.push({ - audioTrackId, - mimeType, - videoFormats: [videoFormat], - }); + mimeAudioObjs.push({ + audioTrackId, + mimeType, + videoFormats: [videoFormat], }); + }); - mimeAudioObjs.forEach(mimeAudioObj => { - const adapSet = { - type: "element", - name: "AdaptationSet", - attributes: { - id: mimeAudioObj.audioTrackId, - lang: mimeAudioObj.audioTrackId?.substr(0, 2), - mimeType: mimeAudioObj.mimeType, - startWithSAP: "1", - subsegmentAlignment: "true", - }, - elements: [], - }; + mimeAudioObjs.forEach(mimeAudioObj => { + const adapSet = { + type: "element", + name: "AdaptationSet", + attributes: { + id: mimeAudioObj.audioTrackId, + lang: mimeAudioObj.audioTrackId?.substr(0, 2), + mimeType: mimeAudioObj.mimeType, + startWithSAP: "1", + subsegmentAlignment: "true", + }, + elements: [], + }; - let isVideoFormat = false; + let isVideoFormat = false; - if (mimeAudioObj.mimeType.includes("video")) { - isVideoFormat = true; - } + if (mimeAudioObj.mimeType.includes("video")) { + isVideoFormat = true; + } + if (isVideoFormat) { + adapSet.attributes.scanType = "progressive"; + } + + for (var i = 0; i < mimeAudioObj.videoFormats.length; i++) { + const videoFormat = mimeAudioObj.videoFormats[i]; if (isVideoFormat) { - adapSet.attributes.scanType = "progressive"; + adapSet.elements.push(generate_representation_video(videoFormat)); + } else { + adapSet.elements.push(generate_representation_audio(videoFormat)); } + } - for (var i = 0; i < mimeAudioObj.videoFormats.length; i++) { - const videoFormat = mimeAudioObj.videoFormats[i]; - if (isVideoFormat) { - adapSet.elements.push(this.generate_representation_video(videoFormat)); - } else { - adapSet.elements.push(this.generate_representation_audio(videoFormat)); - } - } + adaptationSets.push(adapSet); + }); + return adaptationSets; +} - adaptationSets.push(adapSet); - }); - return adaptationSets; - }, - generate_representation_audio(Format) { - const representation = { - type: "element", - name: "Representation", - attributes: { - id: Format.itag, - codecs: Format.codec, - bandwidth: Format.bitrate, +function generate_representation_audio(Format) { + const representation = { + type: "element", + name: "Representation", + attributes: { + id: Format.itag, + codecs: Format.codec, + bandwidth: Format.bitrate, + }, + elements: [ + { + type: "element", + name: "AudioChannelConfiguration", + attributes: { + schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011", + value: "2", + }, }, - elements: [ - { - type: "element", - name: "AudioChannelConfiguration", - attributes: { - schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011", - value: "2", + { + type: "element", + name: "BaseURL", + elements: [ + { + type: "text", + text: Format.url, }, - }, - { - type: "element", - name: "BaseURL", - elements: [ - { - type: "text", - text: Format.url, - }, - ], - }, - { - type: "element", - name: "SegmentBase", - attributes: { - indexRange: `${Format.indexStart}-${Format.indexEnd}`, - }, - elements: [ - { - type: "element", - name: "Initialization", - attributes: { - range: `${Format.initStart}-${Format.initEnd}`, - }, - }, - ], - }, - ], - }; - return representation; - }, - generate_representation_video(Format) { - const representation = { - type: "element", - name: "Representation", - attributes: { - id: Format.itag, - codecs: Format.codec, - bandwidth: Format.bitrate, - width: Format.width, - height: Format.height, - maxPlayoutRate: "1", - frameRate: Format.fps, + ], }, - elements: [ - { - type: "element", - name: "BaseURL", - elements: [ - { - type: "text", - text: Format.url, - }, - ], + { + type: "element", + name: "SegmentBase", + attributes: { + indexRange: `${Format.indexStart}-${Format.indexEnd}`, }, - { - type: "element", - name: "SegmentBase", - attributes: { - indexRange: `${Format.indexStart}-${Format.indexEnd}`, + elements: [ + { + type: "element", + name: "Initialization", + attributes: { + range: `${Format.initStart}-${Format.initEnd}`, + }, }, - elements: [ - { - type: "element", - name: "Initialization", - attributes: { - range: `${Format.initStart}-${Format.initEnd}`, - }, - }, - ], - }, - ], - }; - return representation; - }, -}; + ], + }, + ], + }; + return representation; +} -export default DashUtils; +function generate_representation_video(Format) { + const representation = { + type: "element", + name: "Representation", + attributes: { + id: Format.itag, + codecs: Format.codec, + bandwidth: Format.bitrate, + width: Format.width, + height: Format.height, + maxPlayoutRate: "1", + frameRate: Format.fps, + }, + elements: [ + { + type: "element", + name: "BaseURL", + elements: [ + { + type: "text", + text: Format.url, + }, + ], + }, + { + type: "element", + name: "SegmentBase", + attributes: { + indexRange: `${Format.indexStart}-${Format.indexEnd}`, + }, + elements: [ + { + type: "element", + name: "Initialization", + attributes: { + range: `${Format.initStart}-${Format.initEnd}`, + }, + }, + ], + }, + ], + }; + return representation; +}