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

Implementing a Source Handlers interface for supporting adaptive formats #1560

Closed
wants to merge 3 commits into from

Conversation

heff
Copy link
Member

@heff heff commented Oct 3, 2014

The source handler pattern came from the need to support adaptive formats using the Media Source Extensions (or faux MSE with Flash) while keeping the code optional and external to core since it's very heavy. I'm hoping to get some feedback on the current implementation, especially from anyone working on the HLS plugin (e.g. @dmlap, @gkatsev, @seniorflexdeveloper)

TO-DO

HLS (to prove this will work)

The source handler interface

// Define a source handler
var mySourceHandler = {
  // does the handler support source object type, return probably, maybe, or ''
  canHandleSource: function(sourceObject){},

  // receive the source and tech. Do whatever is needed to handle the source format.
  // through the tech you have direct access to the video element (or flash object), events, and the tech API
  handleSource: function(source, tech){}
};

// Register the source handler with the specific tech (source handlers are tech specific)
vjs.Html5.registerSourceHandler(mySourceHandler);
// or
vjs.Flash.registerSourceHandler(mySourceHandler);

After registering a source handler it will be included when the tech is asked if it can support a source (Html5.canPlaySource) and handed source types that it supports (Html5.prototype.setSource).

I've currently only implemented it on the HTML5 side, but Flash should look identical. (done)

Native format support is also set up as a source handler here, which allows it to be prioritized in case we want our own HLS support to come before native, for example.

HLS-HTML Source Handler Pseudo Code

videojs.Html5.registerSourceHandler({
  canHandleSource: function(source){
    if (MSEisSupported() && sourceIsM3u8(source)) {
      return 'maybe';
    } else {
      return '';
    }
  },

  handleSource: function(source, tech){
    return new Html5HLS(source, tech);
  }
});

function Html5HLS(source, tech){
  var mediaSource = createMediaSource(source);

  tech.setSrc(mediaSource.blobURL);

  tech.on('seeking', function(){
    var seekTarget = tech.currentTime();

    updateMediaSource(seekTarget);
  });
}

Html5HLS.prototype.dispose = function(){};

Overview

Native Source Handler

HLS Source Handler

Ideal Code Sharing


/**
* Check if the volume can be changed in this browser/device.
* Volume cannot be changed from 1 on iOS.
Copy link
Member

Choose a reason for hiding this comment

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

a lot of mobile devices don't support changing volume programmatically.

Copy link
Member Author

Choose a reason for hiding this comment

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

Cool, I'll update that

@dmlap
Copy link
Member

dmlap commented Oct 3, 2014

Does this mean we will have to standardize the tech API? Export/Extern it for gcc?

One thing that I worry about this design is tech-level state. Handing off the underlying tech element allows consumers to perform operations that can invalidate the assumptions of the tech. For instance, lastSeekTarget_ in the Flash tech. Am I misunderstanding how source handlers interact with the tech? Do you have any ideas how we can ensure things don't get out of sync?

@heff
Copy link
Member Author

heff commented Oct 4, 2014

Does this mean we will have to standardize the tech API? Export/Extern it for gcc?

We already do that for the most part so the player can interact with external techs. I imagine we can improve that, but is there specific properties or whatever you're thinking of?

One thing that I worry about this design is tech-level state.

I at least don't mean for this to significantly change how the HLS logic interacts with the tech and tech element today, but I could be missing some details.

With HTML-MSE my understanding is that our code would respond to "need data" events, fetch the data, and feed it into the source buffer. Based on that (very unconfirmed) example I don't see it screwing with tech state, however the HLS (Flash) plugin does currently insert itself earlier in processes by modifying currentTime and duration. I don't have a story around how that would continue to work here yet. Do you have a better idea on the HTML-MSE needs?

Assuming MSE needs the same, we could consider other options for allowing a source handler to insert itself into currentTime and duration. Possibly firing events from those methods that allow preventDefault on them or modifying return values.

@heff
Copy link
Member Author

heff commented Oct 4, 2014

Updated it to share the selection logic more, per @gkatsev's comment.

@dmlap I realized there was a place where only the element was passed to the source handler, not the tech. That was wrong in case that was confusing things. The source handler would be passed the source and the tech, not the el directly. handleSource: function(source, tech){},

@heff
Copy link
Member Author

heff commented Oct 6, 2014

In the latest update I:

  • Moved most of the source handler code into a mixin that can be applied to any tech
  • Updated the Flash tech to use the source handler functions

In the process I was able to create an RTMP source handler, separating all the RTMP code from the main Flash code. So that's at least one nice thing that's come of this.

The next step is to approach the HLS plugin with these changes in mind and see what additional issue I run into. If there's any other feedback so far let me know.

@dmlap let me know if you have any follow up thoughts on my previous comments.

@heff
Copy link
Member Author

heff commented Oct 9, 2014

Added a feature request on videojs-contrib-media-sources for MSE's duration method, videojs/videojs-contrib-media-sources#18. It would prevent source handlers having to be involved in the duration getting process.

@heff
Copy link
Member Author

heff commented Oct 10, 2014

I added some pretty pictures to the issue description that probably don't do any better of a job explaining this, but hopefully. The pseudo code at the end of the description might help the most to illustrate the process.

@heff
Copy link
Member Author

heff commented Oct 16, 2014

I added a pic on the ideal code sharing scenario to the description.

One question I'm trying to answer now is if we'll need Source Handlers to create instances. It'd be nice to keep them singletons, but then that leaves the question of where state should be stored. Possibly the tech itself, but that doesn't feel very clean.

@heff
Copy link
Member Author

heff commented Oct 28, 2014

After chatting with @dmlap I changed the workflow to have the source handler return an instance, and the dispose method is (optionally) on that instance. The native source handlers don't need to create an instance or support a dispose method because they just pass the url to the video element.

@heff
Copy link
Member Author

heff commented Dec 2, 2014

Rebased and updated with tests. I think this is ready to be pulled in.

Refactoring of HTML5 source handler pattern

Updated source handlers to share selection logic

Created a mixin for source handler functions and update Flash to have source handlers
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.

3 participants