Simplify export and filter manifests from dash generation.

This commit is contained in:
Kavin 2023-03-02 14:18:53 +00:00
parent bf0fb000e3
commit acff16a8d4
No known key found for this signature in database
GPG key ID: 49451E4482CC5BCD
2 changed files with 183 additions and 179 deletions

View file

@ -283,9 +283,10 @@ export default {
mime = "application/x-mpegURL"; mime = "application/x-mpegURL";
} else if (this.video.audioStreams.length > 0 && !lbry && MseSupport) { } else if (this.video.audioStreams.length > 0 && !lbry && MseSupport) {
if (!this.video.dash) { if (!this.video.dash) {
const dash = ( const dash = (await import("../utils/DashUtils.js")).generate_dash_file_from_formats(
await import("@/utils/DashUtils.js").then(mod => mod.default) streams,
).generate_dash_file_from_formats(streams, this.video.duration); this.video.duration,
);
uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(dash); uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(dash);
} else { } else {

View file

@ -4,201 +4,204 @@ import { Buffer } from "buffer";
window.Buffer = Buffer; window.Buffer = Buffer;
import { json2xml } from "xml-js"; import { json2xml } from "xml-js";
const DashUtils = { export function generate_dash_file_from_formats(VideoFormats, VideoLength) {
generate_dash_file_from_formats(VideoFormats, VideoLength) { const generatedJSON = generate_xmljs_json_from_data(VideoFormats, VideoLength);
const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength); return json2xml(generatedJSON);
return json2xml(generatedJSON); }
},
generate_xmljs_json_from_data(VideoFormatArray, VideoLength) { function generate_xmljs_json_from_data(VideoFormatArray, VideoLength) {
const convertJSON = { const convertJSON = {
declaration: { declaration: {
attributes: { attributes: {
version: "1.0", version: "1.0",
encoding: "utf-8", encoding: "utf-8",
},
}, },
elements: [ },
{ elements: [
type: "element", {
name: "MPD", type: "element",
attributes: { name: "MPD",
xmlns: "urn:mpeg:dash:schema:mpd:2011", attributes: {
profiles: "urn:mpeg:dash:profile:full:2011", xmlns: "urn:mpeg:dash:schema:mpd:2011",
minBufferTime: "PT1.5S", profiles: "urn:mpeg:dash:profile:full:2011",
type: "static", minBufferTime: "PT1.5S",
mediaPresentationDuration: `PT${VideoLength}S`, type: "static",
}, mediaPresentationDuration: `PT${VideoLength}S`,
elements: [
{
type: "element",
name: "Period",
elements: this.generate_adaptation_set(VideoFormatArray),
},
],
}, },
], elements: [
}; {
return convertJSON; type: "element",
}, name: "Period",
generate_adaptation_set(VideoFormatArray) { elements: generate_adaptation_set(VideoFormatArray),
const adaptationSets = []; },
],
},
],
};
return convertJSON;
}
let mimeAudioObjs = []; function generate_adaptation_set(VideoFormatArray) {
const adaptationSets = [];
VideoFormatArray.forEach(videoFormat => { let mimeAudioObjs = [];
// the dual formats should not be used
if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) { 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; return;
} }
}
const audioTrackId = videoFormat.audioTrackId; mimeAudioObjs.push({
const mimeType = videoFormat.mimeType; audioTrackId,
mimeType,
for (let i = 0; i < mimeAudioObjs.length; i++) { videoFormats: [videoFormat],
const mimeAudioObj = mimeAudioObjs[i];
if (mimeAudioObj.audioTrackId == audioTrackId && mimeAudioObj.mimeType == mimeType) {
mimeAudioObj.videoFormats.push(videoFormat);
return;
}
}
mimeAudioObjs.push({
audioTrackId,
mimeType,
videoFormats: [videoFormat],
});
}); });
});
mimeAudioObjs.forEach(mimeAudioObj => { mimeAudioObjs.forEach(mimeAudioObj => {
const adapSet = { const adapSet = {
type: "element", type: "element",
name: "AdaptationSet", name: "AdaptationSet",
attributes: { attributes: {
id: mimeAudioObj.audioTrackId, id: mimeAudioObj.audioTrackId,
lang: mimeAudioObj.audioTrackId?.substr(0, 2), lang: mimeAudioObj.audioTrackId?.substr(0, 2),
mimeType: mimeAudioObj.mimeType, mimeType: mimeAudioObj.mimeType,
startWithSAP: "1", startWithSAP: "1",
subsegmentAlignment: "true", subsegmentAlignment: "true",
}, },
elements: [], elements: [],
}; };
let isVideoFormat = false; let isVideoFormat = false;
if (mimeAudioObj.mimeType.includes("video")) { if (mimeAudioObj.mimeType.includes("video")) {
isVideoFormat = true; isVideoFormat = true;
} }
if (isVideoFormat) {
adapSet.attributes.scanType = "progressive";
}
for (var i = 0; i < mimeAudioObj.videoFormats.length; i++) {
const videoFormat = mimeAudioObj.videoFormats[i];
if (isVideoFormat) { 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++) { adaptationSets.push(adapSet);
const videoFormat = mimeAudioObj.videoFormats[i]; });
if (isVideoFormat) { return adaptationSets;
adapSet.elements.push(this.generate_representation_video(videoFormat)); }
} else {
adapSet.elements.push(this.generate_representation_audio(videoFormat));
}
}
adaptationSets.push(adapSet); function generate_representation_audio(Format) {
}); const representation = {
return adaptationSets; type: "element",
}, name: "Representation",
generate_representation_audio(Format) { attributes: {
const representation = { id: Format.itag,
type: "element", codecs: Format.codec,
name: "Representation", bandwidth: Format.bitrate,
attributes: { },
id: Format.itag, elements: [
codecs: Format.codec, {
bandwidth: Format.bitrate, type: "element",
name: "AudioChannelConfiguration",
attributes: {
schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
value: "2",
},
}, },
elements: [ {
{ type: "element",
type: "element", name: "BaseURL",
name: "AudioChannelConfiguration", elements: [
attributes: { {
schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011", type: "text",
value: "2", 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",
type: "element", name: "SegmentBase",
name: "BaseURL", attributes: {
elements: [ indexRange: `${Format.indexStart}-${Format.indexEnd}`,
{
type: "text",
text: Format.url,
},
],
}, },
{ elements: [
type: "element", {
name: "SegmentBase", type: "element",
attributes: { name: "Initialization",
indexRange: `${Format.indexStart}-${Format.indexEnd}`, attributes: {
range: `${Format.initStart}-${Format.initEnd}`,
},
}, },
elements: [ ],
{ },
type: "element", ],
name: "Initialization", };
attributes: { return representation;
range: `${Format.initStart}-${Format.initEnd}`, }
},
},
],
},
],
};
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;
}