mirror of
https://github.com/mmjee/Piped-Material.git
synced 2024-12-06 19:26:36 +01:00
191 lines
5.1 KiB
JavaScript
191 lines
5.1 KiB
JavaScript
// Based of https://github.com/GilgusMaximus/yt-dash-manifest-generator/blob/master/src/DashGenerator.js
|
|
|
|
import xml from '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 {
|
|
DashUtils
|
|
}
|