Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FrameTimeCode should be identic to itself when applying the resulting values to create a new FrameTimeCode #268

Closed
Wirg opened this issue Apr 20, 2022 · 4 comments
Labels
Milestone

Comments

@Wirg
Copy link

Wirg commented Apr 20, 2022

Hi !

Thank you for PySceneDetect.

I ran into issues where after some serialization the resulting time frame was not the expected one.
For example:

frame_time_code = FrameTimecode(61, fps=14)
seconds = frame_time_code.get_seconds()
time_code = frame_time_code.get_timecode()

...

FrameTimecode(seconds, fps=14).get_frames() == 60 # not 61
FrameTimecode(time_code, fps=14).get_frames() == 60 # not 61

I found the corresponding code with flooring (with int instead of round) :

def _seconds_to_frames(self, seconds):
# type: (float) -> int
""" Converts the passed value seconds to the nearest number of frames using
the current FrameTimecode object's FPS (self.framerate).
Returns:
Integer number of frames the passed number of seconds represents using
the current FrameTimecode's framerate property.
"""
return int(seconds * self.framerate)

return int(secs * self.framerate)

I ran into the following code which seems to indicate this is on purpose. What is the reason?

assert FrameTimecode(timecode='00:00:01', fps=1).frame_num == 1
assert FrameTimecode(timecode='00:00:01.9999', fps=1).frame_num == 1
assert FrameTimecode(timecode='00:00:02.0000', fps=1).frame_num == 2

Have a nice day !

@Breakthrough
Copy link
Owner

Hey @Wirg;

Thanks for looking into this. It looks like some of the existing test cases are failing after your change (probably just a few off-by-one errors now), so will need to see why that is before merging #269 (thanks for the PR as well). I'm not sure if this should be taken for v0.5 or not, as this could possibly be a breaking change, but I'd be happy to consider it for v0.6.

I ended up doing a similar workaround in v0.6 for the PyAV backend, so I think your change is correct. Truthfully it's been quite a few years since I've touched FrameTimecode, so I can't really remember the intent behind these test cases you pointed out:

assert FrameTimecode(timecode='00:00:01', fps=1).frame_num == 1
assert FrameTimecode(timecode='00:00:01.9999', fps=1).frame_num == 1
assert FrameTimecode(timecode='00:00:02.0000', fps=1).frame_num == 2

I may mark this as a known issue for v0.5, but bring your change in for v0.6. Thanks for the report!

@Breakthrough Breakthrough added this to the v0.6 milestone Apr 20, 2022
Breakthrough added a commit that referenced this issue Apr 20, 2022
Reformat test cases using autoformatter.

Thanks @Wirg for finding this and suggesting a solution.
@Breakthrough
Copy link
Owner

Breakthrough commented Apr 20, 2022

I've accepted your suggested solution for v0.6 (c5ac42b) and it will be included in the next beta release, as well as v0.6. I'm reluctant to merge this fix into v0.5 as it may constitute a breaking change for some existing applications.

TODO before closing this issue:

@Wirg
Copy link
Author

Wirg commented Apr 21, 2022

Thanks for the fast answer!

I think it's ok for me, I agree with your reasoning. I may try the v0.6 branch then.

@Breakthrough
Copy link
Owner

This is now available in the latest release of v0.6 (v0.6-rc0), feel free to give it a try!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants