mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-26 00:02:09 +00:00
perf: Optimise DASH manifest generation (#870)
This commit is contained in:
@@ -32,13 +32,13 @@ async function OTFPostLiveDvrSegmentInfo({ info }: { info: FSegmentInfo }) {
|
||||
|
||||
const template = await info.getSegmentTemplate();
|
||||
|
||||
return <segment-template
|
||||
return <segmentTemplate
|
||||
startNumber={template.init_url ? '1' : '0'}
|
||||
timescale="1000"
|
||||
initialization={template.init_url}
|
||||
media={template.media_url}
|
||||
>
|
||||
<segment-timeline>
|
||||
<segmentTimeline>
|
||||
{
|
||||
template.timeline.map((segment_duration) => (
|
||||
<s
|
||||
@@ -47,8 +47,8 @@ async function OTFPostLiveDvrSegmentInfo({ info }: { info: FSegmentInfo }) {
|
||||
/>
|
||||
))
|
||||
}
|
||||
</segment-timeline>
|
||||
</segment-template>;
|
||||
</segmentTimeline>
|
||||
</segmentTemplate>;
|
||||
}
|
||||
|
||||
function SegmentInfo({ info }: { info: FSegmentInfo }) {
|
||||
@@ -56,12 +56,12 @@ function SegmentInfo({ info }: { info: FSegmentInfo }) {
|
||||
return <OTFPostLiveDvrSegmentInfo info={info} />;
|
||||
}
|
||||
return <>
|
||||
<base-url>
|
||||
<baseURL>
|
||||
{info.base_url}
|
||||
</base-url>
|
||||
<segment-base indexRange={`${info.index_range.start}-${info.index_range.end}`}>
|
||||
</baseURL>
|
||||
<segmentBase indexRange={`${info.index_range.start}-${info.index_range.end}`}>
|
||||
<initialization range={`${info.init_range.start}-${info.init_range.end}`} />
|
||||
</segment-base>
|
||||
</segmentBase>
|
||||
</>;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ async function DashManifest({
|
||||
|
||||
// XXX: DASH spec: https://standards.iso.org/ittf/PubliclyAvailableStandards/c083314_ISO_IEC%2023009-1_2022(en).zip
|
||||
|
||||
return <mpd
|
||||
return <mPD
|
||||
xmlns="urn:mpeg:dash:schema:mpd:2011"
|
||||
minBufferTime="PT1.500S"
|
||||
profiles="urn:mpeg:dash:profile:isoff-main:2011"
|
||||
@@ -99,7 +99,7 @@ async function DashManifest({
|
||||
<period>
|
||||
{
|
||||
audio_sets.map((set, index) => (
|
||||
<adaptation-set
|
||||
<adaptationSet
|
||||
id={index}
|
||||
mimeType={set.mime_type}
|
||||
startWithSAP="1"
|
||||
@@ -125,7 +125,7 @@ async function DashManifest({
|
||||
}
|
||||
{
|
||||
set.channels &&
|
||||
<audio-channel-configuration
|
||||
<audioChannelConfiguration
|
||||
schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
|
||||
value={set.channels}
|
||||
/>
|
||||
@@ -140,7 +140,7 @@ async function DashManifest({
|
||||
>
|
||||
{
|
||||
rep.channels &&
|
||||
<audio-channel-configuration
|
||||
<audioChannelConfiguration
|
||||
schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
|
||||
value={rep.channels}
|
||||
/>
|
||||
@@ -149,12 +149,12 @@ async function DashManifest({
|
||||
</representation>
|
||||
))
|
||||
}
|
||||
</adaptation-set>
|
||||
</adaptationSet>
|
||||
))
|
||||
}
|
||||
{
|
||||
video_sets.map((set, index) => (
|
||||
<adaptation-set
|
||||
<adaptationSet
|
||||
id={index + audio_sets.length}
|
||||
mimeType={set.mime_type}
|
||||
startWithSAP="1"
|
||||
@@ -166,21 +166,21 @@ async function DashManifest({
|
||||
>
|
||||
{
|
||||
set.color_info.primaries &&
|
||||
<supplemental-property
|
||||
<supplementalProperty
|
||||
schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries"
|
||||
value={set.color_info.primaries}
|
||||
/>
|
||||
}
|
||||
{
|
||||
set.color_info.transfer_characteristics &&
|
||||
<supplemental-property
|
||||
<supplementalProperty
|
||||
schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics"
|
||||
value={set.color_info.transfer_characteristics}
|
||||
/>
|
||||
}
|
||||
{
|
||||
set.color_info.matrix_coefficients &&
|
||||
<supplemental-property
|
||||
<supplementalProperty
|
||||
schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients"
|
||||
value={set.color_info.matrix_coefficients}
|
||||
/>
|
||||
@@ -199,12 +199,12 @@ async function DashManifest({
|
||||
</representation>
|
||||
))
|
||||
}
|
||||
</adaptation-set>
|
||||
</adaptationSet>
|
||||
))
|
||||
}
|
||||
{
|
||||
image_sets.map(async (set, index) => {
|
||||
return <adaptation-set
|
||||
return <adaptationSet
|
||||
id={index + audio_sets.length + video_sets.length}
|
||||
mimeType={await set.getMimeType()}
|
||||
contentType="image"
|
||||
@@ -217,11 +217,11 @@ async function DashManifest({
|
||||
width={rep.sheet_width}
|
||||
height={rep.sheet_height}
|
||||
>
|
||||
<essential-property
|
||||
<essentialProperty
|
||||
schemeIdUri="http://dashif.org/thumbnail_tile"
|
||||
value={`${rep.columns}x${rep.rows}`}
|
||||
/>
|
||||
<segment-template
|
||||
<segmentTemplate
|
||||
media={rep.template_url}
|
||||
duration={rep.template_duration}
|
||||
startNumber="0"
|
||||
@@ -229,12 +229,12 @@ async function DashManifest({
|
||||
</representation>
|
||||
))
|
||||
}
|
||||
</adaptation-set>;
|
||||
</adaptationSet>;
|
||||
})
|
||||
}
|
||||
{
|
||||
text_sets.map((set, index) => {
|
||||
return <adaptation-set
|
||||
return <adaptationSet
|
||||
id={index + audio_sets.length + video_sets.length + image_sets.length}
|
||||
mimeType={set.mime_type}
|
||||
lang={set.language}
|
||||
@@ -255,15 +255,15 @@ async function DashManifest({
|
||||
id={set.representation.uid}
|
||||
bandwidth="0"
|
||||
>
|
||||
<base-url>
|
||||
<baseURL>
|
||||
{set.representation.base_url}
|
||||
</base-url>
|
||||
</baseURL>
|
||||
</representation>
|
||||
</adaptation-set>;
|
||||
</adaptationSet>;
|
||||
})
|
||||
}
|
||||
</period>
|
||||
</mpd>;
|
||||
</mPD>;
|
||||
}
|
||||
|
||||
export function toDash(
|
||||
|
||||
@@ -33,11 +33,7 @@ function escapeXMLString(str: string) {
|
||||
}
|
||||
|
||||
function normalizeTag(tag: string) {
|
||||
if (tag === 'mpd') return 'MPD';
|
||||
if (tag === 'base-url') return 'BaseURL';
|
||||
|
||||
const sections = tag.split('-');
|
||||
return sections.map((section) => section.charAt(0).toUpperCase() + section.slice(1)).join('');
|
||||
return tag.charAt(0).toUpperCase() + tag.slice(1);
|
||||
}
|
||||
|
||||
export function createElement(
|
||||
@@ -45,7 +41,7 @@ export function createElement(
|
||||
props: { [key: string] : unknown } | null | undefined,
|
||||
...children: DashChild[]
|
||||
): DashNode | Promise<DashNode> {
|
||||
const normalizedChildren = children.flat().map((child) => typeof child === 'string' ? createTextElement(child) : child);
|
||||
const normalizedChildren = children.flat();
|
||||
|
||||
if (typeof tagNameOrFunction === 'function') {
|
||||
return tagNameOrFunction({ ...props, children: normalizedChildren });
|
||||
@@ -60,26 +56,18 @@ export function createElement(
|
||||
};
|
||||
}
|
||||
|
||||
export function createTextElement(text: string): DashNode {
|
||||
return {
|
||||
type: 'TEXT_ELEMENT',
|
||||
props: { nodeValue: text }
|
||||
};
|
||||
}
|
||||
|
||||
export async function renderElementToString(element: DashNode): Promise<string> {
|
||||
if (element.type === 'TEXT_ELEMENT')
|
||||
return escapeXMLString(typeof element.props.nodeValue === 'string' ? element.props.nodeValue : '');
|
||||
export async function renderElementToString(element: DashNode | string): Promise<string> {
|
||||
if (typeof element === 'string')
|
||||
return escapeXMLString(element);
|
||||
|
||||
let dom = `<${element.type}`;
|
||||
|
||||
if (element.props) {
|
||||
const properties = Object.keys(element.props)
|
||||
.filter((key) => ![ 'children', 'nodeValue' ].includes(key) && element.props[key] !== undefined)
|
||||
.map((name) => `${name}="${escapeXMLString(`${element.props[name]}`)}"`);
|
||||
|
||||
if (properties.length > 0)
|
||||
dom += ` ${properties.join(' ')}`;
|
||||
for (const key of Object.keys(element.props)) {
|
||||
if (key !== 'children' && element.props[key] !== undefined) {
|
||||
dom += ` ${key}="${escapeXMLString(`${element.props[key]}`)}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (element.props.children) {
|
||||
|
||||
Reference in New Issue
Block a user