yta-video-frame-time 0.0.5__py3-none-any.whl → 0.0.7__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.

@@ -15,7 +15,11 @@ from yta_validation import PythonValidator
15
15
  from quicktions import Fraction
16
16
  from typing import Union
17
17
 
18
+ import math
18
19
 
20
+
21
+ # TODO: This T class has to be removed
22
+ # and replaced by the THandler
19
23
  class T:
20
24
  """
21
25
  Class to simplify the way we work with a
@@ -149,16 +153,9 @@ class T:
149
153
  return T(pts * time_base, time_base)
150
154
 
151
155
 
152
- # TODO: Careful with this below
153
- """
154
- To obtain the pts step, or frame duration in
155
- ticks, you need to apply 2 formulas that are
156
- different according to if the frame is video
157
- or audio:
158
- - Audio: .samples
159
- - Video: int(round((1 / .fps) / .time_base))
160
- """
161
-
156
+ # TODO: This below is interesting, above
157
+ # is old...
158
+
162
159
  def get_ts(
163
160
  start: Union[int, float, Fraction],
164
161
  end: Union[int, float, Fraction],
@@ -173,21 +170,21 @@ def get_ts(
173
170
  [start, end) because the last frame is the
174
171
  start of another time range.
175
172
  """
176
- start = T.from_fps(start, fps).truncated
177
- end = T.from_fps(end, fps).truncated
173
+ thandler = THandler(fps)
174
+
175
+ start = thandler.t.truncated(start)
176
+ end = thandler.t.truncated(end)
178
177
 
