All-VLC version of MovieStim2

Hey there folks. We were running into some weird stuttering and timing issues with MovieStim2 (it desynced on most WMV files I tried, and there’s weird startup input lag) so I decided to roll a pure libvlc version that just uses VLC for both audio and video:

The hard part of the C buffer interop is done, but I still need to get it placing the video on the screen correctly.

I’m not super familiar with the PsychoPy ecosystem. Do you think when this is ready to pull request, I should submit it as MovieStim4 (bleh), or a new thing called VlcMovieStim, replace the OpenCV MovieStim2 entirely, or something else?

Interesting work. I was going down the other route of phasing this one out in favour of moviepy (based on ffmpeg), but you think a full vlc backend will have better performance than using ffmpeg? If we were going this route it would be nice to package up the dlls into standalone too (or into vlc wheel) so the user doesn’t need to install a bit-compatible vlc version (although now we have 64bit Standalone on Windows that’s less confusing to users I guess).

I don’t really mind on the naming. Maybe we should have done something more like the the sound libs and have a single class the user calls, simply called Movie, but this can call different backends as a preference (or a parameter?). I guess calling VlcMovieStim is best of a bad lot for an easy route?

Yes, a pull request is fine :slight_smile:

I think VLC may be a better path than moviepy, but I’m not super familiar with moviepy. It looks like moviepy is more targeted to editing than playback?

If you’re already going down that path, maybe it’s worth a comparison of performance and how difficult it is to get the prerequisites packaged.

I have hit some oddities with vlc and python-vlc being possibly in conflict, at least on Windows.

Will report back with an initial pull request soonish.

MoviePy has high precision in theory (e.g., the ability to present individual frames on demand) but it’s very inefficient and often ends up a bit imprecise in terms of playback duration due to lag or desync. I would be interested in trying out this alternative at some point, if it’s more reliable about performance it could be great for my little add-on (https://github.com/jfkominsky/PyHab).

I also wanted to mention that I can already see something that will break the way I’m using movieStim3 now: seek automatically calls play, even if the movie was paused before. If you want to seek to a different point in the movie but leave it paused (which I do, for various reasons), that’s not going to work, but it is easily fixed. Just check whether self.status==‘PLAYING’ again at the end of the seek function.

Also curious if this handles sound differently than the current setup. As far as I can tell it doesn’t do sound at all?

Sound works automatically, handled by VLC, so far less sync issues. (You can attach callbacks to audio, but it doesn’t seem necessary.)

As for the seek bit, it seems to me like seek should not do anything about pausing or playing - if paused, you should seek and stay paused, if playing, you should seek and stay playing? That’s the behavior I’d expect. Easy to change…

My branch now has a demo that works… only the sizing is not quite right yet.

I also have a strange bug where if any other stimuli are initialized after the movie, its callbacks break and things segfault. Very odd; not sure what is causing this, would appreciate a glance at it if someone with more expertise has time:

Example of change that goes from working to broken:

This looks cool. If you can accurately report the flip time of each video frame when using vlc , then this addresses the reason I used an opencv + vlc combo in movie2 originally.

Nice.

Welllllll that’s kind of an open question still. What do we need, exactly?

I have exact frame count working. I took out all the clocks needed to try to sync between the opencv + vlc audio in MovieStim2, but I can time things using the vlc.EventType.MediaPlayerTimeChanged callback that you were using OR just use system clock time when frames are locked.

When you say flip time, do you mean according to VLC or according to when the .draw() cycle calls?

Fixed that issue, it’s relatively solid now. Going to do some more testing and send a PR in the next few days.

When you say flip time, do you mean according to VLC or according to when the .draw() cycle calls?

I meant the time each video frame is actually displayed, in pscyhopy time, i.e. win.flip() time for each frame after it is drawn.