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

DynamicConcatenatingMediaSource question #3400

Closed
Tolriq opened this issue Oct 27, 2017 · 10 comments
Closed

DynamicConcatenatingMediaSource question #3400

Tolriq opened this issue Oct 27, 2017 · 10 comments
Labels

Comments

@Tolriq
Copy link
Contributor

Tolriq commented Oct 27, 2017

ExoPlayer 2.5.4

I'm trying to implement DynamicConcatenatingMediaSource and have managed to do it for simple use cases.

My problem is that for some types of media I need to start a transcode session on the server and obviously can't start them all when filling the playlist. Only the media currently buffering should start this. (So actual and next one)

I'm trying to understand where and how to properly integrate that and I'm a little lost :(

  1. Is prepareSource() from MediaSource called on a background thread and only when the player will actually buffer the media?

  2. If yes any reason why ExtractorMediaSource is final as overriding this simple function would solve my use case :)

  3. If no then where should I insert my start Transcoding

@tonihei
Copy link
Collaborator

tonihei commented Oct 27, 2017

DynamicConcatenatingMediaSource uses other MediaSources for the single playback items. These are the ones you add when you call for example dynamicConcatenatingMediaSource.addSource(newSinglePlaybackItemMediaSource).

The prepareSource method of the single playlist items is called as soon as possible. What you're looking for is the createPeriod(..) method of MediaSource which is only called when the actual buffering starts.

ExtractorMediaSource is final, but you can still extend it to your own needs by writing a wrapper MediaSource which just forwards all 5 methods to the actual ExtractorMediaSource. This is, admittedly, more complicated when just overriding. When doing this, please make sure to call the inner prepareSource with isTopLevelSource=false and your own listener override as such:

@Override
public void prepareSource(ExoPlayer player, boolean isTopLevelSource, final Listener listener) {
  extractorSource.prepareSource(player, false, new Listener() {
    @Override
    public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
      listener.onSourceInfoRefreshed(timeline, manifest);
    }
  });
}

@Tolriq
Copy link
Contributor Author

Tolriq commented Oct 27, 2017

@tonihei Thanks for the insight.

Unfortunately the uri field of ExtractorMediaSource is private so I can't update it with a new value that can change if transcoding is actually needed.
And I also can't call directly ExtractorMediaPeriod as it's package private.

I can of course use the same package name for the new extractor to bypass that as I have to do to fix some Support Libraries issues.

But I usually prefer to find a proper way before.

Anything I missed before faking package name ?

@tonihei
Copy link
Collaborator

tonihei commented Oct 27, 2017

We thought about your problem more closely and actually it's not a good idea to do the transcoding in createPeriod(). Sorry for the confusion :) The reason is that this would block the current playback.

There are two other possible solutions:

  1. Manage the playlist yourself without immediately adding everything to the DynamicConcatenatingMediaSource. You can listen to Player.EventListener.onPositionDiscontinuity() to notice when the player starts playing the next item and only ever add the next two items to the list.
  2. Implement your own custom DataSource and pass it to the ExtractorMediaSource. In your data source, you can override .open(DataSpec) to start your transcoding, wait for the result and to open the actual data source with your new Uri. This method is allowed to block as long as is takes to open your actual connection.

@Tolriq
Copy link
Contributor Author

Tolriq commented Oct 27, 2017

Thanks.

I'll pass on the managing playlist myself as there's way too many cases to handle with user that can move items in it :)
Like moving the next item to before actual play would need to stop transcoding without playing. (Was my first idea)

DataSource sounds good as the open / close allows perfect management. I'll see if I can manage that easily by just proxying OkHTTPDatasource to not have to invent wheel again.

@Tolriq
Copy link
Contributor Author

Tolriq commented Oct 29, 2017

@tonihei So I started to look how I could integrate into all that, and it seems there's nowhere the place to add a custom object that moves along everything. The only things that seems to fit would be the customCacheKey that is then available as key in the DataSpec.

The doc is not very clear about the usage of this field and the implications of this value.

Is it used by default if not activating specifically cache?

How is this value used after (IE what are the collision risks if I use this field with an unique identifier but with extra data appended)

@tonihei
Copy link
Collaborator

tonihei commented Oct 30, 2017

Could you clarify where your custom object should "move along" exactly?
From my understanding of your problem you have an URI (which is passed in the DataSpec object) and your custom data source can read this URI, start the transcoding on your server to retrieve the actual media URI, and use this media URI to open the actual data source. This means that your initial URI acts as an custom object passed to your data source.

@Tolriq
Copy link
Contributor Author

Tolriq commented Oct 30, 2017

Well actually I need some more data than just the URI, to know if, when and how to start the transcoding.

Currently from the servers I support there's no use of Uri fragment so could use that, but if a future server needs those it will be complex to update.

It seems most of the default things are build around Uri and building something based on a custom object would need a lot a custom components just to reproduce existing things or I may have missed something obvious but I don't think :(

If I can pass an ID or something different from Uri (As same Uri might need different things depending on many factors), then I can pass an interface to DataSourceFactory and DataSource to query those additional details and do anything I need in the Open / Close.

Only issue is that Uri is not enough by itself so the cache key sounded like an easy alternative.

@tonihei
Copy link
Collaborator

tonihei commented Oct 30, 2017

I suppose you could append an ID to the URI itself?
If this ID or the general set-up needs more work, you should probably create a custom MediaSource (as I originally proposed to your question) which creates the ID and sets up all auxiliary information you need. It then calls through to the ExtractorMediaSource (with the extended URI including the ID), which in turn uses the custom DataSource to read the URI with the ID to perform the transcoding. Does that sound reasonable?

@Tolriq
Copy link
Contributor Author

Tolriq commented Oct 30, 2017

Well yes this was my first idea using uri fragments (#xxxx) to pass necessary info. Will just need to take care if source uri already have some in the future.

I just wanted to be sure that there was no better / proper way before building on this. I prefer to have good foundation than rushing onto my first ideas :)

Anyway thanks a lot for the time and all the details, I have the custom factory / datasource proxying to okHttp working so the rest is just details I hope.

@tonihei
Copy link
Collaborator

tonihei commented Oct 30, 2017

Sounds good. I'll close the issue then.

@tonihei tonihei closed this as completed Oct 30, 2017
@google google locked and limited conversation to collaborators Mar 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants