yta-video-frame-time 0.0.1__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.

Potentially problematic release.


This version of yta-video-frame-time might be problematic. Click here for more details.

@@ -0,0 +1,543 @@
1
+ """
2
+ Module to handle frame indexes and times.
3
+ """
4
+ from yta_validation.parameter import ParameterValidator
5
+
6
+
7
+ SMALL_AMOUNT_TO_FIX = 0.0000000001
8
+ """
9
+ Small amount we need to add to fix some floating
10
+ point number issues we've found. Something like
11
+ 0.3333333333333326 will turn into 9 frames for a
12
+ fps = 30 video, but this is wrong, as it should
13
+ be 10 frames and it is happening due to a minimal
14
+ floating point difference.
15
+ """
16
+
17
+
18
+ class T:
19
+ """
20
+ Class to wrap the functionality related
21
+ to handling a video frame time moment 't'.
22
+ """
23
+
24
+ def get_frame_time_base(
25
+ t: float,
26
+ fps: float
27
+ ):
28
+ """
29
+ Get the base frame time moment t
30
+ (the one who is the start of the
31
+ frame time interval plus a small
32
+ amount to fix issues) from the
33
+ given time moment 't' of the video
34
+ with the also provided 'fps'.
35
+ """
36
+ ParameterValidator.validate_mandatory_positive_number('t', t, do_include_zero = True)
37
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
38
+
39
+ return T.frame_time_to_frame_index(t, fps) / fps + SMALL_AMOUNT_TO_FIX
40
+
41
+ def get_frame_indexes(
42
+ duration: float,
43
+ fps: float,
44
+ do_invert_order: bool = False
45
+ ):
46
+ """
47
+ Get the list of the frame indexes of
48
+ the video with the given 'duration'
49
+ and 'fps'.
50
+
51
+ If a video lasts 1 second and has 5
52
+ fps, this method will return: 0, 1,
53
+ 2, 3, 4.
54
+ """
55
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
56
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
57
+ ParameterValidator.validate_mandatory_bool('do_invert_order', do_invert_order)
58
+
59
+ # If you remove 'list' you get a generator instead
60
+ frame_indexes = list(range(get_number_of_frames(duration, fps)))
61
+
62
+ return (
63
+ frame_indexes[::-1]
64
+ if do_invert_order else
65
+ frame_indexes
66
+ )
67
+
68
+ def get_frame_indexes_from_number_of_frames(
69
+ number_of_frames: int,
70
+ do_invert_order: bool = False
71
+ ):
72
+ """
73
+ Get all the video frame indexes that
74
+ a video with the 'number_of_frames'
75
+ given, ordered from first to last if
76
+ 'do_invert_order' is False, or from
77
+ last to first if it is True.
78
+ """
79
+ ParameterValidator.validate_mandatory_positive_int('number_of_frames', number_of_frames, do_include_zero = True)
80
+ ParameterValidator.validate_mandatory_bool('do_invert_order', do_invert_order)
81
+
82
+ return (
83
+ list(range(number_of_frames - 1, -1, -1))
84
+ if do_invert_order else
85
+ list(range(number_of_frames))
86
+ )
87
+
88
+ def get_first_n_frames_indexes(
89
+ duration: float,
90
+ fps: float,
91
+ n: int
92
+ ):
93
+ """
94
+ Obtain the first 'n' frames indexes of the current
95
+ video to be able to use them within a condition
96
+ with the '.get_frame(t)' method.
97
+
98
+ This list can be used to check if the current frame
99
+ number (index) is on it or not, to apply the frame
100
+ image effect or to leave it as it is.
101
+
102
+ Each frame time moment has been increased by
103
+ a small amount to ensure it is greater than
104
+ the base frame time value (due to decimals
105
+ issue).
106
+ """
107
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
108
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
109
+ ParameterValidator.validate_mandatory_positive_int('n', n, do_include_zero = False)
110
+
111
+ return T.get_odd_frames_indexes(duration, fps)[:n]
112
+
113
+ def get_last_n_frames_indexes(
114
+ duration: float,
115
+ fps: float,
116
+ n: int
117
+ ):
118
+ """
119
+ Obtain the last 'n' frames indexes of the current
120
+ video to be able to use them within a condition
121
+ with the '.get_frame(t)' method.
122
+
123
+ This list can be used to check if the current frame
124
+ number (index) is on it or not, to apply the frame
125
+ image effect or to leave it as it is.
126
+
127
+ Each frame time moment has been increased by
128
+ a small amount to ensure it is greater than
129
+ the base frame time value (due to decimals
130
+ issue).
131
+ """
132
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
133
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
134
+ ParameterValidator.validate_mandatory_positive_int('n', n, do_include_zero = False)
135
+
136
+ return T.get_odd_frames_indexes(duration, fps)[-n:]
137
+
138
+ def get_even_frames_indexes(
139
+ duration: float,
140
+ fps: float
141
+ ):
142
+ """
143
+ Array containing all the even indexes of video
144
+ frames that can be used to obtain its corresponding
145
+ frame time moment, or to simplify calculations.
146
+ """
147
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
148
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
149
+
150
+ frame_indexes = T.get_frame_indexes(duration, fps)
151
+
152
+ return frame_indexes[frame_indexes % 2 == 0]
153
+
154
+ def get_first_n_even_frames_indexes(
155
+ duration: float,
156
+ fps: float,
157
+ n: int
158
+ ):
159
+ """
160
+ Obtain the first 'n' even frames indexes of the
161
+ current video to be able to use them within a
162
+ condition with the '.get_frame(t)' method.
163
+
164
+ This list can be used to check if the current frame
165
+ number (index) is on it or not, to apply the frame
166
+ image effect or to leave it as it is.
167
+
168
+ If 'n' is greater than the real number of even
169
+ frames, 'n' will get that value so the result will
170
+ be all the even frames indexes.
171
+
172
+ Each frame time moment has been increased by
173
+ a small amount to ensure it is greater than
174
+ the base frame time value (due to decimals
175
+ issue).
176
+ """
177
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
178
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
179
+ ParameterValidator.validate_mandatory_positive_int('n', n, do_include_zero = False)
180
+
181
+ return T.get_even_frames_indexes(duration, fps)[:n]
182
+
183
+ def get_last_n_even_frames_indexes(
184
+ duration: float,
185
+ fps: float,
186
+ n: int
187
+ ):
188
+ """
189
+ Obtain the last 'n' even frames indexes of the
190
+ current video to be able to use them within a
191
+ condition with the '.get_frame(t)' method.
192
+
193
+ This list can be used to check if the current frame
194
+ number (index) is on it or not, to apply the frame
195
+ image effect or to leave it as it is.
196
+
197
+ If 'n' is greater than the real number of even
198
+ frames, 'n' will get that value so the result will
199
+ be all the even frames indexes.
200
+
201
+ Each frame time moment has been increased by
202
+ a small amount to ensure it is greater than
203
+ the base frame time value (due to decimals
204
+ issue).
205
+ """
206
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
207
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
208
+ ParameterValidator.validate_mandatory_positive_int('n', n, do_include_zero = False)
209
+
210
+ return T.get_even_frames_indexes(duration, fps)[-n:]
211
+
212
+ def get_odd_frames_indexes(
213
+ duration: float,
214
+ fps: float,
215
+ ):
216
+ """
217
+ Array containing all the odd indexes of video
218
+ frames that can be used to obtain its corresponding
219
+ frame time moment, or to simplify calculations.
220
+ """
221
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
222
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
223
+
224
+ frame_indexes = T.get_frame_indexes(duration, fps)
225
+
226
+ return frame_indexes[frame_indexes % 2 != 0]
227
+
228
+ def get_last_n_odd_frames_indexes(
229
+ duration: float,
230
+ fps: float,
231
+ n: int
232
+ ):
233
+ """
234
+ Obtain the last 'n' odd frames indexes of the
235
+ current video to be able to use them within a
236
+ condition with the '.get_frame(t)' method.
237
+
238
+ This list can be used to check if the current frame
239
+ number (index) is on it or not, to apply the frame
240
+ image effect or to leave it as it is.
241
+
242
+ If 'n' is greater than the real number of odd
243
+ frames, 'n' will get that value so the result will
244
+ be all the odd frames indexes.
245
+
246
+ Each frame time moment has been increased by
247
+ a small amount to ensure it is greater than
248
+ the base frame time value (due to decimals
249
+ issue).
250
+ """
251
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
252
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
253
+ ParameterValidator.validate_mandatory_positive_int('n', n, do_include_zero = False)
254
+
255
+ return T.get_odd_frames_indexes(duration, fps)[-n:]
256
+
257
+ def get_first_n_odd_frames_indexes(
258
+ duration: float,
259
+ fps: float,
260
+ n: int
261
+ ):
262
+ """
263
+ Obtain the first 'n' odd frames indexes of the
264
+ current video to be able to use them within a
265
+ condition with the '.get_frame(t)' method.
266
+
267
+ This list can be used to check if the current frame
268
+ number (index) is on it or not, to apply the frame
269
+ image effect or to leave it as it is.
270
+
271
+ If 'n' is greater than the real number of odd
272
+ frames, 'n' will get that value so the result will
273
+ be all the odd frames indexes.
274
+
275
+ Each frame time moment has been increased by
276
+ a small amount to ensure it is greater than
277
+ the base frame time value (due to decimals
278
+ issue).
279
+ """
280
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
281
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
282
+ ParameterValidator.validate_mandatory_positive_int('n', n, do_include_zero = False)
283
+
284
+ return T.get_odd_frames_indexes(duration, fps)[:n]
285
+
286
+ def get_frame_time_moments(
287
+ duration: float,
288
+ fps: float,
289
+ do_invert_order: bool = False
290
+ ):
291
+ """
292
+ Get the time moment of each video
293
+ frame according to the provided video
294
+ 'duration' and 'fps'. This will always
295
+ include the second 0 and the
296
+ inmediately before the duration.
297
+
298
+ If a video lasts 1 second and has 5
299
+ fps, this method will return: 0, 0.2,
300
+ 0.4, 0.6, 0.8.
301
+
302
+ This method can return non-exact
303
+ decimal values so we recommend you to
304
+ add a small amount to ensure it is
305
+ above the expected base frame time.
306
+ """
307
+ ParameterValidator.validate_mandatory_positive_number('duration', duration, do_include_zero = False)
308
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
309
+ ParameterValidator.validate_mandatory_bool('do_invert_order', do_invert_order)
310
+
311
+ frame_time_moments = [
312
+ (get_frame_duration(fps) * i) + SMALL_AMOUNT_TO_FIX
313
+ for i in range(get_number_of_frames(duration, fps) + 1)
314
+ ][:-1]
315
+
316
+ return (
317
+ frame_time_moments[::-1]
318
+ if do_invert_order else
319
+ frame_time_moments
320
+ )
321
+
322
+ def get_frame_time_moments_from_number_of_frames(
323
+ number_of_frames: int,
324
+ fps: float,
325
+ do_invert_order: bool = False
326
+ ):
327
+ """
328
+ Get all the video frame time moments
329
+ t for a video with the provided
330
+ 'number_of_frames'. Each 't' includes
331
+ a small amount increased to fix some
332
+ issues.
333
+ """
334
+ ParameterValidator.validate_mandatory_positive_int('number_of_frames', number_of_frames, do_include_zero = False)
335
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
336
+ ParameterValidator.validate_mandatory_bool('do_invert_order', do_invert_order)
337
+
338
+ return [
339
+ T.frame_index_to_frame_time(i, fps)
340
+ for i in T.get_frame_indexes_from_number_of_frames(number_of_frames)
341
+ ]
342
+
343
+ def video_frame_time_to_video_frame_index(
344
+ t: float,
345
+ fps: float
346
+ ):
347
+ """
348
+ Transform the provided 't' frame time to
349
+ its corresponding frame index according
350
+ to the 'fps' provided.
351
+
352
+ This method applies the next formula:
353
+
354
+ int(t * fps + SMALL_AMOUNT_TO_FIX)
355
+ """
356
+ ParameterValidator.validate_mandatory_positive_number('t', t, do_include_zero = True)
357
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
358
+
359
+ return int((t + SMALL_AMOUNT_TO_FIX) * fps)
360
+
361
+ def video_frame_index_to_video_frame_time(
362
+ i: int,
363
+ fps: float
364
+ ):
365
+ """
366
+ Transform the provided 'i' frame index to
367
+ its corresponding frame time according to
368
+ the 'fps' provided.
369
+
370
+ This method applies the next formula:
371
+
372
+ i * 1 / fps + SMALL_AMOUNT_TO_FIX
373
+ """
374
+ ParameterValidator.validate_mandatory_positive_int('i', i, do_include_zero = True)
375
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
376
+
377
+ return i * get_frame_duration(fps) + SMALL_AMOUNT_TO_FIX
378
+
379
+ # Audio below
380
+ def video_frame_time_to_audio_frame_times(
381
+ video_t: float,
382
+ video_fps: float,
383
+ audio_fps: float,
384
+ do_invert_order: bool = False
385
+ ):
386
+ """
387
+ Get all the audio time moments (tts)
388
+ attached to the given video time
389
+ moment 't', as an array.
390
+
391
+ One video time moment 't' includes
392
+ a lot of video audio 't' time
393
+ moments. The amount of video audio
394
+ frames per video frame is calculated
395
+ with the division of the audio fps
396
+ by the video fps.
397
+
398
+ The result is an array of 't' video
399
+ audio time moments. Maybe you need
400
+ to turn it into a numpy array.
401
+
402
+ This is useful to obtain all the
403
+ video audio time moments attached to
404
+ the given video time moment
405
+ 'video_t'.
406
+ """
407
+ ParameterValidator.validate_mandatory_positive_number('video_t', video_t, do_include_zero = True)
408
+ ParameterValidator.validate_mandatory_positive_number('video_fps', video_fps, do_include_zero = False)
409
+ ParameterValidator.validate_mandatory_positive_number('audio_fps', audio_fps, do_include_zero = False)
410
+ ParameterValidator.validate_mandatory_bool('do_invert_order', do_invert_order)
411
+
412
+ from yta_general_utils.math.progression import Progression
413
+
414
+ audio_frames_per_video_frame = int(audio_fps / video_fps)
415
+ audio_frame_duration = 1 / audio_fps
416
+ video_frame_duration = 1 / video_fps
417
+
418
+ t = T.get_frame_time_base(video_t, video_fps)
419
+
420
+ audio_time_moments = Progression(
421
+ start = t,
422
+ end = t + video_frame_duration - audio_frame_duration,
423
+ n = audio_frames_per_video_frame
424
+ ).values
425
+
426
+ return (
427
+ audio_time_moments[::-1]
428
+ if do_invert_order else
429
+ audio_time_moments
430
+ )
431
+
432
+ def audio_frame_time_to_video_frame_time(
433
+ audio_t: float,
434
+ video_fps: float
435
+ ):
436
+ """
437
+ Get the video frame time moment t
438
+ from the given video udio frame time
439
+ moment 'audio_t', according to its
440
+ 'video_fps' frames per second.
441
+
442
+ This method is useful to obtain the
443
+ video frame attached to the given
444
+ audio time moment 'audio_t'.
445
+ """
446
+ ParameterValidator.validate_mandatory_positive_number('audio_t', audio_t, do_include_zero = True)
447
+ ParameterValidator.validate_mandatory_positive_number('video_fps', video_fps, do_include_zero = False)
448
+
449
+ return T.get_frame_time_base(audio_t , video_fps)
450
+
451
+ def audio_frame_index_to_video_frame_index(
452
+ audio_index: int,
453
+ video_fps: float,
454
+ audio_fps: float
455
+ ):
456
+ """
457
+ Get the video frame index from the
458
+ provided video audio frame index
459
+ 'audio_index', using the also given
460
+ 'video_fps' and 'audio_fps'.
461
+ """
462
+ ParameterValidator.validate_mandatory_positive_int('audio_index', audio_index, do_include_zero = True)
463
+ ParameterValidator.validate_mandatory_positive_number('video_fps', video_fps, do_include_zero = False)
464
+ ParameterValidator.validate_mandatory_positive_number('audio_fps', audio_fps, do_include_zero = False)
465
+
466
+ return round(audio_index * (video_fps / audio_fps))
467
+
468
+ def audio_frame_index_to_video_frame_time(
469
+ audio_index: int,
470
+ video_fps: float,
471
+ audio_fps: float
472
+ ):
473
+ """
474
+ Get the video frame time moment t
475
+ from the given video audio frame
476
+ index 'audio_index', using the also
477
+ provided 'video_fps' and
478
+ 'audio_fps'.
479
+ """
480
+ ParameterValidator.validate_mandatory_positive_int('audio_index', audio_index, do_include_zero = True)
481
+ ParameterValidator.validate_mandatory_positive_number('video_fps', video_fps, do_include_zero = False)
482
+ ParameterValidator.validate_mandatory_positive_number('audio_fps', audio_fps, do_include_zero = False)
483
+
484
+ return T.video_frame_index_to_video_frame_time(
485
+ T.audio_frame_index_to_video_frame_index(
486
+ audio_index,
487
+ video_fps,
488
+ audio_fps
489
+ ),
490
+ video_fps
491
+ )
492
+
493
+ def audio_frame_time_to_video_frame_index(
494
+ audio_t: float,
495
+ video_fps: float,
496
+ audio_fps: float
497
+ ):
498
+ """
499
+ Get the video frame index from the
500
+ the given video audio frame time
501
+ moment 'audio_t', using the also
502
+ provided 'video_fps' and 'audio_fps'.
503
+ """
504
+ ParameterValidator.validate_mandatory_positive_number('audio_t', audio_t, do_include_zero = True)
505
+ ParameterValidator.validate_mandatory_positive_number('video_fps', video_fps, do_include_zero = False)
506
+ ParameterValidator.validate_mandatory_positive_number('audio_fps', audio_fps, do_include_zero = False)
507
+
508
+ return T.audio_frame_index_to_video_frame_index(
509
+ T.video_frame_time_to_video_frame_index(
510
+ audio_t,
511
+ audio_fps
512
+ ),
513
+ video_fps,
514
+ audio_fps
515
+ )
516
+
517
+ def get_frame_duration(
518
+ fps: float
519
+ ) -> float:
520
+ """
521
+ Get the frame duration based on the
522
+ video frames per second ('fps')
523
+ provided.
524
+
525
+ The formula is:
526
+ - `1 / fps`
527
+ """
528
+ return 1 / fps
529
+
530
+ def get_number_of_frames(
531
+ duration: float,
532
+ fps: float
533
+ ) -> int:
534
+ """
535
+ Get the number of frames of the video
536
+ with the given 'duration' and 'fps'
537
+ and using a small amount to fix the
538
+ rounding bug.
539
+
540
+ The formula is:
541
+ - `int(duration * fps + SMALL_AMOUNT)`
542
+ """
543
+ return int(duration * fps + SMALL_AMOUNT_TO_FIX)
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.3
2
+ Name: yta-video-frame-time
3
+ Version: 0.0.1
4
+ Summary: Youtube Autonomous Video Frame Time Module
5
+ Author: danialcala94
6
+ Author-email: danielalcalavalera@gmail.com
7
+ Requires-Python: ==3.9
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Requires-Dist: yta_validation (>=0.0.1,<1.0.0)
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Youtube Autonomous Video Frame Time Module
14
+
15
+ The way to handle video frame timing
@@ -0,0 +1,5 @@
1
+ yta_video_frame_time/__init__.py,sha256=iN9nRtV3Rjpp6vCcz1fckjVDijHLHzLdTfGN9l4cG6w,20019
2
+ yta_video_frame_time-0.0.1.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
3
+ yta_video_frame_time-0.0.1.dist-info/METADATA,sha256=uYL_vqtsJSQ7DqSxGf8YXWRyIX1kQDcfYbCLPWH28v8,472
4
+ yta_video_frame_time-0.0.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
5
+ yta_video_frame_time-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.1.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any