mirror of
https://github.com/TeamPiped/Piped.git
synced 2024-11-27 16:07:26 +00:00
189 lines
6.6 KiB
JavaScript
189 lines
6.6 KiB
JavaScript
// Based of https://github.com/GilgusMaximus/yt-dash-manifest-generator/blob/master/src/DashGenerator.js
|
|
|
|
const xml = require("xml-js");
|
|
|
|
const DashUtils = {
|
|
generate_dash_file_from_formats(VideoFormats, VideoLength) {
|
|
const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength);
|
|
return xml.json2xml(generatedJSON);
|
|
},
|
|
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),
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
return convertJSON;
|
|
},
|
|
generate_adaptation_set(VideoFormatArray) {
|
|
const adaptationSets = [];
|
|
const mimeTypes = [];
|
|
const mimeObjects = [[]];
|
|
// sort the formats by mime types
|
|
VideoFormatArray.forEach(videoFormat => {
|
|
// the dual formats should not be used
|
|
if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) {
|
|
return;
|
|
}
|
|
// 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);
|
|
if (mimeTypeIndex > -1) {
|
|
mimeObjects[mimeTypeIndex].push(videoFormat);
|
|
} else {
|
|
mimeTypes.push(mimeType);
|
|
mimeObjects.push([]);
|
|
mimeObjects[mimeTypes.length - 1].push(videoFormat);
|
|
}
|
|
});
|
|
// for each MimeType generate a new Adaptation set with Representations as sub elements
|
|
for (let i = 0; i < mimeTypes.length; i++) {
|
|
let isVideoFormat = false;
|
|
const adapSet = {
|
|
type: "element",
|
|
name: "AdaptationSet",
|
|
attributes: {
|
|
id: i,
|
|
mimeType: mimeTypes[i],
|
|
startWithSAP: "1",
|
|
subsegmentAlignment: "true",
|
|
},
|
|
elements: [],
|
|
};
|
|
if (!mimeTypes[i].includes("audio")) {
|
|
adapSet.attributes.scanType = "progressive";
|
|
isVideoFormat = true;
|
|
}
|
|
mimeObjects[i].forEach(format => {
|
|
if (isVideoFormat) {
|
|
adapSet.elements.push(this.generate_representation_video(format));
|
|
} else {
|
|
adapSet.elements.push(this.generate_representation_audio(format));
|
|
}
|
|
});
|
|
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,
|
|
},
|
|
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: "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}`,
|
|
},
|
|
elements: [
|
|
{
|
|
type: "element",
|
|
name: "Initialization",
|
|
attributes: {
|
|
range: `${Format.initStart}-${Format.initEnd}`,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
return representation;
|
|
},
|
|
};
|
|
|
|
export default DashUtils;
|