yta-video-opengl 0.0.23__py3-none-any.whl → 0.0.24__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.
- yta_video_opengl/__init__.py +2 -3
- yta_video_opengl/editor.py +333 -0
- yta_video_opengl/nodes/__init__.py +31 -27
- yta_video_opengl/nodes/audio/__init__.py +164 -55
- yta_video_opengl/nodes/video/__init__.py +27 -1
- yta_video_opengl/nodes/video/{opengl.py → opengl/__init__.py} +8 -4
- yta_video_opengl/nodes/video/opengl/experimental.py +760 -0
- yta_video_opengl/tests.py +201 -197
- {yta_video_opengl-0.0.23.dist-info → yta_video_opengl-0.0.24.dist-info}/METADATA +2 -1
- yta_video_opengl-0.0.24.dist-info/RECORD +13 -0
- yta_video_opengl/classes.py +0 -1276
- yta_video_opengl-0.0.23.dist-info/RECORD +0 -12
- {yta_video_opengl-0.0.23.dist-info → yta_video_opengl-0.0.24.dist-info}/LICENSE +0 -0
- {yta_video_opengl-0.0.23.dist-info → yta_video_opengl-0.0.24.dist-info}/WHEEL +0 -0
yta_video_opengl/tests.py
CHANGED
@@ -565,204 +565,208 @@ NUMPY_FORMAT = 'rgb24'
|
|
565
565
|
# print(f'Saved as "{self.output_filename}".')
|
566
566
|
|
567
567
|
|
568
|
-
|
569
|
-
#
|
570
|
-
#
|
571
|
-
#
|
572
|
-
#
|
573
|
-
#
|
574
|
-
#
|
575
|
-
|
576
|
-
#
|
577
|
-
#
|
578
|
-
|
579
|
-
#
|
580
|
-
#
|
581
|
-
|
582
|
-
#
|
583
|
-
|
584
|
-
#
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
#
|
592
|
-
|
593
|
-
#
|
594
|
-
#
|
595
|
-
#
|
596
|
-
#
|
568
|
+
def video_modified_stored():
|
569
|
+
# This path below was trimmed in an online platform
|
570
|
+
# and seems to be bad codified and generates error
|
571
|
+
# when processing it, but it is readable in the
|
572
|
+
# file explorer...
|
573
|
+
#VIDEO_PATH = 'test_files/test_1_short_broken.mp4'
|
574
|
+
# This is short but is working well
|
575
|
+
VIDEO_PATH = "test_files/test_1_short_2.mp4"
|
576
|
+
# Long version below, comment to test faster
|
577
|
+
#VIDEO_PATH = "test_files/test_1.mp4"
|
578
|
+
OUTPUT_PATH = "test_files/output.mp4"
|
579
|
+
# TODO: This has to be dynamic, but
|
580
|
+
# according to what (?)
|
581
|
+
NUMPY_FORMAT = 'rgb24'
|
582
|
+
# TODO: Where do we obtain this from (?)
|
583
|
+
VIDEO_CODEC_NAME = 'libx264'
|
584
|
+
# TODO: Where do we obtain this from (?)
|
585
|
+
PIXEL_FORMAT = 'yuv420p'
|
586
|
+
|
587
|
+
from yta_video_opengl.utils import texture_to_frame, frame_to_texture
|
588
|
+
|
589
|
+
#from yta_video_pyav.video import Video
|
590
|
+
|
591
|
+
#video = Video(VIDEO_PATH)
|
592
|
+
|
593
|
+
#effect = WavingFrame(size = video.size)
|
594
|
+
#effect = BreathingFrame(size = video.size)
|
595
|
+
#effect = HandheldFrame(size = video.size)
|
596
|
+
# effect = OrbitingFrame(
|
597
|
+
# size = video.size,
|
598
|
+
# first_frame = video.next_frame
|
599
|
+
# )
|
600
|
+
# effect = RotatingInCenterFrame(
|
601
|
+
# size = video.size,
|
602
|
+
# first_frame = video.next_frame
|
603
|
+
# )
|
604
|
+
|
605
|
+
# effect = GlitchRgbFrame(
|
606
|
+
# size = video.size,
|
607
|
+
# first_frame = video.next_frame
|
608
|
+
# )
|
609
|
+
from yta_video_opengl.editor import OpenglEditor
|
610
|
+
|
611
|
+
editor = OpenglEditor()
|
612
|
+
# waving_node_effect = editor.effects.video.waving_node(video.size, amplitude = 0.2, frequency = 9, speed = 3)
|
613
|
+
# chorus_effect = editor.effects.audio.chorus(audio.sample_rate)
|
614
|
+
# print(waving_node_effect)
|
597
615
|
|
598
|
-
#
|
599
|
-
#
|
600
|
-
#
|
601
|
-
#
|
602
|
-
#
|
603
|
-
#
|
604
|
-
#
|
605
|
-
#
|
606
|
-
#
|
607
|
-
#
|
608
|
-
#
|
609
|
-
|
610
|
-
#
|
611
|
-
#
|
612
|
-
#
|
613
|
-
#
|
616
|
+
# New way, with nodes
|
617
|
+
# context = moderngl.create_context(standalone = True)
|
618
|
+
# node = WavingNode(context, video.size, amplitude = 0.2, frequency = 9, speed = 3)
|
619
|
+
# print(node.process(video.get_frame_from_t(0)))
|
620
|
+
# We need to reset it to being again pointing
|
621
|
+
# to the first frame...
|
622
|
+
# TODO: Improve this by, maybe, storing the first
|
623
|
+
# frame in memory so we can append it later, or
|
624
|
+
# using the '.seek(0)' even when it could be not
|
625
|
+
# accurate
|
626
|
+
#video.reset()
|
627
|
+
|
628
|
+
# # TODO: By now this is applying an effect
|
629
|
+
# # by default
|
630
|
+
# VideoProcessor(
|
631
|
+
# filename = VIDEO_PATH,
|
632
|
+
# output_filename = OUTPUT_PATH
|
633
|
+
# ).process()
|
634
|
+
|
635
|
+
# return
|
636
|
+
|
637
|
+
return
|
614
638
|
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
#
|
620
|
-
|
621
|
-
|
622
|
-
#
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
#
|
633
|
-
|
634
|
-
|
635
|
-
#
|
636
|
-
|
637
|
-
#
|
638
|
-
|
639
|
-
|
640
|
-
#
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
#
|
647
|
-
#
|
648
|
-
#
|
649
|
-
|
650
|
-
#
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
#
|
655
|
-
#
|
656
|
-
#
|
657
|
-
#
|
658
|
-
# PIXEL_FORMAT = 'yuv420p'
|
659
|
-
|
660
|
-
# # Framebuffer to render
|
661
|
-
# fbo = waving_frame_effect.fbo
|
662
|
-
# fbo.use()
|
663
|
-
|
664
|
-
# # Decode first frame and use as texture
|
665
|
-
# first_frame = video.next_frame
|
666
|
-
# # We need to reset it to being again pointing
|
667
|
-
# # to the first frame...
|
668
|
-
# # TODO: Improve this by, maybe, storing the first
|
669
|
-
# # frame in memory so we can append it later, or
|
670
|
-
# # using the '.seek(0)' even when it could be not
|
671
|
-
# # accurate
|
672
|
-
# video = VideoReader(VIDEO_PATH)
|
673
|
-
|
674
|
-
# # Most of OpenGL textures expect origin in lower
|
675
|
-
# # left corner
|
676
|
-
# # TODO: What if alpha (?)
|
677
|
-
# # TODO: Move this to the OpenglFrameEffect maybe (?)
|
639
|
+
AMP = 0.05
|
640
|
+
FREQ = 10.0
|
641
|
+
SPEED = 2.0
|
642
|
+
|
643
|
+
# Get the information about the video
|
644
|
+
video = VideoReader(VIDEO_PATH)
|
645
|
+
|
646
|
+
# ModernGL context without window
|
647
|
+
context = moderngl.create_standalone_context()
|
648
|
+
|
649
|
+
waving_frame_effect = WavingFrame(
|
650
|
+
context = context,
|
651
|
+
frame_size = video.size
|
652
|
+
)
|
653
|
+
|
654
|
+
vao = waving_frame_effect.vao
|
655
|
+
|
656
|
+
# TODO: This has to be dynamic, but
|
657
|
+
# according to what (?)
|
658
|
+
NUMPY_FORMAT = 'rgb24'
|
659
|
+
# TODO: Where do we obtain this from (?)
|
660
|
+
VIDEO_CODEC_NAME = 'libx264'
|
661
|
+
# TODO: Where do we obtain this from (?)
|
662
|
+
PIXEL_FORMAT = 'yuv420p'
|
663
|
+
|
664
|
+
# Framebuffer to render
|
665
|
+
fbo = waving_frame_effect.fbo
|
666
|
+
fbo.use()
|
667
|
+
|
668
|
+
# Decode first frame and use as texture
|
669
|
+
first_frame = video.next_frame
|
670
|
+
# We need to reset it to being again pointing
|
671
|
+
# to the first frame...
|
672
|
+
# TODO: Improve this by, maybe, storing the first
|
673
|
+
# frame in memory so we can append it later, or
|
674
|
+
# using the '.seek(0)' even when it could be not
|
675
|
+
# accurate
|
676
|
+
video = VideoReader(VIDEO_PATH)
|
677
|
+
|
678
|
+
# Most of OpenGL textures expect origin in lower
|
679
|
+
# left corner
|
680
|
+
# TODO: What if alpha (?)
|
681
|
+
# TODO: Move this to the OpenglFrameEffect maybe (?)
|
678
682
|
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
#
|
683
|
-
#
|
684
|
-
#
|
685
|
-
#
|
686
|
-
#
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
#
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
#
|
707
|
-
#
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
#
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
#
|
724
|
-
#
|
725
|
-
#
|
726
|
-
|
683
|
+
texture: moderngl.Texture = frame_to_texture(first_frame, waving_frame_effect.context)
|
684
|
+
texture.build_mipmaps()
|
685
|
+
|
686
|
+
# These properties can be set before
|
687
|
+
# iterating the frames or maybe for
|
688
|
+
# each iteration... depending on the
|
689
|
+
# effect.
|
690
|
+
# Uniforms (properties)
|
691
|
+
(
|
692
|
+
waving_frame_effect
|
693
|
+
.set_value('amp', AMP)
|
694
|
+
.set_value('freq', FREQ)
|
695
|
+
.set_value('speed', SPEED)
|
696
|
+
)
|
697
|
+
|
698
|
+
# Writer with H.264 codec
|
699
|
+
video_writer = (
|
700
|
+
VideoWriter(OUTPUT_PATH)
|
701
|
+
.set_video_stream(VIDEO_CODEC_NAME, video.fps, video.size, PIXEL_FORMAT)
|
702
|
+
.set_audio_stream_from_template(video.audio_stream)
|
703
|
+
)
|
704
|
+
|
705
|
+
frame_index = 0
|
706
|
+
for frame_or_packet in video.iterate_with_audio(
|
707
|
+
do_decode_video = True,
|
708
|
+
do_decode_audio = False
|
709
|
+
):
|
710
|
+
# This below is because of the parameters we
|
711
|
+
# passed to the method
|
712
|
+
is_video_frame = PythonValidator.is_instance_of(frame_or_packet, 'VideoReaderFrame')
|
713
|
+
is_audio_packet = PythonValidator.is_instance_of(frame_or_packet, 'VideoReaderPacket')
|
714
|
+
|
715
|
+
# To simplify the process
|
716
|
+
if frame_or_packet is not None:
|
717
|
+
frame_or_packet = frame_or_packet.data
|
718
|
+
|
719
|
+
if is_audio_packet:
|
720
|
+
video_writer.mux(frame_or_packet)
|
721
|
+
elif is_video_frame:
|
722
|
+
with Timer(is_silent_as_context = True) as timer:
|
723
|
+
|
724
|
+
def process_frame(
|
725
|
+
frame: 'VideoFrame'
|
726
|
+
):
|
727
|
+
# Add some variables if we need, for the
|
728
|
+
# opengl change we are applying (check the
|
729
|
+
# program code)
|
730
|
+
waving_frame_effect.set_value('time', T.video_frame_index_to_video_frame_time(frame_index, float(video.fps)))
|
727
731
|
|
728
|
-
#
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
#
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
#
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
#
|
742
|
-
#
|
743
|
-
#
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
#
|
749
|
-
|
750
|
-
#
|
751
|
-
#
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
#
|
760
|
-
#
|
761
|
-
#
|
762
|
-
#
|
763
|
-
|
764
|
-
|
765
|
-
#
|
766
|
-
|
767
|
-
|
768
|
-
|
732
|
+
# Create texture
|
733
|
+
texture = frame_to_texture(frame, waving_frame_effect.context)
|
734
|
+
texture.use()
|
735
|
+
|
736
|
+
# Render with shader to frame buffer
|
737
|
+
fbo.use()
|
738
|
+
vao.render(moderngl.TRIANGLE_STRIP)
|
739
|
+
|
740
|
+
# Processed GPU result to numpy
|
741
|
+
processed_data = np.frombuffer(
|
742
|
+
fbo.read(components = 3, alignment = 1), dtype = np.uint8
|
743
|
+
)
|
744
|
+
|
745
|
+
# Invert numpy to normal frame
|
746
|
+
# TODO: Can I use the texture.size to fill
|
747
|
+
# these 'img_array.shape[0]' (?)
|
748
|
+
processed_data = np.flipud(
|
749
|
+
processed_data.reshape((texture.size[1], texture.size[0], 3))
|
750
|
+
)
|
751
|
+
|
752
|
+
# To VideoFrame and to buffer
|
753
|
+
frame = av.VideoFrame.from_ndarray(processed_data, format = NUMPY_FORMAT)
|
754
|
+
# TODO: What is this for (?)
|
755
|
+
#out_frame.pict_type = 'NONE'
|
756
|
+
return frame
|
757
|
+
|
758
|
+
video_writer.mux_video_frame(process_frame(frame_or_packet))
|
759
|
+
|
760
|
+
print(f'Frame {str(frame_index)}: {timer.time_elapsed_str}s')
|
761
|
+
frame_index += 1
|
762
|
+
|
763
|
+
# While this code can be finished, the work in
|
764
|
+
# the muxer could be not finished and have some
|
765
|
+
# packets waiting to be written. Here we tell
|
766
|
+
# the muxer to process all those packets.
|
767
|
+
video_writer.mux_video_frame(None)
|
768
|
+
|
769
|
+
# TODO: Maybe move this to the '__del__' (?)
|
770
|
+
video_writer.output.close()
|
771
|
+
video.container.close()
|
772
|
+
print(f'Saved as "{OUTPUT_PATH}".')
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: yta-video-opengl
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.24
|
4
4
|
Summary: Youtube Autonomous Video OpenGL Module
|
5
5
|
Author: danialcala94
|
6
6
|
Author-email: danielalcalavalera@gmail.com
|
@@ -9,6 +9,7 @@ Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.9
|
10
10
|
Requires-Dist: moderngl (>=0.0.1,<9.0.0)
|
11
11
|
Requires-Dist: numpy (>=0.0.1,<9.0.0)
|
12
|
+
Requires-Dist: yta_programming (>=0.0.1,<1.0.0)
|
12
13
|
Requires-Dist: yta_validation (>=0.0.1,<1.0.0)
|
13
14
|
Description-Content-Type: text/markdown
|
14
15
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
yta_video_opengl/__init__.py,sha256=ycAx_XYMVDfkuObSvtW6irQ0Wo-fgxEz3fjIRMe8PpY,205
|
2
|
+
yta_video_opengl/editor.py,sha256=ILzeGAe6uO5IptwrplbvnFu8e0j8v9AOaAmuvFH4YjI,9218
|
3
|
+
yta_video_opengl/nodes/__init__.py,sha256=Rbh6HxWpKrdF_qlcGVKYBGW6i10NodoExa5qGEMcmIM,3738
|
4
|
+
yta_video_opengl/nodes/audio/__init__.py,sha256=upKsYZrrNW2DxP77RyMCw2I16Lj9JsHbXGALw5grxbQ,6143
|
5
|
+
yta_video_opengl/nodes/video/__init__.py,sha256=Nf1CnUaz6m7mOvVsuoTKMsq5QIVqEqZaiGseNOre8_k,859
|
6
|
+
yta_video_opengl/nodes/video/opengl/__init__.py,sha256=bVPdS_wpz4HNurmLRDEHUmNZU7Qz8LptKfJ9yN_2PJM,8587
|
7
|
+
yta_video_opengl/nodes/video/opengl/experimental.py,sha256=XuriXcOuJU5P0FruKffudCpMuO-ht8weJud88Qn8GKk,22158
|
8
|
+
yta_video_opengl/tests.py,sha256=uvTU1_cvz5r7fETd4X8hvsYw4jViMDA0x-LsDNplFPM,24265
|
9
|
+
yta_video_opengl/utils.py,sha256=w6jYnZcBYPNAsTolkAlA6dxph0u_8-mcUzKvADlIlW8,3098
|
10
|
+
yta_video_opengl-0.0.24.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
11
|
+
yta_video_opengl-0.0.24.dist-info/METADATA,sha256=WKcDQFnZS0TvesGJM9N-bbPjOx0DdTNZb6yU-4nzUqY,589
|
12
|
+
yta_video_opengl-0.0.24.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
13
|
+
yta_video_opengl-0.0.24.dist-info/RECORD,,
|