Skip to content

Conversation

@sebastianpiq
Copy link

@sebastianpiq sebastianpiq commented Feb 25, 2025

List MPD

This feature introduces support for List MPDs (MPD@type="list") and their Linked Periods.

Key aspects of the implementation:

  • Handling Linked Periods: When a Period contains an ImportedMPD element, it is a Linked Period, meaning its content is imported from an external MPD located at another path.
  • Playback Order: The first Period in a List MPD starts at PeriodStart = 0. Subsequent Linked Periods are resolved based on ImportedMPD@earliestResolutionTimeOffset.
  • List MPD Structure: A List MPD can contain both regular and Linked Periods, but Linked Periods can only exist within a List MPD.
  • Seamless Transitions: The player dynamically fetches and merges imported MPDs, ensuring smooth playback across Linked Periods.

Summary

This PR introduces support for List MPD profiles by implementing necessary parsing, handling, and playback functionalities.

Key changes include:

  • Recognition of List MPD Profile: Added logic to detect and process List MPDs.
  • Parsing Imported MPD Periods: Properly parses ImportedMPD tags within the manifest.
  • ListMpdController implementation:
    • Manages ImportedMPD and LinkedPeriod behaviors.
    • Handles seamless transitions between different Period types.
  • EarliestResolutionTimeOffset Handling: Ensures accurate timing of Imported MPDs based on earliestResolutionTimeOffset.
  • ManifestLoader updates: Now supports requesting Imported MPDs dynamically.
  • mergeManifest method: Resolves LinkedPeriod timing and merging conflicts.
  • New List MPD sample page: Provides a visual example for testing.
  • Unit Tests: Added tests for ListMpdController to validate functionality.

Testing

The following List MPD test cases cover various playback scenarios:

  1. Single Linked Period

    • The MPD contains a single Period linking to an Imported MPD.
  2. Multiple Linked Periods

    • The MPD has multiple Linked Periods, each referencing a different Imported MPD.
  3. Linked Period + Regular Period

    • One Linked Period is followed by a Regular Period.
  4. Regular Period + Linked Period

    • A Regular Period appears first, followed by a Linked Period.
  5. EarliestResolutionTime > minBufferTime

    • The earliestResolutionTime of the Linked Period is greater than minBufferTime.
  6. EarliestResolutionTime < minBufferTime

    • The earliestResolutionTime of the Linked Period is less than minBufferTime.
  7. Different Linked Period & Imported MPD Durations

    • The Linked Period references an Imported MPD with a mismatched duration.
  8. First List MPD Period with Start Time ≠ 0

    • The MPD type is List, but the first Period has a non-zero start time.
  9. Retry Scenario

    • The MPD is of type List, and the Imported MPD should not be downloadable.

Known Issues

  • Playback Freeze on Low Connectivity Streams
    • When switching Periods, if a low-connectivity stream has a low earliestResolutionTimeOffset, the GapController may cause the stream to freeze.
    • This issue occurs when handling a gap during a Period switch

Notes

  • This PR is based on the Dash draft (MDS24421_WG03_N01358_DASH-6th-edition_2nd_DraftFDIS_r17)

sebastianpiq and others added 30 commits November 29, 2024 11:43
Fix list mpd with a regular period as first period
…n-time

Mpd lists/zero earliest resolution time
…-error

Fix first period start time error
Co-authored-by: Sebastian Piquerez <89274285+sebastianpiq@users.noreply.github.com>
Resolve imported mpd url using list mpd BaseURL
…riod

