Skip to content

Commit

Permalink
perf: Optimise DASH manifest generation (#870)
Browse files Browse the repository at this point in the history
  • Loading branch information
absidue authored Jan 13, 2025
1 parent 33c27dd commit 1a3d663
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 49 deletions.
54 changes: 27 additions & 27 deletions src/utils/DashManifest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -47,21 +47,21 @@ async function OTFPostLiveDvrSegmentInfo({ info }: { info: FSegmentInfo }) {
/>
))
}
</segment-timeline>
</segment-template>;
</segmentTimeline>
</segmentTemplate>;
}

function SegmentInfo({ info }: { info: FSegmentInfo }) {
if (info.is_oft || info.is_post_live_dvr) {
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>
</>;
}

Expand All @@ -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"
Expand All @@ -99,7 +99,7 @@ async function DashManifest({
<period>
{
audio_sets.map((set, index) => (
<adaptation-set
<adaptationSet
id={index}
mimeType={set.mime_type}
startWithSAP="1"
Expand All @@ -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}
/>
Expand All @@ -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}
/>
Expand All @@ -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"
Expand All @@ -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}
/>
Expand All @@ -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"
Expand All @@ -217,24 +217,24 @@ 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"
/>
</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}
Expand All @@ -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(
Expand Down
32 changes: 10 additions & 22 deletions src/utils/DashUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,15 @@ 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(
tagNameOrFunction: string | ((props: DashProps) => DashNode | Promise<DashNode>),
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 });
Expand All @@ -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) {
Expand Down

0 comments on commit 1a3d663

Please sign in to comment.