Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DASH: Make use of multiple BaseURL elements, where more than one is defined. #771

Closed
Bastian35022 opened this issue Sep 8, 2015 · 30 comments
Assignees

Comments

@Bastian35022
Copy link
Contributor

From what i saw, the BaseURL element in the DASH MPD is generally supported by the ExoPlayer. However, it does not seem to support multiple/alternative segment locations, as described in ISO/IEC 23009-1:2014 5.6.5. Do you plan on adding this?

@ojw28
Copy link
Contributor

ojw28 commented Sep 8, 2015

What would you expect the client to do with them? All the specification says is: "In the absence of other criteria, the DASH Client may use the first BaseURL element as base URI".

@ojw28 ojw28 added the question label Sep 8, 2015
@Bastian35022
Copy link
Contributor Author

It also says

5.6.5 Alternative base URLs
If alternative base URLs are provided through the BaseURL element at any level, identical Segments shall be accessible at multiple locations. In the absence of other criteria, the DASH Client may use the first BaseURL element as “base URI". The DASH Client may use base URLs provided in the BaseURL element as “base URI” and may implement any suitable algorithm to determine which URLs it uses for requests.

So if multiple alternative base URLs are indicated (as I understood, by declaring them in the same element / on the same level), the client could e.g. start with any base URL, and try another base URL if it can't get a segment from the previous one.

This is of course an effort vs. sophistication thing.

@ojw28
Copy link
Contributor

ojw28 commented Sep 8, 2015

It kind of depends what "other criteria" is supposed to mean. The fact that the specification doesn't define what these criteria should be kind of indicates that the criteria should be specific to the server-side streaming infrastructure (e.g. YouTube may have different criteria to an application using Akamai's CDN). Obviously we don't know the specifics, so we need to either implement something generic enough to be sensible for all infrastructures, or make it pluggable, or do nothing.

For now, I think we're fine just using the first BaseURL. Which we don't currently do, since the current code will end up picking the last one. I'll fix this.

@Bastian35022
Copy link
Contributor Author

I totally agree about the infrastructure dependencies. And creating a small generic interface for multiple base URLs would be very nice, such as offering multiple base URLs in RangedUri or Representation instances.

@ojw28 ojw28 changed the title DASH BaseURL element support for indication of multiple locations DASH: Make use of multiple BaseURL elements, where more than one is defined. Sep 10, 2015
@pakerfeldt
Copy link
Contributor

This is on my plate as well right now. If there's any more input on this I'll gladly take it. In our case we want to be able to failover to another CDN if necessary. But I prefer to implement it such that it can go upstream rather than just fork and hack.

@abhiguru
Copy link

It picks the first one for the load and if there is a timeout it tries the other base URLs sequentially ? (ideally be based on latency imo)

@pakerfeldt
Copy link
Contributor

I was thinking of having the failover logic to be an application specific implementation. Maybe with some sane default to use though. I, for instance, have a pretty specific kind of behavior I want to add but I don't necessarily want to enforce it on everyone.

@pakerfeldt
Copy link
Contributor

@ojw28 Do you have any input on this? Making this pluggable is not trivial since segmentBase and initilizationUri both creates the baseUrl during mpd parsing. I'm currently experimenting with having a list of baseUrls in these to see where I get. But my approach to solve this might differ significantly depending on the likeliness of getting such change merged upstream since I want to diverge from upstream/master as little as possible.

@Bastian35022
Copy link
Contributor Author

@pakerfeldt I also implemented a list of baseUris in the RangedUri class, and all the necessary parsing, recently. I will update this and push it to a fork, so you can have a look if you want to.

@Bastian35022
Copy link
Contributor Author