Mpd lists/default start linked period
…ds (#61)

* Merge mpd level essentaial and suplemental properties to linked periods

* bug fix: some elements of imported period always overrides an element of the linked period

* rename mergeUniqueProperties and bugfix

* bugfix for undefined behaviour

* Update src/dash/DashAdapter.js

---------

Co-authored-by: Constanza Dibueno <constanzad@qualabs.com>
Co-authored-by: cotid-qualabs <121617928+cotid-qualabs@users.noreply.github.com>
Co-authored-by: Tatiana Perera <109090910+tatiana-perera@users.noreply.github.com>
Copy link

@emilsas emilsas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also first sync the changes with the last commit of dash.js in order to have this merged with the last changes in the codebase, it will help to resolve all conflicts before open a PR to dash.js

Also, check that all github actions pass successfully.

Comment on lines 45 to 53
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list0.mpd">Case 0: Single Linked Period</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list1.mpd">Case 1: Multiple Linked Period</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list2.mpd">Case 2: Linked Period + Regular Period</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list3.mpd">Case 3: Regular Period + Linked Period</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list4.mpd">Case 4: EarliestResolutionTime &gt; minBufferTime</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list5.mpd">Case 5: EarliestResolutionTime &lt; minBufferTime</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list6.mpd">Case 6: Different Linked Period and Imported Period durations</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list7.mpd">Case 7: First List MPD Period with start time =/ 0</a>
<a class="dropdown-item" data-url="https://comcast-dash-6-assets.s3.us-east-2.amazonaws.com/ListMPDs/bbb/list8.mpd">Case 8: Retry</a>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this samples will be hosted by us? (Thinking about the PR with the official dash.js repo)

Comment on lines 100 to 118
if (target.text === "Case 0: Single Linked Period") {
behavior.innerText = "The player should download the Imported MPD and reproduce the unique Period.";
} else if (target.text === "Case 1: Multiple Linked Period") {
behavior.innerText = "The player should download the first Imported MPD, reproduce its first Period, and, upon completion, download the second Imported MPD and reproduce its first Period.";
} else if (target.text === "Case 2: Linked Period + Regular Period") {
behavior.innerText = "The player should download the first Imported MPD, reproduce its first Period, and, upon completion, play the next regular Period.";
} else if (target.text === "Case 3: Regular Period + Linked Period") {
behavior.innerText = "The player should start by playing the first regular Period as usual and, upon its completion, download the linked Imported MPD and reproduce its first Period.";
} else if (target.text === "Case 4: EarliestResolutionTime > minBufferTime") {
behavior.innerText = "The player should start by playing the first regular Period as usual and, upon its completion, download the linked Imported MPD at startTime - earliestResolutionTime and reproduce its first Period";
} else if (target.text === "Case 5: EarliestResolutionTime < minBufferTime") {
behavior.innerText = "The player should start by playing the first regular Period as usual and, upon its completion, download the linked Imported MPD at with earliestResolutionTime = 0 and reproduce its first Period.";
} else if (target.text === "Case 6: Different Linked Period and Imported Period durations") {
behavior.innerText = "The player must respect the shortest duration between the Linked Period in the main manifest and the Imported MPD. Playback should seamlessly stop at the shorter duration, ensuring no content extends beyond the specified boundaries.";
} else if (target.text === "Case 7: First List MPD Period with start time =/ 0") {
behavior.innerText = "The player should throw an error indicating that the start time of the first period in a list type MPD manifest is invalid.";
} else if (target.text === "Case 8: Retry") {
behavior.innerText = "The player should attempt to download the manifest four times before failing.";
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this could be handled using an id in each option instead of comparing a text.

Comment on lines 648 to 649
.catch(error => {
console.error(error);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be handled by the errHandler, right?

const DEFAULT_EARLIEST_RESOLUTION_TIME_OFFSET = 60;

function ListMpdController() {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the other controllers, and they all have this space. I'm going to leave them like this to maintain the code style.

Comment on lines 92 to 94
if (manifest.Period[0].start) {
throw new Error('The first period in a list MPD must have start time equal to 0');
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this for only checking presence of start attr? In that case the error message is no suggesting that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In linked periods, the start attribute must be 0. If start has any value greater than 0, an error must be displayed.

The default value of manifest.Period[0].start is 0 if it is not present, so any value greater than 0 will result in an error.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to check if it is 0, it will be preferred to ask specifically for that. As it is right now it is suggesting if the attributte is present or not.

Comment on lines +125 to +134
.then((importedManifest) => {
dashAdapter.mergeManifests(manifest, importedManifest, period, mpdHasDuration);
}, () => {
dashAdapter.mergeManifests(manifest, null, period, mpdHasDuration);
})
.then(() => {
eventBus.trigger(Events.MANIFEST_UPDATED, { manifest });
linkedPeriodList = linkedPeriodList.filter((element) => element.id !== period.id);
resolve(manifest);
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error handling is missing

Comment on lines 326 to 328
if (importedManifest.hasOwnProperty(DashConstants.PROFILES)) {
importedPeriod.profiles = importedManifest.profiles;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must change to MPD level as it was discussed with Alex G.


if (linkedPeriods.length > 0) {
if (mpd.manifest.type !== DashConstants.MPD_LIST) {
throw new Error('Linked periods are only allowed in a list MPD');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say in an MPD with profile .... (DashConstants.MPD_LIST)

const eventBus = EventBus(context).getInstance();
const urlUtils = URLUtils(context).getInstance();

function ManifestLoader() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change is needed? It is tested that anything else is still working?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was implemented because the manifestLoader was changed to a singleton. In MediaPlayer, the ListMpdController is initialized before the manifestLoader, and an instance of it is needed.

It shouldn't be an issue that it's a singleton since there isn't another place where a new instance of manifestLoader is created.
Notice that the config code is moved to setConfig.

Anyway, after a quick look at the code, I think it might be possible to change the initialization order so that ListMpdController is initialized after manifestLoader (along with all playbackControllers), avoiding this change. I have to take a deeper look into it.

sebastianpiq and others added 6 commits March 21, 2025 16:20
* Fix merge imported profiles issue

* Fix imporetd mpd repeated profiles

* Fix wrong profile split by dot

* Check multiple profiles in mpd lists
[MpdLists] Minor code review changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants