yta-video-opengl 0.0.18__py3-none-any.whl → 0.0.20__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: yta-video-opengl
3
- Version: 0.0.18
3
+ Version: 0.0.20
4
4
  Summary: Youtube Autonomous Video OpenGL Module
5
5
  Author: danialcala94
6
6
  Author-email: danielalcalavalera@gmail.com
@@ -1,27 +1,30 @@
1
1
  yta_video_opengl/__init__.py,sha256=ycAx_XYMVDfkuObSvtW6irQ0Wo-fgxEz3fjIRMe8PpY,205
2
+ yta_video_opengl/audio.py,sha256=YePF1025CgK335bc6qwzPzqvZ56TJ4aZH86ElyA08s8,6797
2
3
  yta_video_opengl/classes.py,sha256=t5-Tfc7ecvHl8JlVBp_FVzZT6ole6Ly5-FeBBH7wcxo,37742
3
4
  yta_video_opengl/complete/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
5
  yta_video_opengl/complete/frame_combinator.py,sha256=uYg7907knjBlmZUZCCzkxDcj0Nown0muvL5PNVS707A,9413
5
6
  yta_video_opengl/complete/frame_generator.py,sha256=VRcPgpqfxQWMeLzgEJObbM0xu7_85I1y_YyQVhcEswc,7853
6
7
  yta_video_opengl/complete/frame_wrapper.py,sha256=g0aTcUVmF5uQtxs95_XsxlwL0QUj-fNOSRHvK4ENqg4,3347
7
- yta_video_opengl/complete/timeline.py,sha256=haUTJoGv15Xqt0G1E52St_PmYrzoqwPF_k88FWBIfyA,16188
8
- yta_video_opengl/complete/track.py,sha256=kLd8iUUPKVbCvk0nRnL630lagjh-8QengcZU65xa21c,15706
9
- yta_video_opengl/complete/video_on_track.py,sha256=laxDvMr1rrmnDfHpk825j42f4pj9I1X8vOFmzwteuM8,4824
8
+ yta_video_opengl/complete/timeline.py,sha256=fri10UpBjsy7QcGdBtSBuqU0eor5faSUyGc6krrBuQw,16877
9
+ yta_video_opengl/complete/track/__init__.py,sha256=E89IQmj6VF-3VGaD34oQbzIMkGEI9ArsgqC76XZ374o,14216
10
+ yta_video_opengl/complete/track/media/__init__.py,sha256=raIbTh5kreFJcnrtxUE1s8Un0N614KzWDWUkS3-OglY,6368
11
+ yta_video_opengl/complete/track/parts.py,sha256=tqUtCdC0WLXAksReX0-77AaH1ywC_nrs4yOdRiWyO4A,7876
12
+ yta_video_opengl/complete/track/utils.py,sha256=nKJT0GqfSnUoATPGCAXinIM9skhtH6v9_MsBZlHYNeg,2486
10
13
  yta_video_opengl/nodes/__init__.py,sha256=TZ-ZO05PZ0_ABq675E22_PngLWOe-_w5s1cLlV3NbWM,3469
11
14
  yta_video_opengl/nodes/audio/__init__.py,sha256=4nKkC70k1UgLcCSPqFWm3cKdaJM0KUmQTwGWv1xFarQ,2926
12
15
  yta_video_opengl/nodes/video/__init__.py,sha256=gSoaoEmjdQmyRwH18mf5z3NAhap3S0RgbeBbfBXi4jc,132
13
16
  yta_video_opengl/nodes/video/opengl.py,sha256=K2pyCJEd9z4gnZqJetKyGPbtHuBzFsx74ZYyzhSqYPo,8510
14
- yta_video_opengl/reader/__init__.py,sha256=kKvOAEeDjIwAaWtpDEQHdAd_Gwk3Ssz2tv6gpNwVkQo,19644
17
+ yta_video_opengl/reader/__init__.py,sha256=fZVb4mwVz9Bb5pawuFXIS-LGPXOLk-9xznAGMoivqTA,19216
15
18
  yta_video_opengl/reader/cache/__init__.py,sha256=PAfGM2J-8Vv6p6Cd9aAUvyBcw3rjx2gy_2pJO22VtDM,7020
16
19
  yta_video_opengl/reader/cache/audio.py,sha256=cm_1D5f5RnmJgaidA1pnEhTPF8DE0mU2MofmwjU_b5k,6781
17
- yta_video_opengl/reader/cache/utils.py,sha256=9aJ6qyUFRvoh2jRbIvtF_-1MOm_sgQtPiy0WXLCZYcA,1402
20
+ yta_video_opengl/reader/cache/utils.py,sha256=a3aeiQ8LJpAFvPeoGEk1cn88NZ6c4Eveka7bTP-58VY,1409
18
21
  yta_video_opengl/reader/cache/video.py,sha256=3sT9cE0sdTty5AE9yFAPJrJNxCX5vWVATK8OeJInr8I,3496
19
22
  yta_video_opengl/t.py,sha256=xOhT1xBEwChlXf-Tuy-WxA_08iRJWVlnL_Hyzr-9-sk,6633
20
- yta_video_opengl/tests.py,sha256=6s5x-RReIZ38d1c4gB7aMoDLHLrC0LWEttOYyixhUV0,27838
23
+ yta_video_opengl/tests.py,sha256=eyFnz7yBDJyIoti-cV7Dz1bMTeF61Z4_JrFkLXuZQl4,28019
21
24
  yta_video_opengl/utils.py,sha256=yUi17EjNR4SVpvdDUwUaKl4mBCb1uyFCSGoIX3Zr2F0,15586
22
- yta_video_opengl/video.py,sha256=Fgu_BzuDlMbfl1Hwjk8Yzo3ZxO73wPuyTUjTbf9OSLw,8951
25
+ yta_video_opengl/video.py,sha256=Og_SOJwb8Dzbx8c-P75cjT9O8QgITru-4LD5wHC_JDM,8785
23
26
  yta_video_opengl/writer.py,sha256=QwvjQcEkzn1WAVqVTFiI6tYIXJO67LKKUTJGO_eflFM,8893