179
- time_base = fps_to_time_base(fps)
180
-
181
178
  return [
182
- start + i * time_base
183
- for i in range((end - start) // time_base)
179
+ start + i * thandler.time_base
180
+ for i in range((end - start) // thandler.time_base)
184
181
  ]
185
182
 
186
183
  def round_t(
187
184
  t: Union[int, float, Fraction],
188
185
  time_base = Fraction(1, 60),
189
186
  do_truncate: bool = True
190
- ):
187
+ ) -> Fraction:
191
188
  """
192
189
  Round the given 't' time moment to the most
193
190
  near multiple of the given 'time_base' (or
@@ -216,19 +213,610 @@ def round_t(
216
213
  round(steps) # round(float(steps))
217
214
  )
218
215
 
219
- return snapped_steps * time_base
216
+ return parse_fraction(snapped_steps * time_base)
217
+
218
+ def round_pts(
219
+ pts: int,
220
+ fps: Union[int, float, Fraction] = 60,
221
+ time_base = Fraction(1, 60),
222
+ do_truncate: bool = True
223
+ ) -> int:
224
+ """
225
+ Round the given 'pts' presentation
226
+ timestamp to the most near index
227
+ corresponding pts value (or the previous
228
+ one always if 'do_truncate' is True).
229
+
230
+ This method is very useful to truncate
231
+ 'pts' values in order to get the frames or
232
+ samples for the specific and exact time
233
+ moments according to their fps or sample
234
+ rate (that should be passed as the
235
+ 'time_base' parameter).
236
+
237
+ Pts value is calculated based on the 'fps'
238
+ and 'time_base', but here is an easier
239
+ example using the time moments.
240
+
241
+ Examples below, with `time_base = 1/5`:
242
+ - `t = 0.25` => `0.2` (truncated or rounded)
243
+ - `t = 0.35` => `0.2` (truncated)
244
+ - `t = 0.45` => `0.4` (truncated or rounded)
245
+ - `t = 0.55` => `0.6` (rounded)
246
+ """
247
+ ticks_per_frame = get_ticks_per_frame(fps, time_base)
248
+
249
+ frame_index = pts / ticks_per_frame
250
+
251
+ frame_index = (
252
+ math.floor(frame_index)
253
+ if do_truncate else
254
+ round(frame_index)
255
+ )
256
+
257
+ return int(frame_index * ticks_per_frame)
258
+
259
+ # TODO: Create a 'round_pts'
260
+
261
+ """
262
+ When we are working with the 't' time
263
+ moment we need to use the fps, and when
264
+ we are working with the 'pts' we need
265
+ to use the 'time_base'.
266
+ """
267
+
268
+ class _T:
269
+ """
270
+ Internal class to be used by the THandler
271
+ as a shortcut to the functionality
272
+ related with 't' values.
273
+ """
274
+
275
+ def __init__(
276
+ self,
277
+ t_handler: 'THandler'
278
+ ):
279
+ self._t_handler: THandler = t_handler
280
+ """
281
+ Instance of the parent THandler to
282
+ access to its properties.
283
+ """
284
+
285
+ def from_pts(
286
+ self,
287
+ pts: int,
288
+ do_truncate: Union[bool, None] = True
289
+ ) -> Fraction:
290
+ """
291
+ Get the 't' time moment for the frame
292
+ defined by the 'pts' presentation
293
+ timestamp.
294
+
295
+ If 't' is in a [start, end) range, we
296
+ will obtain the 'start' value if 't'
297
+ value is closer to it than to the 'end
298
+ value.
299
+
300
+ If 'do_truncate' is True, we will
301
+ always receive the 'start' value. If
302
+ None, we will not make any conversion
303
+ and the value received could be useless
304
+ because it is in the middle of a range.
305
+
306
+ The formula:
307
+ - `pts * time_base`
308
+ """
309
+ pts = (
310
+ self._t_handler.pts.truncated(pts)
311
+ if do_truncate is True else
312
+ self._t_handler.pts.rounded(pts)
313
+ if do_truncate is False else
314
+ pts # if None
315
+ )
316
+
317
+ return Fraction(pts * self._t_handler.time_base)
318
+
319
+ def to_pts(
320
+ self,
321
+ t: Union[int, float, Fraction],
322
+ do_truncate: Union[bool, None] = True
323
+ ) -> int:
324
+ """
325
+ Transform the given 't' to a 'pts' value
326
+ truncating, rounding or applying no
327
+ variation.
328
+
329
+ The formula:
330
+ - `int(t / time_base)`
331
+ """
332
+ return self._t_handler.pts.from_t(t, do_truncate)
333
+
334
+ def to_index(
335
+ self,
336
+ t: Union[int, float, Fraction],
337
+ do_truncate: Union[bool, None] = True
338
+ ) -> int:
339
+ """
340
+ Transform the given 't' to a index value
341
+ truncating, rounding or applying no
342
+ variation.
343
+
344
+ The formula:
345
+ - `int(t * fps)`
346
+ """
347
+ t = (
348
+ self.truncated(t)
349
+ if do_truncate is True else
350
+ self.rounded(t)
351
+ if do_truncate is False else
352
+ t
353
+ )
354
+
355
+ return frame_t_to_index(t, self.fps)
356
+
357
+ def from_index(
358
+ self,
359
+ index: int
360
+ ) -> Fraction:
361
+ """
362
+ Transform the given index to a 't' time
363
+ moment value.
364
+
365
+ The formula:
366
+ - `frame_index * (1 / fps)`
367
+ """
368
+ return frame_index_to_t(index, self.fps)
369
+
370
+ def truncated(
371
+ self,
372
+ t: Union[int, float, Fraction]
373
+ ):
374
+ """
375
+ Get the 't' value provided but truncated.
376
+
377
+ This means that if 't' is in a
378
+ [start, end) range, we will obtain the
379
+ 'start' value always.
380
+ """
381
+ return round_t(t, Fraction(1, self._t_handler.fps), do_truncate = True)
382
+
383
+ def rounded(
384
+ self,
385
+ t: Union[int, float, Fraction]
386
+ ):
387
+ """
388
+ Get the 't' value provided but rounded.
389
+
390
+ This means that if 't' is in a
391
+ [start, end) range, we will obtain
392
+ the 'start' or the 'end' value according
393
+ to which one is closer to the that 't'
394
+ value provided.
395
+ """
396
+ return round_t(t, Fraction(1, self._t_handler.fps), do_truncate = False)
397
+
398
+ def next(
399
+ self,
400
+ t: Union[int, float, Fraction],
401
+ n: int = 1,
402
+ do_truncate: bool = True
403
+ ) -> Fraction:
404
+ """
405
+ Get the value that is 'n' times ahead of
406
+ the 't' property of this instance
407
+ (truncated or rounded according to the
408
+ 'do_truncate' parameter provided).
409
+
410
+ Useful when you need the next value for a
411
+ range in an iteration or similar.
412
+
413
+ The formula:
414
+ - `t + n * (1 / fps)`
415
+ """
416
+ t = (
417
+ self.truncated(t)
418
+ if do_truncate else
419
+ self.rounded(t)
420
+ )
421
+
422
+ return t + n * (1 / self._t_handler.fps)
423
+
424
+ def previous(
425
+ self,
426
+ t: Union[int, float, Fraction],
427
+ n: int = 1,
428
+ do_truncate: bool = True
429
+ ) -> Fraction:
430
+ """
431
+ Get the value that is 'n' times before
432
+ the 't' property of this instance
433
+ (truncated or rounded according to the
434
+ 'do_truncate' parameter provided).
435
+
436
+ Useful when you need the previous value to
437
+ check if the current is the next one or
438
+ similar.
439
+
440
+ Be careful, if the 'truncated' value is 0
441
+ this will give you an unexpected negative
442
+ value.
443
+
444
+ The formula:
445
+ - `t - n * (1 / fps)`
446
+ """
447
+ t = (
448
+ self.truncated(t)
449
+ if do_truncate else
450
+ self.rounded(t)
451
+ )
452
+
453
+ return t - n * (1 / self._t_handler.fps)
454
+
455
+ class _Pts:
456
+ """
457
+ Internal class to be used by the THandler
458
+ as a shortcut to the functionality
459
+ related with 'pts' values.
460
+ """
461
+
462
+ def __init__(
463
+ self,
464
+ t_handler: 'THandler'
465
+ ):
466
+ self._t_handler: THandler = t_handler
467
+ """
468
+ Instance of the parent THandler to
469
+ access to its properties.
470
+ """
471
+
472
+ def from_t(
473
+ self,
474
+ t: Union[int, float, Fraction],
475
+ do_truncate: Union[bool, None] = True
476
+ ) -> int:
477
+ """
478
+ Get the pts (the amount of accumulated
479
+ ticks, also called presentation timestamp),
480
+ for the frame defined by the 't' time
481
+ moment provided.
482
+
483
+ If 't' is in a [start, end) range, we
484
+ will obtain the 'start' value if 't'
485
+ value is closer to it than to the 'end
486
+ value.
487
+
488
+ If 'do_truncate' is True, we will
489
+ always receive the 'start' value. If
490
+ None, we will not make any conversion
491
+ and the value received could be useless
492
+ because it is in the middle of a range.
493
+
494
+ The formula:
495
+ - `int(t / time_base)`
496
+ """
497
+ t = (
498
+ self._t_handler.t.truncated(t)
499
+ if do_truncate is True else
500
+ self._t_handler.t.rounded(t)
501
+ if do_truncate is False else
502
+ t # if None
503
+ )
504
+
505
+ return int(t / self._t_handler.time_base)
506
+
507
+ def to_t(
508
+ self,
509
+ pts: int,
510
+ do_truncate: Union[bool, None] = True
511
+ ) -> Fraction:
512
+ """
513
+ Transform the given 'pts' to a 't' value
514
+ truncating, rounding or applying no
515
+ variation.
516
+
517
+ The formula:
518
+ - `pts * time_base`
519
+ """
520
+ return self._t_handler.t.from_pts(pts, do_truncate)
521
+
522
+ def to_index(
523
+ self,
524
+ pts: int,
525
+ do_truncate: Union[bool, None] = True
526
+ ) -> int:
527
+ """
528
+ Transform the given 'pts' to a index value
529
+ truncating, rounding or applying no
530
+ variation.
531
+
532
+ The formula:
533
+ - `int((pts * time_base) * fps)`
534
+ """
535
+ return self._t_handler.t.to_index(
536
+ self.to_t(pts, do_truncate = None),
537
+ do_truncate = do_truncate
538
+ )
539
+
540
+ def from_index(
541
+ self,
542
+ index: int
543
+ ) -> Fraction:
544
+ """
545
+ Transform the given index to a 't' time
546
+ moment value.
547
+
548
+ The formula:
549
+ - `int((frame_index * (1 / fps)) * time_base)`
550
+ """
551
+ return self.from_t(
552
+ t = self._t_handler.t.from_index(index),
553
+ do_truncate = True
554
+ )
555
+
556
+ def truncated(
557
+ self,
558
+ pts: int
559
+ ):
560
+ """
561
+ Get the 'pts' value provided but truncated.
562
+
563
+ This means that if 't' is in a
564
+ [start, end) range, we will obtain the
565
+ 'start' value always.
566
+ """
567
+ return round_pts(
568
+ pts = pts,
569
+ fps = self._t_handler.fps,
570
+ time_base = self._t_handler.time_base,
571
+ do_truncate = True
572
+ )
573
+
574
+ def rounded(
575
+ self,
576
+ pts: int
577
+ ) -> int:
578
+ """
579
+ Get the 'pts' value provided but rounded.
580
+
581
+ This means that if 't' is in a
582
+ [start, end) range, we will obtain
583
+ the 'start' or the 'end' value according
584
+ to which one is closer to the that 't'
585
+ value provided.
586
+ """
587
+ return round_pts(
588
+ pts = pts,
589
+ fps = self._t_handler.fps,
590
+ time_base = self._t_handler.time_base,
591
+ do_truncate = False
592
+ )
593
+
594
+ def next(
595
+ self,
596
+ pts: int,
597
+ n: int = 1,
598
+ do_truncate: bool = True
599
+ ) -> int:
600
+ """
601
+ Get the value that is 'n' times ahead of
602
+ the 'pts' value provided (truncated or
603
+ rounded according to the 'do_truncate'
604
+ parameter provided).
605
+
606
+ Useful when you need the next value for a
607
+ range in an iteration or similar.
608
+
609
+ The formula:
610
+ - `pts + n * ticks_per_frame`
611
+ """
612
+ pts = (
613
+ self.truncated(pts)
614
+ if do_truncate else
615
+ self.rounded(pts)
616
+ )
617
+
618
+ return pts + n * get_ticks_per_frame(self._t_handler.fps, self._t_handler.time_base)
619
+
620
+ def previous(
621
+ self,
622
+ pts: int,
623
+ n: int = 1,
624
+ do_truncate: bool = True
625
+ ) -> int:
626
+ """
627
+ Get the value that is 'n' times before
628
+ the 't' property of this instance
629
+ (truncated or rounded according to the
630
+ 'do_truncate' parameter provided).
631
+
632
+ Useful when you need the previous value to
633
+ check if the current is the next one or
634
+ similar.
635
+
636
+ Be careful, if the 'truncated' value is 0
637
+ this will give you an unexpected negative
638
+ value.
639
+
640
+ The formula:
641
+ - `pts - n * ticks_per_frame`
642
+ """
643
+ pts = (
644
+ self.truncated(pts)
645
+ if do_truncate else
646
+ self.rounded(pts)
647
+ )
648
+
649
+ return pts - n * get_ticks_per_frame(self._t_handler.fps, self._t_handler.time_base)
650
+
651
+ class THandler:
652
+ """
653
+ Class to simplify the way we work with
654
+ pyav frames time moments, indexes and
655
+ pts values.
656
+
657
+ This is an example of what a video has:
658
+ - `fps = 60`
659
+ - `time_base = 1 / 15360`
660
+ - `tick = fps * time_base = 256`
661
+
662
+ So, considering this above:
663
+ - Frame #1: `pts[0] = 256 * 0 = 0`
664
+ - Frame #2: `pts[1] = 256 * 1 = 256`
665
+ - Frame #16: `pts[15] = 256 * 15 = 3840`
666
+ """
667
+
668
+ def __init__(
669
+ self,
670
+ fps: Union[int, float, Fraction],
671
+ time_base: Union[Fraction, None] = None
672
+ ):
673
+ """
674
+ If the 'time_base' provided is None it will
675
+ be automatically `1/fps`.
676
+ """
677
+ ParameterValidator.validate_mandatory_positive_number('fps', fps, do_include_zero = False)
678
+ ParameterValidator.validate_instance_of('time_base', time_base, 'Fraction')
679
+
680
+ self.fps: Fraction = parse_fraction(fps)
681
+ """
682
+ The frames per second.
683
+ """
684
+ self.time_base: Fraction = (
685
+ time_base
686
+ if time_base is not None else
687
+ fps_to_time_base(self.fps)
688
+ )
689
+ """
690
+ The time base.
691
+ """
692
+ self.t: _T = _T(self)
693
+ """
694
+ Shortcut to the instance that handles
695
+ the 't' related functionality.
696
+ """
697
+ self.pts: _Pts = _Pts(self)
698
+ """
699
+ Shortcut to the instance that handles
700
+ the 'pts' related functionality.
701
+ """
702
+
703
+ # TODO: I think I should create a THandler
704
+ # that receives 'fps' and 'time_base' and
705
+ # then, by passing a 't' value, we can
706
+ # calculate everything we need, so we
707
+ # simplify all these processes
708
+ def frame_t_to_index(
709
+ t: Union[float, int, Fraction],
710
+ fps: Union[float, int, Fraction]
711
+ ) -> int:
712
+ """
713
+ Get the index of the frame with the
714
+ given 't' time moment, based on the
715
+ also provided 'fps'.
716
+
717
+ The formula:
718
+ - `int(t * fps)`
719
+ """
720
+ return int(parse_fraction(t) * fps)
721
+
722
+ def frame_index_to_t(
723
+ index: int,
724
+ fps: Union[float, int, Fraction]
725
+ ):
726
+ """
727
+ Get the 't' time moment for the frame
728
+ with the given 'index', based on the
729
+ also provided 'fps'.
730
+
731
+ The formula:
732
+ - `frame_index * (1 / fps)`
733
+ """
734
+ return index * parse_fraction(1, parse_fraction(fps))
735
+
736
+ def frame_t_to_pts(
737
+ t: Union[float, int, Fraction],
738
+ fps: Union[float, int, Fraction],
739
+ time_base: Fraction
740
+ ):
741
+ """
742
+ Get the pts (the amount of accumulated
743
+ ticks, also called presentation timestamp),
744
+ for the frame defined by the 't' time
745
+ moment provided, based on the also provided
746
+ 'fps' and 'time_base'.
747
+
748
+ The formula:
749
+ - `frame_index * ticks_per_frame`
750
+ """
751
+ return frame_t_to_index(t, fps) * get_ticks_per_frame(fps, time_base)
752
+
753
+ def frame_pts_to_t(
754
+ pts: int,
755
+ time_base: Fraction
756
+ ) -> Fraction:
757
+ """
758
+ Get the 't' time moment of the frame with
759
+ the given 'pts' (the amount of accumulated
760
+ ticks, also called presentation timestamp),
761
+ based on the also provided 'time_base'.
762
+
763
+ The formula:
764
+ - `pts * time_base`
765
+ """
766
+ return parse_fraction(pts * time_base)
767
+
768
+ def get_ticks_per_frame(
769
+ fps: Union[float, int, Fraction],
770
+ time_base: Fraction
771
+ ) -> int:
772
+ """
773
+ Get the amount of ticks per frame. A
774
+ tick is the minimum amount of time we
775
+ spend from one frame to the next.
776
+
777
+ (!) This is only valid for video
778
+ apparently.
779
+
780
+ The formula:
781
+ - `1 / (fps * time_base)`
782
+ """
783
+ return int(Fraction(1, 1) / (fps * time_base))
784
+
785
+ def fps_to_frame_duration(
786
+ fps: Union[float, int, Fraction]
787
+ ) -> Fraction:
788
+ """
789
+ Get the frame duration based on the 'fps'
790
+ provided.
791
+
792
+ The formula:
793
+ - `1 / fps`
794
+ """
795
+ return Fraction(1, parse_fraction(fps))
220
796
 
221
797
  def fps_to_time_base(
222
- fps: Union[int, float, Fraction]
798
+ fps: Union[float, int, Fraction]
223
799
  ) -> Fraction:
224
800
  """
225
- Get the pyav time base from the given
226
- 'fps'.
801
+ Get the time base based on the given 'fps',
802
+ that will be basically `1/fps`. This is a
803
+ bit useless, just when we don't want to
804
+ think too much to use a time base and we
805
+ want to use the fps.
806
+
807
+ The formula:
808
+ - `1 / fps`
227
809
  """
228
- return (
229
- Fraction(1, fps)
230
- if NumberValidator.is_int(fps) else
231
- Fraction(1, 1) / fps
232
- if PythonValidator.is_instance_of(fps, 'Fraction') else
233
- Fraction(1, 1) / Fraction.from_float(fps).limit_denominator(1000000) # if float
234
- )
810
+ return Fraction(1, parse_fraction(fps))
811
+
812
+ def parse_fraction(
813
+ value: Union[float, int, Fraction]
814
+ ) -> Fraction:
815
+ """
816
+ Parse the provided 'value' as a Fraction
817
+ and limits its denominator.
818
+ """
819
+ fraction = Fraction(value)#.limit_denominator(100_000)
820
+
821
+ return fraction
822
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: yta-video-frame-time
3
- Version: 0.0.5
3
+ Version: 0.0.7
4
4
  Summary: Youtube Autonomous Video Frame Time Module
5
5
  Author: danialcala94
6
6
  Author-email: danielalcalavalera@gmail.com
@@ -0,0 +1,6 @@
1
+ yta_video_frame_time/__init__.py,sha256=-YOa7lOKdiA3FwDEHHU1tHobnmhjFpTaVLfJQLZqoMI,22252
2
+ yta_video_frame_time/t_fraction.py,sha256=hsCNZajG98XGnWYI0T6wSfBnAK3vf7ZiFI_GZHO8yRI,22254
3
+ yta_video_frame_time-0.0.7.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ yta_video_frame_time-0.0.7.dist-info/METADATA,sha256=ooHYnwkytyyjpKRKLKakXhDJJD-HAmpXxvWuaXfVrZo,515
5
+ yta_video_frame_time-0.0.7.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
6
+ yta_video_frame_time-0.0.7.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- yta_video_frame_time/__init__.py,sha256=-YOa7lOKdiA3FwDEHHU1tHobnmhjFpTaVLfJQLZqoMI,22252
2
- yta_video_frame_time/t_fraction.py,sha256=JR2GNDjk06I2YFKTVJpNQ2hxlEwUF3QG02Ba2sEDrj0,6639
3
- yta_video_frame_time-0.0.5.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
- yta_video_frame_time-0.0.5.dist-info/METADATA,sha256=Lh-jnjYVJh5mmLYq0ngkgMP1u9L_ta23nMQrfgNkZKQ,515
5
- yta_video_frame_time-0.0.5.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
6
- yta_video_frame_time-0.0.5.dist-info/RECORD,,