simple_ffmpeg_batch_io.FrameCounter
Create a FrameCounter to follow elapsed time in audio or video file in read/write mode. Static utility function allows to get/format elapsed time.
Authors
Dominique Vaufreydaz
1""" 2Create a ``FrameCounter`` to follow elapsed time in audio or video file in read/write mode. Static utility function allows to get/format elapsed time. 3 4Authors 5------- 6Dominique Vaufreydaz 7 8""" 9 10__authors__ = ("Dominique Vaufreydaz") 11 12from typing import Union 13 14# class to count frame, thus time, in audio/video files 15class FrameCounter: 16 """ 17 Create a ``FrameCounter`` to follow elapsed time in audio/video file in read or write mode. Static utility functions allow to format elapsed time. 18 """ 19 20 class FrameCounterException(Exception): 21 """ 22 Dedicated exception class for FrameCounter class. 23 """ 24 def __init__(self, message="Error while setting FrameCounter parameters."): 25 self.message = message 26 super().__init__(self.message) 27 28 _fps: float # (private) 29 """ Fps of current stream """ 30 31 _frame_count: int # (private) 32 """ Frame count in the current stream """ 33 34 def __init__(self, fps: Union[int, float]): 35 """ 36 Create a VideoIO object giving ffmpeg/ffrobe loglevel and defining debug mode 37 38 Parameters 39 ---------- 40 fps: int or float. 41 Frames per second of the associated stream. 42 """ 43 # check init fps value 44 self._fps = float(fps) 45 if self._fps <= 0.0: 46 raise FrameCounterException("fps must be > 0.0.") 47 48 # 2 modes 49 self._frame_count = 0 # at 00:00:00.000 50 51 # support += 52 def __iadd__(self, other: Union[int, float]): 53 """ 54 Support += operator for FrameCounter. 55 56 Parameters 57 ---------- 58 other: int or float. 59 If other is a float, add the number of frame to add 'other' seconds (thus other * self._fps samples). 60 If other is an int, add the value as a number of samples in the stream. 61 """ 62 if isinstance(other,float): 63 # float means adding time 64 self._frame_count += int(other * self._fps) # number of second * Nb of elements per seconds 65 else: 66 # for int, add number of element 67 self._frame_count += other 68 return self 69 70 @property 71 def frame_count(self): 72 """ 73 Property to get underlying self._frame_count. Idea is to control setter to valid setting values. 74 """ 75 return self._frame_count 76 77 @frame_count.setter 78 def frame_count(self, value: int): 79 """ 80 Setter for underlying self._frame_count controlling setting value. 81 """ 82 if value < 0: 83 raise FrameCounterException("frame_count must be >= 0") 84 self._frame_count = value 85 86 @property 87 def fps(self): 88 """ 89 Property to get underlying self._fps. 90 """ 91 return self._fps 92 93 @staticmethod 94 def format_time(nb_frames: int, fps: float, show_ms : bool = True, show_days : bool = False) -> str: 95 """ 96 Static function to format time given by a number of frames and an fps. show_ms value defines if we show milliseconds, 97 show_days to show days instead of cummulative hour count. 98 99 Parameters 100 ---------- 101 nb_frames: int. 102 Number of samples already present in the stream. 103 104 fps: float. 105 Fps of the associated stream. 106 107 show_ms: bool. 108 Flag to say if we want to show milliseconds in the output str. 109 110 show_days: bool. 111 Flag to say if we want to show says instead of cumulative hours in the output str. 112 113 Returns 114 ------- 115 str representing corresponding time. Either 26:15:00 (show_ms=False, show_days=False), 26:15:00.500 (show_ms=True, show_days=False) 116 or 1 day(s) 02:15:00.500 (show_ms=True, show_days=True) 117 """ 118 # exact time in seconds (float) 119 exact_seconds = nb_frames / fps 120 121 # integer part for days/hours/minutes/seconds 122 total_seconds = int(exact_seconds) 123 124 # milliseconds = decimal part * 1000 125 millis = int(round((exact_seconds - total_seconds) * 1000)) 126 127 # handle the case where rounding results in 1000 ms 128 if millis == 1000: 129 millis = 0 130 total_seconds += 1 131 132 if show_days: 133 # compute number of days, hours, minutes, seconds 134 days, mod = divmod(total_seconds, 24 * 3600) 135 hours, mod = divmod(mod, 3600) 136 minutes, seconds = divmod(mod, 60) 137 138 if days > 0: 139 days = f"{days} days(s) " 140 else: 141 days = "" 142 else: 143 days = "" # no day as show_days = False 144 hours, mod = divmod(total_seconds, 3600) 145 minutes, seconds = divmod(mod, 60) 146 147 if show_ms == True: 148 millis = f".{millis:03d}" 149 else: 150 millis = "" 151 152 return f"{days}{hours:02d}:{minutes:02d}:{seconds:02d}{millis}" 153 154 def get_elapsed_time_as_str(self) -> str: 155 """ 156 Get elapsed time as string representing a float value rounded to 3 decimals. 157 158 Returns 159 ------- 160 str representing corresponding time in float format rounded to 3 decimals. 161 """ 162 return f"{float(self._frame_count)/self._fps:.3f}" 163 164 def get_formated_elapsed_time_as_str(self, show_ms : bool = True, show_days : bool = False) -> str: 165 """ 166 Get elapsed time as string representing time with different mode (see ``FrameCounter.format_time`` for parameter explanation). 167 Returns 168 ------- 169 str representing corresponding time in float format rounded to 3 decimals. 170 """ 171 # frame count to time correction is done in format_time 172 return FrameCounter.format_time(self._frame_count, self._fps, show_ms, show_days) 173 174 def get_elapsed_time(self) -> float: 175 """ 176 Get elapsed time as float value rounded to 3 decimals. 177 178 Returns 179 ------- 180 str representing corresponding time in float format rounded to 3 decimals. 181 """ 182 return round(float(self._frame_count)/self._fps,3)
16class FrameCounter: 17 """ 18 Create a ``FrameCounter`` to follow elapsed time in audio/video file in read or write mode. Static utility functions allow to format elapsed time. 19 """ 20 21 class FrameCounterException(Exception): 22 """ 23 Dedicated exception class for FrameCounter class. 24 """ 25 def __init__(self, message="Error while setting FrameCounter parameters."): 26 self.message = message 27 super().__init__(self.message) 28 29 _fps: float # (private) 30 """ Fps of current stream """ 31 32 _frame_count: int # (private) 33 """ Frame count in the current stream """ 34 35 def __init__(self, fps: Union[int, float]): 36 """ 37 Create a VideoIO object giving ffmpeg/ffrobe loglevel and defining debug mode 38 39 Parameters 40 ---------- 41 fps: int or float. 42 Frames per second of the associated stream. 43 """ 44 # check init fps value 45 self._fps = float(fps) 46 if self._fps <= 0.0: 47 raise FrameCounterException("fps must be > 0.0.") 48 49 # 2 modes 50 self._frame_count = 0 # at 00:00:00.000 51 52 # support += 53 def __iadd__(self, other: Union[int, float]): 54 """ 55 Support += operator for FrameCounter. 56 57 Parameters 58 ---------- 59 other: int or float. 60 If other is a float, add the number of frame to add 'other' seconds (thus other * self._fps samples). 61 If other is an int, add the value as a number of samples in the stream. 62 """ 63 if isinstance(other,float): 64 # float means adding time 65 self._frame_count += int(other * self._fps) # number of second * Nb of elements per seconds 66 else: 67 # for int, add number of element 68 self._frame_count += other 69 return self 70 71 @property 72 def frame_count(self): 73 """ 74 Property to get underlying self._frame_count. Idea is to control setter to valid setting values. 75 """ 76 return self._frame_count 77 78 @frame_count.setter 79 def frame_count(self, value: int): 80 """ 81 Setter for underlying self._frame_count controlling setting value. 82 """ 83 if value < 0: 84 raise FrameCounterException("frame_count must be >= 0") 85 self._frame_count = value 86 87 @property 88 def fps(self): 89 """ 90 Property to get underlying self._fps. 91 """ 92 return self._fps 93 94 @staticmethod 95 def format_time(nb_frames: int, fps: float, show_ms : bool = True, show_days : bool = False) -> str: 96 """ 97 Static function to format time given by a number of frames and an fps. show_ms value defines if we show milliseconds, 98 show_days to show days instead of cummulative hour count. 99 100 Parameters 101 ---------- 102 nb_frames: int. 103 Number of samples already present in the stream. 104 105 fps: float. 106 Fps of the associated stream. 107 108 show_ms: bool. 109 Flag to say if we want to show milliseconds in the output str. 110 111 show_days: bool. 112 Flag to say if we want to show says instead of cumulative hours in the output str. 113 114 Returns 115 ------- 116 str representing corresponding time. Either 26:15:00 (show_ms=False, show_days=False), 26:15:00.500 (show_ms=True, show_days=False) 117 or 1 day(s) 02:15:00.500 (show_ms=True, show_days=True) 118 """ 119 # exact time in seconds (float) 120 exact_seconds = nb_frames / fps 121 122 # integer part for days/hours/minutes/seconds 123 total_seconds = int(exact_seconds) 124 125 # milliseconds = decimal part * 1000 126 millis = int(round((exact_seconds - total_seconds) * 1000)) 127 128 # handle the case where rounding results in 1000 ms 129 if millis == 1000: 130 millis = 0 131 total_seconds += 1 132 133 if show_days: 134 # compute number of days, hours, minutes, seconds 135 days, mod = divmod(total_seconds, 24 * 3600) 136 hours, mod = divmod(mod, 3600) 137 minutes, seconds = divmod(mod, 60) 138 139 if days > 0: 140 days = f"{days} days(s) " 141 else: 142 days = "" 143 else: 144 days = "" # no day as show_days = False 145 hours, mod = divmod(total_seconds, 3600) 146 minutes, seconds = divmod(mod, 60) 147 148 if show_ms == True: 149 millis = f".{millis:03d}" 150 else: 151 millis = "" 152 153 return f"{days}{hours:02d}:{minutes:02d}:{seconds:02d}{millis}" 154 155 def get_elapsed_time_as_str(self) -> str: 156 """ 157 Get elapsed time as string representing a float value rounded to 3 decimals. 158 159 Returns 160 ------- 161 str representing corresponding time in float format rounded to 3 decimals. 162 """ 163 return f"{float(self._frame_count)/self._fps:.3f}" 164 165 def get_formated_elapsed_time_as_str(self, show_ms : bool = True, show_days : bool = False) -> str: 166 """ 167 Get elapsed time as string representing time with different mode (see ``FrameCounter.format_time`` for parameter explanation). 168 Returns 169 ------- 170 str representing corresponding time in float format rounded to 3 decimals. 171 """ 172 # frame count to time correction is done in format_time 173 return FrameCounter.format_time(self._frame_count, self._fps, show_ms, show_days) 174 175 def get_elapsed_time(self) -> float: 176 """ 177 Get elapsed time as float value rounded to 3 decimals. 178 179 Returns 180 ------- 181 str representing corresponding time in float format rounded to 3 decimals. 182 """ 183 return round(float(self._frame_count)/self._fps,3)
Create a FrameCounter to follow elapsed time in audio/video file in read or write mode. Static utility functions allow to format elapsed time.
35 def __init__(self, fps: Union[int, float]): 36 """ 37 Create a VideoIO object giving ffmpeg/ffrobe loglevel and defining debug mode 38 39 Parameters 40 ---------- 41 fps: int or float. 42 Frames per second of the associated stream. 43 """ 44 # check init fps value 45 self._fps = float(fps) 46 if self._fps <= 0.0: 47 raise FrameCounterException("fps must be > 0.0.") 48 49 # 2 modes 50 self._frame_count = 0 # at 00:00:00.000
Create a VideoIO object giving ffmpeg/ffrobe loglevel and defining debug mode
Parameters
fps: int or float. Frames per second of the associated stream.
71 @property 72 def frame_count(self): 73 """ 74 Property to get underlying self._frame_count. Idea is to control setter to valid setting values. 75 """ 76 return self._frame_count
Property to get underlying self._frame_count. Idea is to control setter to valid setting values.
87 @property 88 def fps(self): 89 """ 90 Property to get underlying self._fps. 91 """ 92 return self._fps
Property to get underlying self._fps.
94 @staticmethod 95 def format_time(nb_frames: int, fps: float, show_ms : bool = True, show_days : bool = False) -> str: 96 """ 97 Static function to format time given by a number of frames and an fps. show_ms value defines if we show milliseconds, 98 show_days to show days instead of cummulative hour count. 99 100 Parameters 101 ---------- 102 nb_frames: int. 103 Number of samples already present in the stream. 104 105 fps: float. 106 Fps of the associated stream. 107 108 show_ms: bool. 109 Flag to say if we want to show milliseconds in the output str. 110 111 show_days: bool. 112 Flag to say if we want to show says instead of cumulative hours in the output str. 113 114 Returns 115 ------- 116 str representing corresponding time. Either 26:15:00 (show_ms=False, show_days=False), 26:15:00.500 (show_ms=True, show_days=False) 117 or 1 day(s) 02:15:00.500 (show_ms=True, show_days=True) 118 """ 119 # exact time in seconds (float) 120 exact_seconds = nb_frames / fps 121 122 # integer part for days/hours/minutes/seconds 123 total_seconds = int(exact_seconds) 124 125 # milliseconds = decimal part * 1000 126 millis = int(round((exact_seconds - total_seconds) * 1000)) 127 128 # handle the case where rounding results in 1000 ms 129 if millis == 1000: 130 millis = 0 131 total_seconds += 1 132 133 if show_days: 134 # compute number of days, hours, minutes, seconds 135 days, mod = divmod(total_seconds, 24 * 3600) 136 hours, mod = divmod(mod, 3600) 137 minutes, seconds = divmod(mod, 60) 138 139 if days > 0: 140 days = f"{days} days(s) " 141 else: 142 days = "" 143 else: 144 days = "" # no day as show_days = False 145 hours, mod = divmod(total_seconds, 3600) 146 minutes, seconds = divmod(mod, 60) 147 148 if show_ms == True: 149 millis = f".{millis:03d}" 150 else: 151 millis = "" 152 153 return f"{days}{hours:02d}:{minutes:02d}:{seconds:02d}{millis}"
Static function to format time given by a number of frames and an fps. show_ms value defines if we show milliseconds, show_days to show days instead of cummulative hour count.
Parameters
nb_frames: int. Number of samples already present in the stream.
fps: float. Fps of the associated stream.
show_ms: bool. Flag to say if we want to show milliseconds in the output str.
show_days: bool. Flag to say if we want to show says instead of cumulative hours in the output str.
Returns
str representing corresponding time. Either 26:15:00 (show_ms=False, show_days=False), 26:15:00.500 (show_ms=True, show_days=False)
or 1 day(s) 02:15:00.500 (show_ms=True, show_days=True)
155 def get_elapsed_time_as_str(self) -> str: 156 """ 157 Get elapsed time as string representing a float value rounded to 3 decimals. 158 159 Returns 160 ------- 161 str representing corresponding time in float format rounded to 3 decimals. 162 """ 163 return f"{float(self._frame_count)/self._fps:.3f}"
Get elapsed time as string representing a float value rounded to 3 decimals.
Returns
str representing corresponding time in float format rounded to 3 decimals.
165 def get_formated_elapsed_time_as_str(self, show_ms : bool = True, show_days : bool = False) -> str: 166 """ 167 Get elapsed time as string representing time with different mode (see ``FrameCounter.format_time`` for parameter explanation). 168 Returns 169 ------- 170 str representing corresponding time in float format rounded to 3 decimals. 171 """ 172 # frame count to time correction is done in format_time 173 return FrameCounter.format_time(self._frame_count, self._fps, show_ms, show_days)
Get elapsed time as string representing time with different mode (see FrameCounter.format_time for parameter explanation).
Returns
str representing corresponding time in float format rounded to 3 decimals.
175 def get_elapsed_time(self) -> float: 176 """ 177 Get elapsed time as float value rounded to 3 decimals. 178 179 Returns 180 ------- 181 str representing corresponding time in float format rounded to 3 decimals. 182 """ 183 return round(float(self._frame_count)/self._fps,3)
Get elapsed time as float value rounded to 3 decimals.
Returns
str representing corresponding time in float format rounded to 3 decimals.
21 class FrameCounterException(Exception): 22 """ 23 Dedicated exception class for FrameCounter class. 24 """ 25 def __init__(self, message="Error while setting FrameCounter parameters."): 26 self.message = message 27 super().__init__(self.message)
Dedicated exception class for FrameCounter class.