Created a pull request for this (#1250).
@ojw28 Maybe we can find a solution to expose multiple locations in some way (either to the app or for implementing a dedicated interface), without limiting it to specific use-cases and without affecting too much of the framework? In the pull request, the locations are exposed in the RangedUri class, and I only touched DASH-related code.

I guess the ideal solution would be to modify the baseUri to be used in general, so without doing it for every single chunk. This could of course be achieved by introducing a LocationSelector class that holds the different baseUris, is referenced by the RangedUri instances, and is exposed per representation (because the set of baseUris can be different for every Representation). The problems here are:

  • Changing the baseUri to be used will not affect already unsuccessfully requested chunks. For that, we'd have to integrate the LocationSelector into the DataSpec class as i see it.
  • Exposing the LocationSelector instances directly to the application probably breaks with some design principles, as i see it. I think location steering should be implemented in the player after all, similarly to the FormatEvaluator implementations.

@pakerfeldt
Copy link
Contributor

I hacked away this afternoon and ended up with something similar to what you have @Bastian35022. It's not very well thought through. I just did minimal work to get something close to what I need. I wrote a BaseUrlSelector interface that is passed to DashChunkSource constructor and used by DashChunkSource when creating the DataSpecs. Then I wrote one FirstBaseUrlSelector as default implementation along with my own selector. Will share what I have soon to add to the discussion.

However, it's crucial for me to get this upstream. I don't want this kind of modification locally since it would make future exoplayer bump a big PITA. In that case, I would prefer hooking up an interceptor to OkHttp to solve the problem.

@pakerfeldt
Copy link
Contributor

And here's my current work in progress: pakerfeldt@291aea5

@Bastian35022
Copy link
Contributor Author

Looks good in principle i think.

It seems though, that we have a different understanding on how alternative base Urls are signaled in the MPD. Unfortunately, the spec is not 100% clear on how this should be signaled. The most reliable info i could find on this is http://www-itec.uni-klu.ac.at/dash/?page_id=958, with some example MPDs. There, multiple locations are signaled using multiple BaseUrl elements on the same level.

In your case, the baseUrls from different levels are assembled, and while that might also be valid, it gets tricky to still support proper reference resolution as well i think. Do you need to support this kind of MPD layout?

@pakerfeldt
Copy link
Contributor

At this point, I didn't really care how it was implemented since I only had multiple BaseUrls on the same level (Period in my case).

But looking at ISO/IEC 23009-1:2014(E) it states:

URLs at each level of the MPD are resolved according to RFC3986 with respect to the BaseURL element specified at that level of the document or the level above in the case of resolving base URLs themselves (the document “base URI” as defined in RFC 3986 Section 5.1 is considered to be the level above the MPD level).

This is still not super clear. Strictly reading, to me this sounds like URLs at each level should only be resolved using BaseUrls on the same level. BaseUrls themselves however, should use the resolved BaseUrl on the level above. However, that would mean we would not be able to resolve URLs on a level where a BaseUrl has not been specified, which of course doesn't make sense. That leads to the question: Should URL resolving on one level always be allowed to use BaseUrls on the level above or only if that level does not contain any BaseUrls already? I guess it could be argued that the lack of BaseUrls on a level could be considered as one single relative BaseUrl containing the empty string "", thus inheriting BaseUrls on the level above.

As an example:

Level BaseURLs Resolved BaseURLs
MPD http://example.org/ http://example.org/
Period http://sub1.example.org/
http://sub2.example.org/
http://sub1.example.org/
http://sub2.example.org/
Adaptation Set http://alt.example.org/segments/
/segments/
http://alt.example.org/segments/
http://sub1.example.org/segments/
http://sub2.example.org/segments/
Representation http://alt.example.org/segments/
http://sub1.example.org/segments/
http://sub2.example.org/segments/

@Bastian35022
Copy link
Contributor Author

I agree about the inheritance, and about it being unclear.

How about doing it like this then:

  • If a BaseURL element contains a relative url, it is interpreted relatively to the resolved base URL of the next higher level.
  • If a BaseURL element contains an absolute url, it is set as the resolved base URL of that level (i.e. resolved base URLs of higher levels are not considered).
  • If multiple BaseURL elements are present on one level, they are:
    • Taken directly as resolved base URLs of that level if they are absolute URLs, or
    • Interpreted relatively to the resolved base URL of the next higher level, and the results are the resolved base URLs of that level.
  • For simplicity: If multiple relative BaseURL elements are present on one level, and the next higher level already has multiple resolved base URLs, a ParserException is raised

@pakerfeldt
Copy link
Contributor

I agree with the first three bullets, and that's pretty much how my example table behaves, right?

However, to your last point, why not let all relative BaseURL elements be resolved using all absolute BaseURL elements of the above level? Two relative BaseURLs with three resolved BaseURLs on the level above would lead to six new resolved BaseURLs on that level. At least that's how I envision it to work. I added another commit to my branch with this behavior implemented (I believe). Please have a look.

I made a simple OkHttp Interceptor that fails my segment requests randomly and it seems to handle failover just the way I want.

@Bastian35022
Copy link
Contributor Author

The reason was to avoid the implementation effort, and because i can't imagine someone actually mixing BaseURLs like this, but it's of course the better solution. I will take a look later.

@pakerfeldt
Copy link
Contributor

That part of the implementation was actually very straight forward. I will smoothen the commits out and create a PR for us to review and reason around.

@Bastian35022
Copy link
Contributor Author

Looks good!

@pakerfeldt
Copy link
Contributor

And here it is: #1259

@ojw28
Copy link
Contributor

ojw28 commented Nov 4, 2016

We're merging a change into dev-v2 shortly that decouples baseURLs from RangedUri and SegmentBase, which might make this significantly easy to do in a way that's both clean and technically correct.

ojw28 pushed a commit that referenced this issue Nov 10, 2016
Issue: #771

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=138399124
@matamegger
Copy link
Contributor

Checking in on this feature request. How is the priority on this issue? Is it somewhere on your road map?

@sjurtf
Copy link

sjurtf commented Jan 23, 2020

Hi, checking in here as well. Is it possible for you to squeeze this feature in some time soon?
Adding the point that there is some demand for this feature.

@jero3000
Copy link

jero3000 commented Jun 1, 2020

Hi, checking in here as well. According to the document "DASH-IF Interoperability: Guidelines for implementations v4.1", section "4.8.2.1 General Robustness":

"Similarly, if the DASH access client receives an HTTP client error (i.e. messages with 4xx
error code) for the request of a Media Segment, the requested Media Segment may not be
available anymore or may not be available yet. In both these case the client should check
if the precision of the time synchronization to a globally accurate time standard or to the
time offered in the MPD is sufficiently accurate. If the clock is believed accurate, or the
error re-occurs after any correction, the client should check for an update of the MPD. If
multiple BaseURL elements are available, the client may also check for alternative in-
stances of the same content that are hosted on a different server.
"