24
- yta_video_opengl-0.0.18.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
25
- yta_video_opengl-0.0.18.dist-info/METADATA,sha256=3sGbbiucD3tIj8QtHNmXKfEK8JW6ZjBWo09xKXmBplY,714
26
- yta_video_opengl-0.0.18.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
27
- yta_video_opengl-0.0.18.dist-info/RECORD,,
27
+ yta_video_opengl-0.0.20.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
28
+ yta_video_opengl-0.0.20.dist-info/METADATA,sha256=j0mtfYaCzxG68PFO5fPPn96raM2sT5wIhZ8dKlI2Beg,714
29
+ yta_video_opengl-0.0.20.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
30
+ yta_video_opengl-0.0.20.dist-info/RECORD,,
@@ -1,467 +0,0 @@
1
- from yta_video_opengl.complete.video_on_track import VideoOnTrack
2
- from yta_video_opengl.video import Video
3
- from yta_video_opengl.t import T
4
- from yta_video_opengl.complete.frame_wrapper import VideoFrameWrapped
5
- from yta_video_opengl.utils import audio_frames_and_remainder_per_video_frame
6
- from yta_video_opengl.t import fps_to_time_base
7
- from yta_video_opengl.complete.frame_wrapper import AudioFrameWrapped
8
- from yta_video_opengl.complete.frame_generator import VideoFrameGenerator, AudioFrameGenerator
9
- from yta_validation.parameter import ParameterValidator
10
- from quicktions import Fraction
11
- from typing import Union
12
-
13
-
14
- NON_LIMITED_EMPTY_PART_END = 999
15
- """
16
- A value to indicate that the empty part
17
- has no end because it is in the last
18
- position and there is no video after it.
19
- """
20
- class _Part:
21
- """
22
- Class to represent an element that is on the
23
- track, that can be an empty space or a video
24
- (with audio).
25
- """
26
-
27
- @property
28
- def is_empty_part(
29
- self
30
- ) -> bool:
31
- """
32
- Flag to indicate if the part is an empty part,
33
- which means that there is no video associated
34
- but an empty space.
35
- """
36
- return self.video is None
37
-
38
- def __init__(
39
- self,
40
- track: 'Track',
41
- start: Union[int, float, Fraction],
42
- end: Union[int, float, Fraction],
43
- video: Union[VideoOnTrack, None] = None
44
- ):
45
- ParameterValidator.validate_mandatory_positive_number('start', start, do_include_zero = True)
46
- ParameterValidator.validate_mandatory_positive_number('end', end, do_include_zero = False)
47
- ParameterValidator.validate_instance_of('video', video, VideoOnTrack)
48
-
49
- self._track: Track = track
50
- """
51
- The instance of the track this part belongs
52
- to.
53
- """
54
- # TODO: I would like to avoid this 2 instances
55
- # here, and I think I've done it with static
56
- # properties in other project, but as I don't
57
- # remember how and where by now, here it is...
58
- self._video_frame_generator: VideoFrameGenerator = VideoFrameGenerator()
59
- """
60
- Useful internal tool to generate background
61
- frames for the empty parts.
62
- """
63
- self._audio_frame_generator: AudioFrameGenerator = AudioFrameGenerator()
64
- """
65
- Useful internal tool to generate silent
66
- audio frames for the empty parts.
67
- """
68
- self.start: Fraction = Fraction(start)
69
- """
70
- The start 't' time moment of the part.
71
- """
72
- self.end: Fraction = Fraction(end)
73
- """
74
- The end 't' time moment of the part.
75
- """
76
- self.video: Union[VideoOnTrack, None] = video
77
- """
78
- The video associated, if existing, or
79
- None if it is an empty space that we need
80
- to fulfill with a black background and
81
- silent audio.
82
- """
83
-
84
- def get_frame_at(
85
- self,
86
- t: Union[int, float, Fraction]
87
- ) -> 'VideoFrameWrapped':
88
- """
89
- Get the frame that must be displayed at
90
- the given 't' time moment.
91
- """
92
- frame = (
93
- # TODO: What about the 'format' (?)
94
- # TODO: Maybe I shouldn't set the 'time_base'
95
- # here and do it just in the Timeline 'render'
96
- #return get_black_background_video_frame(self._track.size)
97
- # TODO: This 'time_base' maybe has to be related
98
- # to a Timeline general 'time_base' and not the fps
99
- VideoFrameWrapped(
100
- frame = self._video_frame_generator.background.full_black(
101
- size = self._track.size,
102
- time_base = fps_to_time_base(self._track.fps)
103
- ),
104
- is_from_empty_part = True
105
- )
106
- if self.is_empty_part else
107
- VideoFrameWrapped(
108
- frame = self.video.get_frame_at(t),
109
- is_from_empty_part = False
110
- )
111
-
112
- )
113
-
114
- # TODO: This should not happen because of
115
- # the way we handle the videos here but the
116
- # video could send us a None frame here, so
117
- # do we raise exception (?)
118
- if frame._frame is None:
119
- #frame = get_black_background_video_frame(self._track.size)
120
- # TODO: By now I'm raising exception to check if
121
- # this happens or not because I think it would
122
- # be malfunctioning
123
- raise Exception(f'Video is returning None video frame at t={str(t)}.')
124
-
125
- return frame
126
-
127
- def get_audio_frames_at(
128
- self,
129
- t: Union[int, float, Fraction]
130
- ):
131
- """
132
- Iterate over all the audio frames that
133
- exist at the time moment 't' provided.
134
- """
135
- if not self.is_empty_part:
136
- for frame in self.video.get_audio_frames_at(t):
137
- yield AudioFrameWrapped(
138
- frame = frame,
139
- is_from_empty_part = False
140
- )
141
- else:
142
- # TODO: Transform this below to a utils in
143
- # which I obtain the array directly
144
- # Check many full and partial silent frames we need
145
- number_of_frames, number_of_remaining_samples = audio_frames_and_remainder_per_video_frame(
146
- video_fps = self._track.fps,
147
- sample_rate = self._track.audio_fps,
148
- number_of_samples_per_audio_frame = self._track.audio_samples_per_frame
149
- )
150
-
151
- # TODO: I need to set the pts, but here (?)
152
- # The complete silent frames we need
153
- silent_frame = self._audio_frame_generator.silent(
154
- sample_rate = self._track.audio_fps,
155
- # TODO: Check where do we get this value from
156
- layout = 'stereo',
157
- number_of_samples = self._track.audio_samples_per_frame,
158
- # TODO: Check where do we get this value from
159
- format = 'fltp',
160
- pts = None,
161
- time_base = None
162
- )
163
-
164
- frames = (
165
- [
166
- AudioFrameWrapped(
167
- frame = silent_frame,
168
- is_from_empty_part = True
169
- )
170
- ] * number_of_frames
171
- if number_of_frames > 0 else
172
- []
173
- )
174
-
175
- # The remaining partial silent frames we need
176
- if number_of_remaining_samples > 0:
177
- silent_frame = self._audio_frame_generator.silent(
178
- sample_rate = self._track.audio_fps,
179
- # TODO: Check where do we get this value from
180
- layout = 'stereo',
181
- number_of_samples = number_of_remaining_samples,
182
- # TODO: Check where do we get this value from
183
- format = 'fltp',
184
- pts = None,
185
- time_base = None
186
- )
187
-
188
- frames.append(
189
- AudioFrameWrapped(
190
- frame = silent_frame,
191
- is_from_empty_part = True
192
- )
193
- )
194
-
195
- for frame in frames:
196
- yield frame
197
-
198
- # TODO: I don't like using t as float,
199
- # we need to implement fractions.Fraction
200
- # TODO: This is called Track but it is
201
- # handling videos only. Should I have
202
- # VideoTrack and AudioTrack (?)
203
- class Track:
204
- """
205
- Class to represent a track in which we place
206
- videos, images and audio to build a video
207
- project.
208
- """
209
-
210
- @property
211
- def parts(
212
- self
213
- ) -> list[_Part]:
214
- """
215
- The list of parts that build this track,
216
- but with the empty parts detected to
217
- be fulfilled with black frames and silent
218
- audios.
219
-
220
- A part can be a video or an empty space.
221
- """
222
- if (
223
- not hasattr(self, '_parts') or
224
- self._parts is None
225
- ):
226
- self._recalculate_parts()
227
-
228
- return self._parts
229
-
230
- @property
231
- def end(
232
- self
233
- ) -> Fraction:
234
- """
235
- The end of the last video of this track,
236
- which is also the end of the track. This
237
- is the last time moment that has to be
238
- rendered.
239
- """
240
- return Fraction(
241
- 0.0
242
- if len(self.videos) == 0 else
243
- max(
244
- video.end
245
- for video in self.videos
246
- )
247
- )
248
-
249
- @property
250
- def videos(
251
- self
252
- ) -> list[VideoOnTrack]:
253
- """
254
- The list of videos we have in the track
255
- but ordered using the 'start' attribute
256
- from first to last.
257
- """
258
- return sorted(self._videos, key = lambda video: video.start)
259
-
260
- def __init__(
261
- self,
262
- # TODO: I need the general settings of the
263
- # project to be able to make audio also, not
264
- # only the empty frames
265
- size: tuple[int, int],
266
- fps: float,
267
- audio_fps: float,
268
- # TODO: Where does it come from (?)
269
- audio_samples_per_frame: int
270
- ):
271
- self._videos: list[VideoOnTrack] = []
272
- """
273
- The list of 'VideoOnTrack' instances that
274
- must play on this track.
275
- """
276
- self.size: tuple[int, int] = size
277
- """
278
- The size of the videos of this track.
279
- """
280
- self.fps: float = float(fps)
281
- """
282
- The fps of the track, needed to calculate
283
- the base t time moments to be precise and
284
- to obtain or generate the frames.
285
- """
286
- self.audio_fps: float = float(audio_fps)
287
- """
288
- The fps of the audio track, needed to
289
- generate silent audios for the empty parts.
290
- """
291
- self.audio_samples_per_frame: int = audio_samples_per_frame
292
- """
293
- The number of samples per audio frame.
294
- """
295
-
296
- def _is_free(
297
- self,
298
- start: Union[int, float, Fraction],
299
- end: Union[int, float, Fraction]
300
- ) -> bool:
301
- """
302
- Check if the time range in between the
303
- 'start' and 'end' time given is free or
304
- there is some video playing at any moment.
305
- """
306
- return not any(
307
- (
308
- video.video.start < end and
309
- video.video.end > start
310
- )
311
- for video in self.videos
312
- )
313
-
314
- def _get_part_at_t(
315
- self,
316
- t: Union[int, float, Fraction]
317
- ) -> _Part:
318
- """
319
- Get the part at the given 't' time
320
- moment, that will always exist because
321
- we have an special non ended last
322
- empty part that would be returned if
323
- accessing to an empty 't'.
324
- """
325
- for part in self.parts:
326
- if part.start <= t < part.end:
327
- return part
328
-
329
- # TODO: This will only happen if they are
330
- # asking for a value greater than the
331
- # NON_LIMITED_EMPTY_PART_END...
332
- raise Exception('NON_LIMITED_EMPTY_PART_END exceeded.')
333
- return None
334
-
335
- def get_frame_at(
336
- self,
337
- t: Union[int, float, Fraction]
338
- ) -> 'VideoFrameWrapped':
339
- """
340
- Get the frame that must be displayed at
341
- the 't' time moment provided, which is
342
- a frame from the video audio that is
343
- being played at that time moment.
344
-
345
- Remember, this 't' time moment provided
346
- is about the track, and we make the
347
- conversion to the actual video 't' to
348
- get the frame.
349
- """
350
- # TODO: What if the frame, that comes from
351
- # a video, doesn't have the expected size (?)
352
- return self._get_part_at_t(t).get_frame_at(t)
353
-
354
- # TODO: This is not working well...
355
- def get_audio_frames_at(
356
- self,
357
- t: Union[int, float, Fraction]
358
- ):
359
- """
360
- Get the sequence of audio frames that
361
- must be displayed at the 't' time
362
- moment provided, which the collection
363
- of audio frames corresponding to the
364
- video frame that is being played at
365
- that time moment.
366
-
367
- Remember, this 't' time moment provided
368
- is about the track, and we make the
369
- conversion to the actual video 't' to
370
- get the frame.
371
-
372
- This is useful when we want to write a
373
- video frame with its audio, so we obtain
374
- all the audio frames associated to it
375
- (remember that a video frame is associated
376
- with more than 1 audio frame).
377
- """
378
- for frame in self._get_part_at_t(t).get_audio_frames_at(t):
379
- yield frame
380
-
381
- def add_video(
382
- self,
383
- video: Video,
384
- t: Union[int, float, Fraction, None] = None
385
- ) -> 'Track':
386
- """
387
- Add the 'video' provided to the track. If
388
- a 't' time moment is provided, the video
389
- will be added to that time moment if
390
- possible. If there is no other video
391
- placed in the time gap between the given
392
- 't' and the provided 'video' duration, it
393
- will be added succesfully. In the other
394
- case, an exception will be raised.
395
-
396
- If 't' is None, the first available 't'
397
- time moment will be used, that will be 0.0
398
- if no video, or the end of the last video.
399
- """
400
- ParameterValidator.validate_mandatory_instance_of('video', video, Video)
401
- ParameterValidator.validate_positive_number('t', t, do_include_zero = True)
402
-
403
- if t is not None:
404
- # TODO: We can have many different strategies
405
- # that we could define in the '__init__' maybe
406
- t: T = T.from_fps(t, self.fps)
407
- if not self._is_free(t.truncated, t.next(1).truncated):
408
- raise Exception('The video cannot be added at the "t" time moment, something blocks it.')
409
- t = t.truncated
410
- else:
411
- t = self.end
412
-
413
- self._videos.append(VideoOnTrack(
414
- video,
415
- t
416
- ))
417
-
418
- self._recalculate_parts()
419
-
420
- # TODO: Maybe return the VideoOnTrack instead (?)
421
- return self
422
-
423
- def _recalculate_parts(
424
- self
425
- ) -> 'Track':
426
- """
427
- Check the track and get all the parts. A
428
- part can be empty (non video nor audio on
429
- that time period, which means black
430
- background and silence audio), or a video
431
- with (or without) audio.
432
- """
433
- parts = []
434
- cursor = 0.0
435
-
436
- for video in self.videos:
437
- # Empty space between cursor and start of
438
- # the next clip
439
- if video.start > cursor:
440
- parts.append(_Part(
441
- track = self,
442
- start = cursor,
443
- end = video.start,
444
- video = None
445
- ))
446
-
447
- # The video itself
448
- parts.append(_Part(
449
- track = self,
450
- start = video.start,
451
- end = video.end,
452
- video = video
453
- ))
454
-
455
- cursor = video.end
456
-
457
- # Add the non limited last empty part
458
- parts.append(_Part(
459
- track = self,
460
- start = cursor,
461
- end = NON_LIMITED_EMPTY_PART_END,
462
- video = None
463
- ))
464
-
465
- self._parts = parts
466
-
467
- return self