Piped/src/utils/DashUtils.js

189 lines
6.6 KiB
JavaScript
Raw Normal View History

2021-02-24 09:35:41 +00:00
// Based of https://github.com/GilgusMaximus/yt-dash-manifest-generator/blob/master/src/DashGenerator.js
const xml = require("xml-js");
2021-02-24 09:35:41 +00:00
const DashUtils = {
generate_dash_file_from_formats(VideoFormats, VideoLength) {
const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength);
return xml.json2xml(generatedJSON);
2021-02-24 09:35:41 +00:00
},
generate_xmljs_json_from_data(VideoFormatArray, VideoLength) {
const convertJSON = {
declaration: {
attributes: {
version: "1.0",
encoding: "utf-8",
},
2021-02-24 09:35:41 +00:00
},
elements: [
2021-02-24 09:35:41 +00:00
{
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`,
2021-02-24 09:35:41 +00:00
},
elements: [
2021-02-24 09:35:41 +00:00
{
type: "element",
name: "Period",
elements: this.generate_adaptation_set(VideoFormatArray),
},
],
},
],
};
return convertJSON;
2021-02-24 09:35:41 +00:00
},
generate_adaptation_set(VideoFormatArray) {
const adaptationSets = [];
const mimeTypes = [];
const mimeObjects = [[]];
2021-02-24 09:35:41 +00:00
// sort the formats by mime types
VideoFormatArray.forEach(videoFormat => {
2021-02-24 09:35:41 +00:00
// the dual formats should not be used
if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) {
return;
2021-02-24 09:35:41 +00:00
}
// if these properties are not available, then we skip it because we cannot set these properties
//if (!(videoFormat.hasOwnProperty('initRange') && videoFormat.hasOwnProperty('indexRange'))) {
// return
//}
const mimeType = videoFormat.mimeType;
const mimeTypeIndex = mimeTypes.indexOf(mimeType);
2021-02-24 09:35:41 +00:00
if (mimeTypeIndex > -1) {
mimeObjects[mimeTypeIndex].push(videoFormat);
2021-02-24 09:35:41 +00:00
} else {
mimeTypes.push(mimeType);
mimeObjects.push([]);
mimeObjects[mimeTypes.length - 1].push(videoFormat);
2021-02-24 09:35:41 +00:00
}
});
2021-02-24 09:35:41 +00:00
// for each MimeType generate a new Adaptation set with Representations as sub elements
for (let i = 0; i < mimeTypes.length; i++) {
let isVideoFormat = false;
2021-02-24 09:35:41 +00:00
const adapSet = {
type: "element",
name: "AdaptationSet",
attributes: {
id: i,
mimeType: mimeTypes[i],
startWithSAP: "1",
subsegmentAlignment: "true",
2021-02-24 09:35:41 +00:00
},
elements: [],
};
2021-02-24 09:35:41 +00:00
if (!mimeTypes[i].includes("audio")) {
adapSet.attributes.scanType = "progressive";
isVideoFormat = true;
2021-02-24 09:35:41 +00:00
}
mimeObjects[i].forEach(format => {
2021-02-24 09:35:41 +00:00
if (isVideoFormat) {
adapSet.elements.push(this.generate_representation_video(format));
2021-02-24 09:35:41 +00:00
} else {
adapSet.elements.push(this.generate_representation_audio(format));
2021-02-24 09:35:41 +00:00
}
});
adaptationSets.push(adapSet);
2021-02-24 09:35:41 +00:00
}
return adaptationSets;
},
generate_representation_audio(Format) {
const representation = {
type: "element",
name: "Representation",
attributes: {
id: Format.itag,
codecs: Format.codec,
bandwidth: Format.bitrate,
2021-02-24 09:35:41 +00:00
},
elements: [
2021-02-24 09:35:41 +00:00
{
type: "element",
name: "AudioChannelConfiguration",
attributes: {
schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
value: "2",
2021-02-24 09:35:41 +00:00
},
},
{
type: "element",
name: "BaseURL",
elements: [
2021-02-24 09:35:41 +00:00
{
type: "text",
text: Format.url,
},
],
2021-02-24 09:35:41 +00:00
},
{
type: "element",
name: "SegmentBase",
attributes: {
indexRange: `${Format.indexStart}-${Format.indexEnd}`,
2021-02-24 09:35:41 +00:00
},
elements: [
2021-02-24 09:35:41 +00:00
{
type: "element",
name: "Initialization",
attributes: {
range: `${Format.initStart}-${Format.initEnd}`,
},
},
],
},
],
};
return representation;
2021-02-24 09:35:41 +00:00
},
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,
2021-02-24 09:35:41 +00:00
},
elements: [
2021-02-24 09:35:41 +00:00
{
type: "element",
name: "BaseURL",
elements: [
2021-02-24 09:35:41 +00:00
{
type: "text",
text: Format.url,
},
],
2021-02-24 09:35:41 +00:00
},
{
type: "element",
name: "SegmentBase",
attributes: {
indexRange: `${Format.indexStart}-${Format.indexEnd}`,
2021-02-24 09:35:41 +00:00
},
elements: [
2021-02-24 09:35:41 +00:00
{
type: "element",
name: "Initialization",
attributes: {
range: `${Format.initStart}-${Format.initEnd}`,
},
},
],
},
],
};
return representation;
},
};
2021-02-24 09:35:41 +00:00
export default DashUtils;