Is there any intention to implement this behavior in a future Exoplayer version?

@ferolpt
Copy link

ferolpt commented Dec 2, 2020

Hi, any news regarding this feature of having multiple BaseURL on the manifest?
"If multiple BaseURL elements are available, the client may also check for alternative in-
stances of the same content that are hosted on a different server."

marcbaechinger added a commit that referenced this issue Jul 27, 2021
Issues: #771 and #7654
PiperOrigin-RevId: 386850707
@brozikcz
Copy link

brozikcz commented Sep 1, 2021

Hi guys, I probably have one issue with multiple baseURL in the downloads / offline feature.
What URL is used to download chunks when the DASH playlist contains multiple URLs? Because when I try to play the downloaded content so the playback randomly doesn't work because

 BaseUrl selectedBaseUrl = baseUrlExclusionList.selectBaseUrl(representation.baseUrls);

randomly select URL but just one Is downloaded / cached.

Or I'm overlooking something?

@marcbaechinger
Copy link
Contributor

Thanks for reporting. I created #9370 to track this. We need to have a way to make the choice of the base URL deterministic at download and playback time.

@brozikcz
Copy link

Hi, it's me again...
Another question about this feature.

I probably don't understand correctly how it works with multiple AdaptationSet in MPD (DASH). Because the instance of BaseUrlExclusionList is the same for all AdaptationSets (video / audio) and when the video failed on one location the DefaultDashChunkSource add location (one BaseUrl) into blacklist

  baseUrlExclusionList.exclude(
          representationHolder.selectedBaseUrl, fallbackSelection.exclusionDurationMs);

but this will be applied for all next sets and in the case when the MPD playlist contains "just" two BaseUrls so for the next AdaptationSet with audio will recognize

fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION)

as false because:

  /* numberOfExcludedLocations= */ priorityCount
            - baseUrlExclusionList.getPriorityCountAfterExclusion(baseUrls),

and the audio AdaptionSet will don't have any next available location. Is it right?

@marcbaechinger
Copy link
Contributor

If there is a load error with the current base URL, all base URLs with the same priority or service location are excluded. The next time a base URL needs to be selected, the selection only considers the base URLs that are not yet excluded.

For your example this means, if there are only two base URLs, then only one base URL can be excluded. If after this, another load error for audio segments occurs that tried loading from the new base URL, then there is no further fallback available.

However, the scenario you are describing looks like you were hit by a bug that called the LoadErrorHandlingPolicy again for audio after video has failed already for the given base URL. This has been fixed in dev-v2 that will land in the next release.

What is the problem you are experiencing? Can you give me some more details or try with the fix from above in dev-v2 to verify if you've been hit by this bug?

@brozikcz
Copy link

Heh, thank you. I tried the build from dev-v2 and that fixed my issue.

@google google locked and limited conversation to collaborators Sep 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants