videopython 0.4.0__py3-none-any.whl → 0.5.0__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 videopython might be problematic. Click here for more details.

@@ -1,55 +0,0 @@
1
- from itertools import repeat
2
- from multiprocessing import Pool
3
-
4
- from videopython.base.transforms import TransformationPipeline
5
- from videopython.base.transitions import InstantTransition, Transition
6
- from videopython.base.video import Video
7
-
8
-
9
- class VideoComposer:
10
- """
11
- Composes multiple Videos into single video using selected transformations
12
- on each video and applies transitions.
13
- """
14
-
15
- def __init__(
16
- self,
17
- transformation_pipeline: TransformationPipeline | None = None,
18
- transition: Transition = InstantTransition(),
19
- ):
20
- """Initializes VideoComposer.
21
-
22
- Args:
23
- transformation_pipeline: Pipeline of transformations to apply on each video.
24
- transition: Transition to apply between videos
25
- """
26
- self.transition = transition
27
- self.transformation_pipeline = transformation_pipeline
28
-
29
- def _apply_transformation(self, video: Video, transformation_pipeline: TransformationPipeline) -> Video:
30
- return transformation_pipeline(video)
31
-
32
- def compose(self, videos: list[Video]) -> Video:
33
- # Apply transformation on each video using multiprocessing pool:
34
- if self.transformation_pipeline:
35
- transformed_videos = []
36
- with Pool() as pool:
37
- transformed_videos = pool.starmap(
38
- self._apply_transformation,
39
- zip(videos, repeat(self.transformation_pipeline)),
40
- )
41
- videos = transformed_videos
42
-
43
- # Check if videos are compatible:
44
- self._compatibility_check(videos)
45
-
46
- # Apply transition:
47
- final_video = videos.pop(0)
48
- for _ in range(len(videos)):
49
- final_video = self.transition.apply((final_video, videos.pop(0)))
50
-
51
- return final_video
52
-
53
- @staticmethod
54
- def _compatibility_check(videos: list[Video]):
55
- assert all([videos[0].metadata.can_be_merged_with(other_video.metadata) for other_video in videos])
@@ -1,13 +0,0 @@
1
- from dataclasses import dataclass
2
-
3
-
4
- @dataclass
5
- class TranscriptionSegment:
6
- start: float
7
- end: float
8
- text: str
9
-
10
-
11
- @dataclass
12
- class Transcription:
13
- segments: list[TranscriptionSegment]
@@ -1,3 +0,0 @@
1
- from videopython.utils.text import AnchorPoint, ImageText, TextAlign
2
-
3
- __all__ = ["AnchorPoint", "ImageText", "TextAlign"]
@@ -1,31 +0,0 @@
1
- import time
2
- import uuid
3
- from pathlib import Path
4
- from typing import Callable
5
-
6
-
7
- def generate_random_name(suffix=".mp4"):
8
- """Generates random name."""
9
- return f"{uuid.uuid4()}{suffix}"
10
-
11
-
12
- def timeit(func: Callable):
13
- """Decorator to measure execution time of a function."""
14
-
15
- def timed(*args, **kwargs):
16
- start = time.time()
17
- result = func(*args, **kwargs)
18
- end = time.time()
19
- print(f"Execution time: {end - start:.3f} seconds.")
20
- return result
21
-
22
- return timed
23
-
24
-
25
- def check_path(path: str, dir_exists: bool = True, suffix: str | None = None) -> str:
26
- fullpath = Path(path).resolve()
27
- if dir_exists and not fullpath.parent.exists():
28
- raise ValueError(f"Directory `{fullpath.parent}` does not exist!")
29
- if suffix and suffix != fullpath.suffix:
30
- raise ValueError(f"Required suffix `{suffix}` does not match the file suffix `{fullpath.suffix}`")
31
- return str(fullpath)
@@ -1,47 +0,0 @@
1
- from typing import Literal
2
-
3
- import cv2
4
- import numpy as np
5
-
6
- from videopython.base.video import Video
7
-
8
-
9
- class SlideOverImage:
10
- def __init__(
11
- self,
12
- direction: Literal["left", "right"],
13
- video_shape: tuple[int, int] = (1080, 1920),
14
- fps: float = 24.0,
15
- length_seconds: float = 1.0,
16
- ) -> None:
17
- self.direction = direction
18
- self.video_width, self.video_height = video_shape
19
- self.fps = fps
20
- self.length_seconds = length_seconds
21
-
22
- def apply(self, image: np.ndarray) -> Video:
23
- image = self._resize(image)
24
- max_offset = image.shape[1] - self.video_width
25
- frame_count = round(self.fps * self.length_seconds)
26
-
27
- deltas = np.linspace(0, max_offset, frame_count)
28
- frames = []
29
-
30
- for delta in deltas:
31
- if self.direction == "right":
32
- frame = image[:, round(delta) : round(delta) + self.video_width]
33
- elif self.direction == "left":
34
- frame = image[:, image.shape[1] - round(delta) - self.video_width : image.shape[1] - round(delta)]
35
- frames.append(frame)
36
-
37
- return Video.from_frames(frames=np.stack(frames, axis=0), fps=self.fps)
38
-
39
- def _resize(self, image: np.ndarray) -> np.ndarray:
40
- resize_factor = image.shape[0] / self.video_height
41
- resize_dims = (round(image.shape[1] / resize_factor), round(image.shape[0] / resize_factor)) # width, height
42
- image = cv2.resize(image, resize_dims)
43
- if self.video_height > image.shape[0] or self.video_width > image.shape[1]:
44
- raise ValueError(
45
- f"Image `{image.shape}` is too small for the video frame `({self.video_width}, {self.video_height})`!"
46
- )
47
- return image
@@ -1,118 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: videopython
3
- Version: 0.4.0
4
- Summary: Minimal video generation and processing library.
5
- Project-URL: Homepage, https://github.com/bartwojtowicz/videopython/
6
- Project-URL: Repository, https://github.com/bartwojtowicz/videopython/
7
- Project-URL: Documentation, https://github.com/bartwojtowicz/videopython/
8
- Author-email: Bartosz Wójtowicz <bartoszwojtowicz@outlook.com>, Bartosz Rudnikowicz <bartoszrudnikowicz840@gmail.com>, Piotr Pukisz <piotr.pukisz@gmail.com>
9
- License: Apache-2.0
10
- License-File: LICENSE
11
- Keywords: editing,generation,movie,opencv,python,video,videopython
12
- Classifier: License :: OSI Approved :: Apache Software License
13
- Classifier: Operating System :: OS Independent
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.10
16
- Classifier: Programming Language :: Python :: 3.11
17
- Requires-Python: <3.13,>=3.10
18
- Requires-Dist: numpy>=1.25.2
19
- Requires-Dist: opencv-python>=4.9.0.80
20
- Requires-Dist: pillow>=10.3.0
21
- Requires-Dist: pydub>=0.25.1
22
- Requires-Dist: soundpython>=0.1.11
23
- Requires-Dist: tqdm>=4.66.3
24
- Description-Content-Type: text/markdown
25
-
26
- # About
27
-
28
- Minimal video generation and processing library.
29
-
30
- ## Setup
31
-
32
- ### Install ffmpeg
33
- ```bash
34
- # Install with brew for MacOS:
35
- brew install ffmpeg
36
- # Install with apt-get for Ubuntu:
37
- sudo apt-get install ffmpeg
38
- ```
39
-
40
- ### Install with pip
41
- ```bash
42
- pip install videopython[ai]
43
- ```
44
- > You can install without `[ai]` dependencies for basic video handling and processing.
45
- > The funcionalities found in `videopython.ai` won't work.
46
-
47
- ## Basic Usage
48
-
49
- ### Video handling
50
-
51
- ```python
52
- from videopython.base.video import Video
53
-
54
- # Load videos and print metadata
55
- video1 = Video.from_path("tests/test_data/small_video.mp4")
56
- print(video1)
57
-
58
- video2 = Video.from_path("tests/test_data/big_video.mp4")
59
- print(video2)
60
-
61
- # Define the transformations
62
- from videopython.base.transforms import CutSeconds, ResampleFPS, Resize, TransformationPipeline
63
-
64
- pipeline = TransformationPipeline(
65
- [CutSeconds(start=1.5, end=6.5), ResampleFPS(fps=30), Resize(width=1000, height=1000)]
66
- )
67
- video1 = pipeline.run(video1)
68
- video2 = pipeline.run(video2)
69
-
70
- # Combine videos, add audio and save
71
- from videopython.base.transitions import FadeTransition
72
-
73
- fade = FadeTransition(effect_time_seconds=3.0)
74
- video = fade.apply(videos=(video1, video2))
75
- video.add_audio_from_file("tests/test_data/test_audio.mp3")
76
-
77
- savepath = video.save()
78
- ```
79
-
80
- ### Video Generation
81
-
82
- > Using Nvidia A40 or better is recommended for the `videopython.ai` module.
83
- ```python
84
- # Generate image and animate it
85
- from videopython.ai.generation import ImageToVideo
86
- from videopython.ai.generation import TextToImage
87
- from videopython.ai.generation import TextToMusic
88
-
89
- image = TextToImage().generate_image(prompt="Golden Retriever playing in the park")
90
- video = ImageToVideo().generate_video(image=image, fps=24)
91
-
92
- # Video generation directly from prompt
93
- from videopython.ai.generation import TextToVideo
94
- video_gen = TextToVideo()
95
- video = video_gen.generate_video("Dogs playing in the snow")
96
- for _ in range(10):
97
- video += video_gen.generate_video("Dogs playing in the snow")
98
-
99
- # Cut the first 2 seconds
100
- from videopython.base.transforms import CutSeconds
101
- transformed_video = CutSeconds(start_second=0, end_second=2).apply(video.copy())
102
-
103
- # Upsample to 30 FPS
104
- from videopython.base.transforms import ResampleFPS
105
- transformed_video = ResampleFPS(new_fps=30).apply(transformed_video)
106
-
107
- # Resize to 1000x1000
108
- from videopython.base.transforms import Resize
109
- transformed_video = Resize(width=1000, height=1000).apply(transformed_video)
110
-
111
- # Add generated music
112
- # MusicGen cannot generate more than 1503 tokens (~30seconds of audio)
113
- text_to_music = TextToMusic()
114
- audio = text_to_music.generate_audio("Happy dogs playing together in a park", max_new_tokens=256)
115
- transformed_video.add_audio(audio=audio)
116
-
117
- filepath = transformed_video.save()
118
- ```