SplitmediaLabsLimited / xjs

XSplit JS Framework. Make plugins for XSplit Broadcaster, quickly and easily.
Other
39 stars 11 forks source link

Bug? Looping video is Playlist but not recognized as such #296

Closed BrendaH closed 4 years ago

BrendaH commented 4 years ago

In my project, where I try to replace parts of file paths with the help of an extension I am writing, I have a single video that is set to loop. In the xml that is the .BPres file I see a node which, besides the normal item=<path> attribute, also has a filled FilePlaylist=<path> attribute. In this case there is only one path in there. So it looks like I got a playlist for a looping video with one item to play. However, if I try to get the Source of this node (via Scene.getSources()) I do not get a VideoPlaylistSource but a MediaSource (at least... if the extension of the file is lower case, see #295).

I need to update the paths to my files, according to some variables that the user has chosen. For this looping video that means that I need to update the item= attribute AND the FilePlaylist= attribute, but with a MediaSource I have no clear way to access the latter.

Trying to find what defines a playlist I found this line: https://github.com/xjsframework/xjs/blob/a1197da3015af103462a8d7ab4dff60c6b07e329/src/util/sourcetyperesolve.ts#L23 Which assumes that a video playlist always has a name attribute of 'Video Playlist'.

However, since my single looping video was not added as a regular Playlist widget, for me the name attribute is not 'Video Playlist' and I can not easily access the FilePlaylist attribute.

Some solutions I can think of: Might it be an idea to make MediaSource a bit smarter and have it's setValue also check if there is a non-empty FilePlaylist attribute that needs the same update? Or make the FilePlaylist attribute accessible on MediaSources so that users can fiddle with it themselves. Or to check the FilePlaylist attribute to determine that something is apparently a VideoPlaylistSource (even if it wasn't added as such, but is just a looping video)?

A workaround that I might implement in the meantime is getting the _xmlparams of the Source that I do have and creating a new VideoPlaylistSource with that to have access to what I need. But this is a bit ugly, to say the least.

BrendaH commented 4 years ago

I tried converting to VideoPlaylistSource using _xmlparams, which seems to work. However, it then turns out that getVideoPlaylistSources() and setVideoPlaylistSources() do not seem to play well with this usecase of replacing pathnames. When doing a get, replacing the pathname, and setting that, the video seems to stop looping (though later this stopped happening, so maybe there is some subtle interaction going on...).

This is probably related to the *0*1*... etc postfix applied to the filename(s) in the playlist. The getter removes this postfix: https://github.com/xjsframework/xjs/blob/a1197da3015af103462a8d7ab4dff60c6b07e329/src/core/source/ivideoplaylist.ts#L128 And the setter appends a new postfix: https://github.com/xjsframework/xjs/blob/a1197da3015af103462a8d7ab4dff60c6b07e329/src/core/source/ivideoplaylist.ts#L148-L157

However, the format seems subtly different. A looping video added through xpslit has e.g.:

FilePlaylist="C:\looping.mov*0*1*642990000,0*100*0*0*0**0"

Note two adjacent **, which has a 0 in between in the postfix generated by the setter. There is also a ,0 in there, but I suspect that is just the decimal part of the duration (the big number). I tried removing these bits of code that remove and re-add the postfixes from the getter and setter function (i.e. modifying xjs.js), so the existing postfix is just kept verbatim. That does seem to keep looping working, but when opening the item settings in the xsplit GUI, it is still set to "Once". Only when it finishes, the next loop starts and then you reopen the settings, it shows "Forever" again. I suspect that this is because loop settings is somehow encoded into this postfix in the playlist items (and maybe loaded from the playlist when the item starts), but the setter sets srcitem before changing filePlaylist, so when srcitem is changed, it is set to an item that is (at that moment) not present in the playlist, so it probably assumes non-looping. This is consistent with the fact that it stays at "Forever" when I do not change the filename (but do call the setter with an unchanged filename).

I'm not entirely sure what is going on here. In the XML, there does not seem to be a clear "looping" variable, so I suspect that the once/forever is somehow encoded into these filename postfixes. Is there any documentation on what these values mean, and how the videoplayer uses them to decide what to do? Apparently the video duration is in there, so maybe that's the video end time (and the 0 before it is the start time). Maybe one of these 0's is the rewind position? Any other insights?

BrendaH commented 4 years ago

Turns out that always inserting the ,0 after the duration keeps the looping working for a single video that loops (so not an official playlist) but whose path (in item= and FilePlaylist= attributes) are changed. This hack in xjs.js probably breaks the thing for normal playlists, but for my use case it'll have to do for now.

SML-MeSo commented 4 years ago

So it looks like I got a playlist for a looping video with one item to play.

This change was introduced when we supported looping for media sources in XBC. This is done internally, to turn all looping sources into playlists. Theoretically, all playlists are file/media sources and all media sources can be a playlist. As I've mentioned in #295, most behaviors in the framework are in-sync with the source properties dialog, but this time, the change in the framework was not done alongside it, for fixing. Of the suggestions you have given, I think the first is the one we're inclined to. Oh, and as a reference, the ,0 denotes the looping (0 for forever, any number for the custom number of loops, without it means once)