yta-video-opengl 0.0.12__py3-none-any.whl → 0.0.13__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.
@@ -4,6 +4,7 @@ that, using ffmpeg, detects the video.
4
4
  """
5
5
  from yta_video_opengl.reader.cache import VideoFrameCache
6
6
  from yta_video_opengl.utils import iterate_stream_frames_demuxing
7
+ from yta_video_opengl.t import T
7
8
  from yta_validation import PythonValidator
8
9
  from av.video.frame import VideoFrame
9
10
  from av.audio.frame import AudioFrame
@@ -11,7 +12,7 @@ from av.packet import Packet
11
12
  from av.video.stream import VideoStream
12
13
  from av.audio.stream import AudioStream
13
14
  from av.container.input import InputContainer
14
- from fractions import Fraction
15
+ from quicktions import Fraction
15
16
  from av import open as av_open
16
17
  from typing import Union
17
18
  from dataclasses import dataclass
@@ -58,7 +59,7 @@ class VideoReaderFrame:
58
59
  self,
59
60
  # TODO: Add the type, please
60
61
  frame: any,
61
- t: float = None,
62
+ t: Union[int, float, Fraction] = None,
62
63
  pixel_format: str = 'rgb24'
63
64
  ):
64
65
  self.value: Union[AudioFrame, VideoFrame] = frame
@@ -66,7 +67,7 @@ class VideoReaderFrame:
66
67
  The frame content, that can be audio or video
67
68
  frame.
68
69
  """
69
- self.t: float = t
70
+ self.t: Fraction = Fraction(t)
70
71
  """
71
72
  The 't' time moment of the frame.
72
73
  """
@@ -139,6 +140,8 @@ class VideoReader:
139
140
  """
140
141
  return self.container.decode(self.video_stream)
141
142
 
143
+ # TODO: Remove this when possible, we are not
144
+ # using 'next' properties
142
145
  @property
143
146
  def next_frame(
144
147
  self
@@ -159,16 +162,6 @@ class VideoReader:
159
162
  """
160
163
  return self.container.decode(self.audio_stream)
161
164
 
162
- @property
163
- def next_audio_frame(
164
- self
165
- ) -> Union[AudioFrame, None]:
166
- """
167
- Get the next audio frame (decoded) from the
168
- iterator.
169
- """
170
- return next(self.audio_frame_iterator)
171
-
172
165
  @property
173
166
  def packet_iterator(
174
167
  self
@@ -179,16 +172,6 @@ class VideoReader:
179
172
  """
180
173
  return self.container.demux(self.video_stream)
181
174
 
182
- @property
183
- def next_packet(
184
- self
185
- ) -> Union[Packet, None]:
186
- """
187
- Get the next video packet (not decoded) from
188
- the iterator.
189
- """
190
- return next(self.packet_iterator)
191
-
192
175
  @property
193
176
  def audio_packet_iterator(
194
177
  self
@@ -199,16 +182,6 @@ class VideoReader:
199
182
  """
200
183
  return self.container.demux(self.audio_stream)
201
184
 
202
- @property
203
- def next_audio_packet(
204
- self
205
- ) -> Union[Packet, None]:
206
- """
207
- Get the next audio packet (not decoded) from
208
- the iterator.
209
- """
210
- return next(self.packet_iterator)
211
-
212
185
  @property
213
186
  def packet_with_audio_iterator(
214
187
  self
@@ -220,18 +193,6 @@ class VideoReader:
220
193
  """
221
194
  return self.container.demux((self.video_stream, self.audio_stream))
222
195
 
223
- @property
224
- def next_packet_with_audio(
225
- self
226
- ) -> Union[Packet, None]:
227
- """
228
- Get the next video frames packet (or audio
229
- frames packet) from the iterator. Depending
230
- on the position, the packet can be video or
231
- audio.
232
- """
233
- return next(self.packet_with_audio_iterator)
234
-
235
196
  @property
236
197
  def has_video(
237
198
  self
@@ -312,8 +273,6 @@ class VideoReader:
312
273
  The fps of the video.
313
274
  """
314
275
  return (
315
- # They return it as a Fraction but we usually
316
- # use it as float or even int
317
276
  self.video_stream.average_rate
318
277
  if self.has_video else
319
278
  None
@@ -515,6 +474,7 @@ class VideoReader:
515
474
  )
516
475
  # TODO: Should this be 'AUTO' (?)
517
476
  self.video_stream.thread_type = 'AUTO'
477
+
518
478
  self.audio_stream = (
519
479
  self.container.streams.audio[0]
520
480
  if self.container.streams.audio else
@@ -534,7 +494,7 @@ class VideoReader:
534
494
 
535
495
  def seek(
536
496
  self,
537
- pts,
497
+ pts: int,
538
498
  stream = None
539
499
  ) -> 'VideoReader':
540
500
  """
@@ -567,7 +527,8 @@ class VideoReader:
567
527
  for frame in self.frame_iterator:
568
528
  yield VideoReaderFrame(
569
529
  frame = frame,
570
- t = float(frame.pts * self.time_base),
530
+ # TODO: Maybe use util to transform it (?)
531
+ t = frame.pts * self.time_base,
571
532
  pixel_format = self.pixel_format
572
533
  )
573
534
 
@@ -672,7 +633,7 @@ class VideoReader:
672
633
 
673
634
  def get_frame_from_t(
674
635
  self,
675
- t: float
636
+ t: Union[int, float, Fraction]
676
637
  ) -> 'VideoFrame':
677
638
  """
678
639
  Get the video frame with the given 't' time
@@ -692,7 +653,7 @@ class VideoReader:
692
653
 
693
654
  def get_audio_frame_from_t(
694
655
  self,
695
- t: float
656
+ t: Union[int, float, Fraction]
696
657
  ) -> 'AudioFrame':
697
658
  """
698
659
  Get the audio frame with the given 't' time
@@ -702,7 +663,7 @@ class VideoReader:
702
663
 
703
664
  def get_audio_frames_from_t(
704
665
  self,
705
- t: float
666
+ t: Union[int, float, Fraction]
706
667
  ):
707
668
  """
708
669
  Get the sequence of audio frames for the
@@ -715,14 +676,14 @@ class VideoReader:
715
676
  (remember that a video frame is associated
716
677
  with more than 1 audio frame).
717
678
  """
718
- print(f'Getting audio frames from video, from t:{str(t)} - nt:{str(t + (1 / self.fps))}')
719
- for frame in self.audio_cache.get_frames(t, t + (1 / self.fps)):
679
+ t: T = T.from_fps(t, self.fps)
680
+ for frame in self.audio_cache.get_frames(t.truncated, t.next(1).truncated):
720
681
  yield frame
721
682
 
722
683
  def get_frames(
723
684
  self,
724
- start: float = 0.0,
725
- end: Union[float, None] = None
685
+ start: Union[int, float, Fraction] = 0.0,
686
+ end: Union[int, float, Fraction, None] = None
726
687
  ):
727
688
  """
728
689
  Iterator to get the video frames in between
@@ -733,8 +694,8 @@ class VideoReader:
733
694
 
734
695
  def get_audio_frames(
735
696
  self,
736
- start: float = 0.0,
737
- end: Union[float, None] = None
697
+ start: Union[int, float, Fraction] = 0.0,
698
+ end: Union[int, float, Fraction, None] = None
738
699
  ):
739
700
  """
740
701
  Iterator to get the audio frames in between
@@ -752,6 +713,8 @@ class VideoReader:
752
713
  self.container.close()
753
714
 
754
715
 
716
+ # TODO: I think I'm not using this...
717
+ # Remove it please
755
718
  def audio_ts_for_video_t(
756
719
  t: float,
757
720
  video_fps: float,
@@ -15,9 +15,14 @@ frame we are requesting in the moment, keeping in
15
15
  memory all those frames to be handled fast. It
16
16
  will remove the old frames if needed to use only
17
17
  the 'size' we set when creating it.
18
+
19
+ A stream can have 'fps = 60' but use another
20
+ different time base that make the pts values go 0,
21
+ 256, 512... for example. The 'time_base' is the
22
+ only accurate way to obtain the pts.
18
23
  """
19
24
  from yta_video_opengl.utils import t_to_pts, pts_to_t, pts_to_index, index_to_pts
20
- from yta_video_frame_time import T
25
+ from yta_video_opengl.t import T
21
26
  from av.container import InputContainer
22
27
  from av.video.stream import VideoStream
23
28
  from av.audio.stream import AudioStream
@@ -25,14 +30,19 @@ from av.video.frame import VideoFrame
25
30
  from av.audio.frame import AudioFrame
26
31
  from yta_validation.parameter import ParameterValidator
27
32
  from yta_validation import PythonValidator
28
- from fractions import Fraction
33
+ from quicktions import Fraction
29
34
  from collections import OrderedDict
30
35
  from typing import Union
31
36
 
32
37
  import numpy as np
38
+ import av
33
39
  import math
34
40
 
35
41
 
42
+ # TODO: This is not actually a Video
43
+ # cache, is a FrameCache because we
44
+ # create one for video but another
45
+ # one for audio. Rename it please.
36
46
  class VideoFrameCache:
37
47
  """
38
48
  Class to manage the frames cache of a video
@@ -108,6 +118,7 @@ class VideoFrameCache:
108
118
  # use the amount of frames of the biggest
109
119
  # interval of frames that belongs to a key
110
120
  # frame, or a value by default
121
+ # TODO: Careful if this is too big
111
122
  fps = (
112
123
  float(self.stream.average_rate)
113
124
  if PythonValidator.is_instance_of(self.stream, VideoStream) else
@@ -116,7 +127,7 @@ class VideoFrameCache:
116
127
  # Intervals, but in number of frames
117
128
  intervals = np.diff(
118
129
  # Intervals of time between keyframes
119
- np.array(self.key_frames_pts) * self.stream.time_base
130
+ np.array(self.key_frames_pts) * self.time_base
120
131
  ) * fps
121
132
 
122
133
  self.size = (
@@ -131,7 +142,7 @@ class VideoFrameCache:
131
142
 
132
143
  self.container.seek(0)
133
144
 
134
- def _get_nearest_keyframe_fps(
145
+ def _get_nearest_keyframe_pts(
135
146
  self,
136
147
  pts: int
137
148
  ):
@@ -157,7 +168,6 @@ class VideoFrameCache:
157
168
  the cache if full.
158
169
  """
159
170
  if frame.pts not in self.cache:
160
- # TODO: The 'format' must be dynamic
161
171
  self.cache[frame.pts] = frame
162
172
 
163
173
  # Clean cache if full
@@ -185,10 +195,19 @@ class VideoFrameCache:
185
195
  return self.cache[pts]
186
196
 
187
197
  # Look for the most near key frame
188
- key_frame_pts = self._get_nearest_keyframe_fps(pts)
198
+ key_frame_pts = self._get_nearest_keyframe_pts(pts)
189
199
 
190
200
  # Go to the key frame that includes it
191
- self.container.seek(key_frame_pts, stream = self.stream)
201
+ # but I read that it is recommended to
202
+ # read ~100ms before the pts we want to
203
+ # actually read so we obtain the frames
204
+ # clean (this is important in audio)
205
+ # TODO: This code is repeated, refactor
206
+ pts_pad = int(0.1 / self.time_base)
207
+ self.container.seek(
208
+ offset = max(0, key_frame_pts - pts_pad),
209
+ stream = self.stream
210
+ )
192
211
 
193
212
  decoded = None
194
213
  for frame in self.container.decode(self.stream):
@@ -199,6 +218,15 @@ class VideoFrameCache:
199
218
  # Store in cache if needed
200
219
  self._store_frame_in_cache(frame)
201
220
 
221
+ """
222
+ The 'frame.pts * frame.time_base' will give
223
+ us the index of the frame, and actually the
224
+ 'pts' que are looking for seems to be the
225
+ index and not a pts.
226
+
227
+ TODO: Review all this in all the logic
228
+ please.
229
+ """
202
230
  if frame.pts >= pts:
203
231
  decoded = self.cache[frame.pts]
204
232
  break
@@ -207,6 +235,7 @@ class VideoFrameCache:
207
235
  # frames to be able to decode...
208
236
  return decoded
209
237
 
238
+ # TODO: I'm not using this method...
210
239
  def get_frame(
211
240
  self,
212
241
  index: int
@@ -226,24 +255,18 @@ class VideoFrameCache:
226
255
 
227
256
  def get_frame_from_t(
228
257
  self,
229
- t: float
258
+ t: Union[int, float, Fraction]
230
259
  ) -> Union[VideoFrame, AudioFrame]:
231
260
  """
232
261
  Get the frame with the given 't' time moment
233
262
  from the cache.
234
263
  """
235
- pts = t_to_pts(t, self.time_base)
236
-
237
- return (
238
- self.cache[pts]
239
- if pts in self.cache else
240
- self.get_frame_from_pts(pts)
241
- )
264
+ return self.get_frame_from_pts(T(t, self.time_base).truncated_pts)
242
265
 
243
266
  def get_frames(
244
267
  self,
245
- start: float = 0,
246
- end: Union[float, None] = None
268
+ start: Union[int, float, Fraction] = 0,
269
+ end: Union[int, float, Fraction, None] = None
247
270
  ):
248
271
  """
249
272
  Get all the frames in the range between
@@ -273,8 +296,7 @@ class VideoFrameCache:
273
296
  """
274
297
 
275
298
  # The 'duration' is on pts ticks
276
- duration = float(self.stream.duration * self.stream.time_base)
277
- print(f'duration of the whole stream: {str(duration)}s, asking for [{str(start)}, {str(end)})')
299
+ duration = float(self.stream.duration * self.time_base)
278
300
  # TODO: I think it would be better to
279
301
  # receive and work with pts instead of
280
302
  # 't' time moments...
@@ -292,16 +314,25 @@ class VideoFrameCache:
292
314
 
293
315
  # If not all, we ignore the cache because we
294
316
  # need to decode and they are all consecutive
295
- start = t_to_pts(start, self.time_base)
317
+ start = T(start, self.time_base).truncated_pts
296
318
  end = (
297
- t_to_pts(end, self.time_base)
319
+ T(end, self.time_base).truncated_pts
298
320
  if end is not None else
299
321
  None
300
322
  )
301
- key_frame_pts = self._get_nearest_keyframe_fps(start)
323
+ key_frame_pts = self._get_nearest_keyframe_pts(start)
302
324
 
303
- # Go to the nearest key frame to start decoding
304
- self.container.seek(key_frame_pts, stream = self.stream)
325
+ # Go to the key frame that includes it
326
+ # but I read that it is recommended to
327
+ # read ~100ms before the pts we want to
328
+ # actually read so we obtain the frames
329
+ # clean (this is important in audio)
330
+ # TODO: This code is repeated, refactor
331
+ pts_pad = int(0.1 / self.time_base)
332
+ self.container.seek(
333
+ offset = max(0, key_frame_pts - pts_pad),
334
+ stream = self.stream
335
+ )
305
336
 
306
337
  for packet in self.container.demux(self.stream):
307
338
  for frame in packet.decode():
@@ -311,11 +342,9 @@ class VideoFrameCache:
311
342
  # We store all the frames in cache
312
343
  self._store_frame_in_cache(frame)
313
344
 
314
- print(frame)
315
345
  frame_end_pts = frame.pts + int(frame.samples * (1 / self.stream.sample_rate) / self.time_base)
316
346
  #frame_end_pts = frame.pts + int(frame.samples)
317
347
  #frame_end_pts = frame.pts + int(frame.samples / (self.stream.sample_rate * self.time_base))
318
- print(f' Frame from [{str(frame.pts)}, {str(frame_end_pts)}] and looking for [{str(start)}, {str(end)}]')
319
348
 
320
349
  # For the next comments imagine we are looking
321
350
  # for the [1.0, 2.0) audio time range
@@ -354,7 +383,7 @@ class VideoFrameCache:
354
383
  # From 0.5 to 2.5 => take 1.0 to 2.0
355
384
  end
356
385
  )
357
- print('A part at the end is included.')
386
+ #print('A part at the end is included.')
358
387
  # TODO: I'm using too much 'pts_to_t'
359
388
  frame = trim_audio_frame_pts(
360
389
  frame = frame,
@@ -374,7 +403,7 @@ class VideoFrameCache:
374
403
  end
375
404
  )
376
405
  # A part at the begining is included
377
- print('A part at the begining is included.')
406
+ #print('A part at the begining is included.')
378
407
  # TODO: I'm using too much 'pts_to_t'
379
408
  frame = trim_audio_frame_pts(
380
409
  frame = frame,
@@ -404,14 +433,7 @@ class VideoFrameCache:
404
433
  return self
405
434
 
406
435
 
407
-
408
- import av
409
- import numpy as np
410
-
411
- import av
412
-
413
-
414
-
436
+ # TODO: Move this to a utils when refactored
415
437
  def trim_audio_frame_pts(
416
438
  frame: av.AudioFrame,
417
439
  start_pts: int,
@@ -444,12 +466,12 @@ def trim_audio_frame_pts(
444
466
  start_idx = int(cut_start_time * sr)
445
467
  end_idx = int(cut_end_time * sr)
446
468
 
447
- print(
448
- f"cutting [{frame.pts}, {frame_end_pts}] "
449
- f"to [{cut_start_pts}, {cut_end_pts}] "
450
- f"({start_idx}:{end_idx} / {frame.samples})"
451
- #f"({start_idx}:{end_idx} / {n_samples})"
452
- )
469
+ # print(
470
+ # f"cutting [{frame.pts}, {frame_end_pts}] "
471
+ # f"to [{cut_start_pts}, {cut_end_pts}] "
472
+ # f"({start_idx}:{end_idx} / {frame.samples})"
473
+ # #f"({start_idx}:{end_idx} / {n_samples})"
474
+ # )
453
475
 
454
476
  cut_samples = samples[:, start_idx:end_idx]
455
477
 
@@ -492,7 +514,7 @@ def trim_audio_frame_t(
492
514
  start_idx = int((cut_start - frame_start) * sr)
493
515
  end_idx = int((cut_end - frame_start) * sr)
494
516
 
495
- print(f'cutting [{str(frame_start)}, {str(frame_end)}] to [{str(float(start_time))}, {str(float(end_time))}] from {str(start_idx)} to {str(end_idx)} of {str(int((frame_end - frame_start) * sr))}')
517
+ # print(f'cutting [{str(frame_start)}, {str(frame_end)}] to [{str(float(start_time))}, {str(float(end_time))}] from {str(start_idx)} to {str(end_idx)} of {str(int((frame_end - frame_start) * sr))}')
496
518
  cut_samples = samples[:, start_idx:end_idx]
497
519
 
498
520
  # crear nuevo AudioFrame
yta_video_opengl/t.py ADDED
@@ -0,0 +1,185 @@
1
+ from yta_validation.parameter import ParameterValidator
2
+ from yta_validation import PythonValidator
3
+ from yta_validation.number import NumberValidator
4
+ from quicktions import Fraction
5
+ from typing import Union
6
+
7
+
8
+ class T:
9
+ """
10
+ Class to simplify the way we work with a
11
+ 't' time moment but using the fractions
12
+ library to be precise and avoid any issue
13
+ related with commas.
14
+
15
+ This class must be used when trying to
16
+ apply a specific 't' time moment for a
17
+ video or audio frame, using the fps or
18
+ sample rate as time_base to be precise.
19
+ """
20
+
21
+ @property
22
+ def truncated(
23
+ self
24
+ ) -> Fraction:
25
+ """
26
+ The 't' but as a Fraction that is multiple
27
+ of the given 'time_base' and truncated.
28
+ """
29
+ return round_t(self._t, self.time_base)
30
+
31
+ @property
32
+ def rounded(
33
+ self
34
+ ) -> Fraction:
35
+ """
36
+ The 't' but as a Fraction that is multiple
37
+ of the given 'time_base' and rounded (the
38
+ value could be the same as truncated if it
39
+ is closer to the previou value).
40
+ """
41
+ return round_t(self._t, self.time_base, do_truncate = False)
42
+
43
+ @property
44
+ def truncated_pts(
45
+ self
46
+ ) -> int:
47
+ """
48
+ The 'truncated' value but as a pts, which
49
+ is the int value to be set in audio and
50
+ video frames in the pyav library to be
51
+ displayed in that moment.
52
+ """
53
+ return int(self.truncated / self.time_base)
54
+
55
+ @property
56
+ def rounded_pts(
57
+ self
58
+ ) -> int:
59
+ """
60
+ The 'rounded' value but as a pts, which
61
+ is the int value to be set in audio and
62
+ video frames in the pyav library to be
63
+ displayed in that moment.
64
+ """
65
+ return int(self.rounded / self.time_base)
66
+
67
+ def __init__(
68
+ self,
69
+ t: Union[int, float, Fraction],
70
+ time_base: Fraction
71
+ ):
72
+ ParameterValidator.validate_mandatory_instance_of('t', t, [int, float, 'Fraction'])
73
+ ParameterValidator.validate_mandatory_instance_of('time_base', time_base, 'Fraction')
74
+
75
+ self._t: Union[int, float, Fraction] = t
76
+ """
77
+ The 't' time moment as it was passed as
78
+ parameter.
79
+ """
80
+ self.time_base: Fraction = time_base
81
+ """
82
+ The time_base that will used to round the
83
+ values to be multiples of it.
84
+ """
85
+
86
+ def next(
87
+ self,
88
+ n: int = 1
89
+ ) -> 'T':
90
+ """
91
+ Get the value that is 'n' times ahead of
92
+ the 'truncated' property of this instance.
93
+
94
+ Useful when you need the next value for a
95
+ range in an iteration or similar.
96
+ """
97
+ return T(self.truncated + n * self.time_base, self.time_base)
98
+
99
+ # TODO: Maybe its better to make the '__init__'
100
+ # receive the fps and create the 'from_time_base'
101
+ # because I think we will provide the fps or the
102
+ # sample rate more often
103
+ @staticmethod
104
+ def from_fps(
105
+ t: Union[int, float, Fraction],
106
+ fps: Union[int, float, Fraction]
107
+ ):
108
+ """
109
+ Get the instance but providing the 'fps'
110
+ (or sample rate) value directly.
111
+ """
112
+ return T(t, fps_to_time_base(fps))
113
+
114
+ def get_ts(
115
+ start: Union[int, float, Fraction],
116
+ end: Union[int, float, Fraction],
117
+ fps: Fraction
118
+ ) -> list[Fraction]:
119
+ """
120
+ Get all the 't' time moments between the given
121
+ 'start' and the given 'end', using the provided
122
+ 'time_base' for precision.
123
+
124
+ The 'end' is not included, we return a range
125
+ [start, end) because the last frame is the
126
+ start of another time range.
127
+ """
128
+ start = T.from_fps(start, fps).truncated
129
+ end = T.from_fps(end, fps).truncated
130
+
131
+ time_base = fps_to_time_base(fps)
132
+ return [
133
+ start + i * time_base
134
+ for i in range((end - start) // time_base)
135
+ ]
136
+
137
+ def round_t(
138
+ t: Union[int, float, Fraction],
139
+ time_base = Fraction(1, 60),
140
+ do_truncate: bool = True
141
+ ):
142
+ """
143
+ Round the given 't' time moment to the most
144
+ near multiple of the given 'time_base' (or
145
+ the previous one if 'do_truncate' is True)
146
+ using fractions module to be precise.
147
+
148
+ This method is very useful to truncate 't'
149
+ time moments in order to get the frames or
150
+ samples for the specific and exact time
151
+ moments according to their fps or sample
152
+ rate (that should be passed as the
153
+ 'time_base' parameter).
154
+
155
+ Examples below, with `time_base = 1/5`:
156
+ - `t = 0.25` => `0.2` (truncated or rounded)
157
+ - `t = 0.35` => `0.2` (truncated)
158
+ - `t = 0.45` => `0.4` (truncated or rounded)
159
+ - `t = 0.55` => `0.6` (rounded)
160
+ """
161
+ t = Fraction(t).limit_denominator()
162
+ steps = t / time_base
163
+
164
+ snapped_steps = (
165
+ steps.numerator // steps.denominator
166
+ if do_truncate else
167
+ round(steps) # round(float(steps))
168
+ )
169
+
170
+ return snapped_steps * time_base
171
+
172
+ def fps_to_time_base(
173
+ fps: Union[int, float, Fraction]
174
+ ) -> Fraction:
175
+ """
176
+ Get the pyav time base from the given
177
+ 'fps'.
178
+ """
179
+ return (
180
+ Fraction(1, fps)
181
+ if NumberValidator.is_int(fps) else
182
+ Fraction(1, 1) / fps
183
+ if PythonValidator.is_instance_of(fps, 'Fraction') else
184
+ Fraction(1, 1) / Fraction.from_float(fps).limit_denominator(1000000) # if float
185
+ )
yta_video_opengl/tests.py CHANGED
@@ -586,10 +586,12 @@ def video_modified_stored():
586
586
 
587
587
  video = Video(VIDEO_PATH, 0.25, 0.75)
588
588
  timeline = Timeline()
589
- timeline.add_video(Video(VIDEO_PATH, 0.25, 0.75), 0.5)
589
+ timeline.add_video(Video(VIDEO_PATH, 0.25, 1.0), 0.5)
590
590
  # This is successfully raising an exception
591
591
  #timeline.add_video(Video(VIDEO_PATH, 0.25, 0.75), 0.6)
592
- timeline.add_video(Video(VIDEO_PATH, 0.25, 0.75), 1.5)
592
+ timeline.add_video(Video(VIDEO_PATH, 0.25, 0.75), 1.75)
593
+ timeline.add_video(Video('C:/Users/dania/Downloads/Y2meta.app-TOP 12 SIMPLE LIQUID TRANSITION _ GREEN SCREEN TRANSITION PACK-(1080p60).mp4', 4.0, 5.0), 3)
594
+ # timeline.add_video(Video('C:/Users/dania/Downloads/Y2meta.app-10 Smooth Transitions Green Screen Template For Kinemaster, Alight Motion, Filmora, premiere pro-(1080p).mp4', 2.25, 3.0), 3)
593
595
  timeline.render(OUTPUT_PATH)
594
596
 
595
597
  return