Skip to content

Instantly share code, notes, and snippets.

@mgoral
Created December 26, 2016 21:23
Show Gist options
  • Save mgoral/091c3899d1654a79be517ec0c2dbc53e to your computer and use it in GitHub Desktop.
Save mgoral/091c3899d1654a79be517ec0c2dbc53e to your computer and use it in GitHub Desktop.
#-*- coding: utf-8 -*-
"""
Copyright (C) 2011, 2012, 2013 Michal Goral.
This file is part of Subconvert
Subconvert is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subconvert is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subconvert. If not, see <http://www.gnu.org/licenses/>.
"""
import re
from subconvert.utils.SubException import SubAssert
from subconvert.utils.Locale import _
class FrameTimeType:
"""Used to determine if frame or time should be changed on FPS change."""
Undefined = 0
Frame = 1
Time = 2
class FrameTime():
"""Class defining a FrameTime object which consists of frame and time metrics (and fps as well)."""
def __init__(self, fps, ms=None, frames=None, time=None):
"""Constructs FrameTime object with a given FPS value. Constructor accepts only one value
from the following ones: time (properly formatted string), number of frames (int) or number
of total milliseconds.
Examples:
FrameTime(time="1:01:01.100", fps=25)
FrameTime(frames=100, fps=25)
FrameTime(ms=3600001, fps=25)
"""
if fps <= 0:
raise ValueError("Incorrect FPS value: %s." % fps)
self._fps = float(fps)
if frames is None and time is None and ms is None:
self._origin = FrameTimeType.Undefined
self._frame = 0
self._ms = 0
else:
exclusiveArgs = [frames, time, ms]
if exclusiveArgs.count(None) != 2:
raise AttributeError("FrameTime can obly be initialized by one type.")
if frames is not None:
self._origin = FrameTimeType.Frame
self._set_frame(int(frames))
elif time is not None:
self._origin = FrameTimeType.Time
self._set_time(str(time))
elif ms is not None:
self._origin = FrameTimeType.Time
self._set_ms(int(ms))
def clone(self):
other = FrameTime(fps = self.fps)
other._origin = self._origin
other._frame = self._frame
other._ms = self._ms
return other
@property
def fps(self):
return self._fps
@fps.setter
def fps(self, newFps):
SubAssert(newFps > 0, "Incorrect FPS value: %s." % newFps, ValueError)
self._fps = float(newFps)
self._set_ms(self._ms)
@property
def frame(self):
"""Get Frame (and FPS) value)"""
return int(round(self._frame))
@property
def ms(self):
return self._ms
@property
def time(self):
hours = int(self._ms / 3600000)
counted = hours * 3600000
minutes = int((self._ms - counted) / 60000)
counted += minutes * 60000
seconds = int((self._ms - counted) / 1000)
counted += seconds * 1000
ms = int(self._ms - counted)
return {
'hours': hours,
'minutes': minutes,
'seconds': seconds,
'milliseconds': ms,
}
def toStr(self, strType="time"):
"""Convert FrameTime to string representation"""
if strType == "time":
return "%(hours)d:%(minutes)02d:%(seconds)02d.%(milliseconds)03d" \
% self.time
elif strType == "frame":
return "%d" % self._frame
else:
raise AttributeError("Incorrect string type: '%s'" % strType)
def _set_time(self, value):
time = re.match(r"(?P<h>\d+):(?P<m>[0-5][0-9]):(?P<s>[0-5][0-9])(?:$|\.(?P<ms>\d{1,3}))", value)
if time is None:
raise ValueError("Incorrect time format.")
if time.group('ms') is not None:
# ljust explenation:
# 10.1 != 10.001
# 10.1 == 10.100
ms = int(time.group('ms').ljust(3, '0'))
else:
ms = 0
seconds = int(time.group('s'))
minutes = int(time.group('m'))
hours = int(time.group('h'))
self._set_ms(int(1000 * (3600*hours + 60*minutes + seconds) + ms))
def _set_ms(self, ms):
SubAssert(ms >= 0, 'Incorrect milliseconds value', ValueError)
self._ms = ms
self._frame = int(round(ms * self.fps / 1000))
def _set_frame(self, frame):
SubAssert(frame >= 0, 'Incorrect frame value', ValueError)
self._frame = frame
self._ms = int(round(frame / self._fps * 1000))
def __eq__(self, other):
SubAssert(self._fps == other._fps, _("FPS values are not equal"))
return self._ms == other._ms
def __ne__(self, other):
SubAssert(self._fps == other._fps, _("FPS values are not equal"))
return self._ms != other._ms
def __lt__(self, other):
SubAssert(self._fps == other._fps, _("FPS values are not equal"))
return self._ms < other._ms
def __gt__(self, other):
SubAssert(self._fps == other._fps, _("FPS values are not equal"))
return self._ms > other._ms
def __add__(self, other):
"""Defines FrameTime + FrameTime"""
SubAssert(self._fps == other._fps, _("FPS values are not equal"))
result = self._ms + other._ms
return FrameTime(fps = self._fps, ms = result)
def __sub__(self, other):
"""Defines FrameTime - FrameTime"""
SubAssert(self._fps == other._fps, _("FPS values are not equal"))
SubAssert(self._ms >= other._ms,
_("Cannot substract higher time from lower"))
result = self._ms - other._ms
return FrameTime(fps = self._fps, ms = result)
def __mul__(self, val):
"""Defines FrameTime * number"""
result = self._ms * val
return FrameTime(fps = self._fps, ms = result)
def __div__(self, val):
"""Defines FrameTime / number"""
result = self._ms / val
return FrameTime(fps = self._fps, ms = result)
def __str__(self):
"""Defines str(FrameTime)"""
fmt = self.time
fmt['frame'] = self.frame
return "t: %(hours)s:%(minutes)s:%(seconds)s.%(milliseconds)s; " \
"f: %(frame)s" % fmt
def __repr__(self):
return "FrameTime(id=%s, s=%s, f=%s, fps=%s)" % \
(id(self), self.ms, self.frame, self.fps)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment