simple-ffmpeg-batch-io 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,81 @@
1
+ """
2
+ Create a ``FrameContainer`` with data and associated timestamp(s)
3
+
4
+ Authors
5
+ -------
6
+ Dominique Vaufreydaz
7
+
8
+ """
9
+
10
+ __authors__ = ("Dominique Vaufreydaz")
11
+
12
+ import numpy as np
13
+
14
+ # class to get audio or video frames with associated timestamp list
15
+ class FrameContainer:
16
+ """
17
+ Create a Container with audio or image data and associated timestamp(s).
18
+ """
19
+
20
+ class FrameContainerException(Exception):
21
+ """
22
+ Dedicated exception class for FrameContainer class.
23
+ """
24
+ def __init__(self, message="Error while setting FrameCounter parameters."):
25
+ self.message = message
26
+ super().__init__(self.message)
27
+
28
+ nb_frames: int
29
+ """ number of frames in the frame container. 1 for audio frame or images, n for a batch. """
30
+
31
+ data: np.array
32
+ """ Audio frame or image, or batch of images or audio frames. """
33
+
34
+ timestamps: np.array
35
+ """ an np.array of timestamp(s) associated to the data frame(s). """
36
+
37
+ def __init__(self, nb_frames : int, frames : np.array, fps : float, start_time : float = 0.0 ):
38
+ """
39
+ Create a FrameContainer object with data and associated timestamps
40
+
41
+ Parameters
42
+ ----------
43
+ nb_frames: int.
44
+ Number of frame(s) in the frame container. Either 1, either number of element in the batch.
45
+
46
+ frames: np.array
47
+ Data for image, audio frame or batch of them.
48
+
49
+ fps : float.
50
+ fps of the read stream.
51
+
52
+ start_time: float (default = 0.0).
53
+ Start time of the current FrameContainer, i.e. time of the (first) frame.
54
+ """
55
+
56
+ # check params
57
+ if nb_frames <= 0:
58
+ raise self.FrameContainerException("nb_frames must be > 0.")
59
+ if nb_frames > 1 and frames.shape[0] != nb_frames:
60
+ raise self.FrameContainerException("nb_frames and batch size (frames.shape[0]) differs.")
61
+ if fps <= 0.0:
62
+ raise self.FrameContainerException("fps must be > 0.0.")
63
+ if start_time < 0.0:
64
+ raise self.FrameContainerException("start_time must be >= 0.0.")
65
+
66
+ self.nb_frames = nb_frames
67
+ self.data = frames
68
+ # first frame is at time start_time
69
+ self.timestamps = np.linspace(start_time, start_time+(self.nb_frames-1)*fps, self.nb_frames).tolist()
70
+
71
+ def totorch(self):
72
+ """
73
+ Convert the numy array into a pytorch tensor.
74
+
75
+ Returns
76
+ ----------
77
+ pytorch tensor.
78
+ """
79
+ # import torch late as it is not in the standard requirements for simple-ffmpeg-batch-io
80
+ import torch
81
+ return torch.from_numpy(self.data)
@@ -0,0 +1,182 @@
1
+ """
2
+ 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.
3
+
4
+ Authors
5
+ -------
6
+ Dominique Vaufreydaz
7
+
8
+ """
9
+
10
+ __authors__ = ("Dominique Vaufreydaz")
11
+
12
+ from typing import Union
13
+
14
+ # class to count frame, thus time, in audio/video files
15
+ class 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)
@@ -0,0 +1,26 @@
1
+ """
2
+ Definition of the PipeMode for ``AudioIO`` and ``VideoIO`` classes.
3
+
4
+ Authors
5
+ -------
6
+ Dominique Vaufreydaz (inspired from original C++ code: https://github.com/Vaufreyd/ReadWriteVideosWithOpenCV)
7
+
8
+ """
9
+
10
+ __authors__ = ("Dominique Vaufreydaz")
11
+
12
+ from enum import Enum
13
+
14
+ class PipeMode(Enum):
15
+ """
16
+ Enum class for pipe opening type.
17
+ """
18
+ UNK_MODE = 0
19
+ """ No pipe mode defined """
20
+
21
+ READ_MODE = 1
22
+ """ Read mode (get data from pipe) """
23
+
24
+ WRITE_MODE = 2
25
+ """ Write mode (write data to pipe) """
26
+