ozmartian / vidcutter

A modern yet simple multi-platform video cutter and joiner.
GNU General Public License v3.0
1.77k stars 137 forks source link

Error during save media with accurate frame cutting enabled #358

Closed zykure closed 1 year ago

zykure commented 2 years ago

This was already reported in #290 which was closed. The issue still exists in the latest version. From what I can gather it is a string-formatting problem that should be easy to fix, see below for an idea.

I had this issue with recent version 6.0.5.1 installed on Manjaro Linux (Python 3.10.4, libmpv 109.1). The error is reproducible when I open the same project file again, as long as SmartCut mode is enabled. Luckily this is fixable with a few code edits.

Log output:

2022-06-08 12:14 - root - CRITICAL -   File "/usr/lib/python3.10/site-packages/vidcutter/videocutter.py", line 1361, in saveMedia
    self.smartcutter(file, source_file, source_ext)
  File "/usr/lib/python3.10/site-packages/vidcutter/videocutter.py", line 1406, in smartcutter
    self.videoService.smartcut(index=index,
  File "/usr/lib/python3.10/site-packages/vidcutter/libs/videoservice.py", line 331, in smartcut
    bisections = self.getGOPbisections(source, start, end)
  File "/usr/lib/python3.10/site-packages/vidcutter/libs/videoservice.py", line 590, in getGOPbisections
    end_pos = bisect_left(keyframes, end)

2022-06-08 12:14 - root - CRITICAL - <class 'TypeError'>: '<' not supported between instances of 'str' and 'float'

I did some debugging and traced the issue down to a wrongly formatted keyframe timestamp. All keyframes are given as float values, except the last one which is a string in H:MM:SS.nnn format. Hence, the comparison operator fails as indicated in the error message. In my case, the keyframes object in the getGOPbisections() method contains:

[0.0, 12.5, 20.6 ... 5575.35, 5587.85, 5600.35, 5612.85, '1:33:36.300']

I was able to add a workaround that simply converts all timestamps to floats, but the actual issue is probably somewhere in the getKeyframes() method which produces the non-float value. Updated code in videocutter.py:

    def getGOPbisections(self, source: str, start: float, end: float) -> dict:
        keyframes = self.getKeyframes(source)
        # hacky solution to convert HH:MM:SS into seconds:
        keyframes = [ (sum([ float(v)*60**i for i,v in enumerate(reversed(f.split(':'))) ]) if type(f) == str else f) for f in keyframes ]
        #print(start, end, keyframes)
cyberpunkrocker-zero commented 1 year ago

Where in the videocutter.py file should the abovementioned code added?

zykure commented 1 year ago

Apparently the code changed and the getGOPbisections is now in the file libs/videoservice.py on line 591. I have VidCutter version 6.0.5.1.

But in that version, the fix I suggested here is already added (you can tell by the keyframes = [ ... ] line.) I guess we can close this issue then.