Why is the VLC library binding in Python not acurately measuring marked end times?

33 Views Asked by At

I am trying to write a tiny video editor in python. All works just fine, however, the function that establishes an end mark sometimes returns a time which is two or three tenths of a second earlier than the desired point. Note that earlier there. I would understand a delay due to human reaction time. It is a negative latency though. What makes it weirder is that the problem occurs only with the end marks and not with the start marks. Here is the code:

from moviepy.video.io.VideoFileClip import VideoFileClip
import vlc
import wx
import sys

def ms_to_hms(ms):
    """Convert milliseconds to h:mm:ss.xxx"""
    seconds, ms = divmod(ms, 1000)
    minutes, seconds = divmod(seconds, 60)
    hours, minutes = divmod(minutes, 60)
    return f"{hours}:{minutes:02d}:{seconds:02d}.{ms:03d}"

class VideoFrame(wx.Frame):
    def __init__(self, parent, title, video_path):
        super().__init__(parent, title=title, size=(800, 600))
        self.video_path = video_path
        self.init_ui()
        self.Show(True)

    def init_ui(self):
        self.panel = wx.Panel(self)
        self.Instance = vlc.Instance()
        self.player = self.Instance.media_list_player_new()
        Media = self.Instance.media_new(self.video_path)
        media_list = self.Instance.media_list_new([Media])
        self.player.set_media_list(media_list)
        self.player.get_media_player().set_hwnd(self.panel.GetHandle())
        self.start_mark = None
        self.end_mark = None
        self.panel.Bind(wx.EVT_CHAR_HOOK, self.on_key_press)

    def on_key_press(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_SPACE:
            self.toggle_play_pause()
        elif keycode == wx.WXK_RETURN:
            self.cut_clip()
        elif keycode == ord('S'):
            self.set_start_mark()
        elif keycode == ord('E'):
            self.set_end_mark()

    def toggle_play_pause(self):
        if self.player.is_playing():
            self.player.pause()
        else:
            self.player.play()

    def set_start_mark(self):
        self.start_mark = self.player.get_media_player().get_time()
        print(f"Start mark set at: {ms_to_hms(self.start_mark)}")

    def set_end_mark(self):
        self.end_mark = self.player.get_media_player().get_time()
        print(f"End mark set at: {ms_to_hms(self.end_mark)}")

    def cut_clip(self):
        if self.start_mark is not None and self.end_mark is not None:
            clip = VideoFileClip(self.video_path).subclip(self.start_mark/1000, self.end_mark/1000)
            output_path = "cut_clip.mp4"
            clip.write_videofile(output_path)
            print(f"Clip cut: Start - {ms_to_hms(self.start_mark)}, End - {ms_to_hms(self.end_mark)}")

def main(video_path):
    app = wx.App(False)
    frame = VideoFrame(None, "Video Player", video_path)
    app.MainLoop()

if __name__ == "__main__":
    video_path = sys.argv[1]
    main(video_path)
0

There are 0 best solutions below