Get Current Frame Number of Video Playing with Python-Vlc

I'm trying to make a python program that plays a video in sync with a light show done via Arduino. To achieve this I need to know what frame of the video is currently playing to send out data to the Arduino.

I modified the cocoavlc.py example of python-vlc to play a video, pause, resume and rewind it, go forward and backwards by 10 seconds.

To keep track of the frame number tried the method get_time of python-vlc but it only updates a few times a second. I had the idea to interpolate its data with a timer but it's not perfect.

Here's the code (without the timer):

import vlc
from pycocoa import __name__ as _pycocoa_

from pycocoa import App, Item, ItemSeparator, MediaWindow, Menu, OpenPanel

from os.path import isfile
from threading import Thread
from time import sleep
import time

_Movies  = '.m4v', '.mov', '.mp4'
_Select  = 'select a video file from the panel'

class AppVLC(App):
    player    = None
    sized     = None
    Toggle    = None
    video     = None
    window    = None

    def __init__(self, video = None, title = 'AppVLC'):
        super(AppVLC, self).__init__(title = title)
        self.media    = None
        self.Toggle   = Item('Play', self.menuToggle_, key='p')
        self.video    = video
        self.player = vlc.MediaPlayer()

    def appLaunched_(self, app):
        super(AppVLC, self).appLaunched_(app)
        self.window = MediaWindow(title=self.video or self.title)

        if self.player and self.video and isfile(self.video):
            # the VLC player on macOS needs an ObjC NSView
            self.media = self.player.set_mrl(self.video)
            self.player.set_nsobject(self.window.NSview)

            menu = Menu('VLC')
            menu.append(
                Item('Open...', key='o'),
                ItemSeparator(),
                self.Toggle,
                Item('Rewind', key='r'),
                Item('Forward', key='f'),
                ItemSeparator(),
                Item('Back', key='b'))
            ItemSeparator(),
            self.append(menu)

        self.menuPlay_(None)
        self.window.front()

    def menuOpen_(self, item):
        self.menuPause_(item)
        self.badge.label = 'O'
        v = OpenPanel(_Select).pick(_Movies)
        if v:
            self.window.title = self.video = v
            self.player.set_mrl(v)
            self.sized = None

    def menuPause_(self, item, pause = False):
        if pause or self.player.is_playing():
            self.player.pause()
            self.badge.label = 'S'
            self.Toggle.title = 'Play'

    def menuPlay_(self, item_or_None):
        self.player.play()
        self._resizer()
        self.badge.label = 'P'
        self.Toggle.title = 'Pause'

    def menuRewind_(self, item):
        self.player.set_position(0.0)
        self.badge.label = 'R'
        self.sized = None

    def menuForward_(self, item):
        time = self.player.get_time()
        lenght = self.player.get_length()
        time = time + 10000
        if time < lenght:
            self.player.set_time(time)
        self.sized = None

    def menuBack_(self, item):
        time = self.player.get_time()
        lenght = self.player.get_length()
        time = time - 10000
        if time > 0:
            self.player.set_time(time)
        self.sized = None

    def menuToggle_(self, item):
        if self.player.is_playing():
            self.menuPause_(item, pause=True)
        else:
            self.menuPlay_(item)

    def windowClose_(self, window):
        if window is self.window:
            self.terminate()
        super(AppVLC, self).windowClose_(window)

    def windowResize_(self, window):
        if window is self.window:
            self._resizer()
        super(AppVLC, self).windowResize_(window)

    def _resizer(self):
        if self.sized:
            self.window.ratio = self.sized
        else:
            Thread(target=self._sizer).start()

    def _sizer(self, secs=0.1):
        while True:
            w, h = self.player.video_get_size(0)
            if h > 0 and w > 0:
                self.window.ratio = self.sized = w, h
                break
            elif secs > 0.001:
                sleep(secs)
            else:
                break

    def get_frame(self):
        #?


def trackframes():
    frame = 0
    while True:
        if frame != app.get_frame():
            frame = app.get_frame()
            send(frame) #send data to the Arduino

if __name__ == '__main__':
    _video = OpenPanel('Select a video file').pick(_Movies)

    app = AppVLC(video = _video)
    Thread(target = trackframes).start()
    app.run(timeout = None)
1

1 Answer

The only sensible way I have discovered to approximate the frame number in python vlc, is to take the frames per second player.get_fps() or 25, if not available and calculate the frame number based on the current playing time.

    sec = player.get_time() / 1000
    frame_no = int(round(sec * fps))
5

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Elena Rostova

Elena Rostova

Lead Health, Wellness & Medical Journalist

Elena Rostova holds a Master's degree in Public Health Journalism. She covers groundbreaking medical research, holistic wellness trends, mental health awareness, and nutritional science.

Share this article
Twitter Facebook Pinterest