kinemotion 0.39.0__py3-none-any.whl → 0.40.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 kinemotion might be problematic. Click here for more details.
- kinemotion/core/debug_overlay_utils.py +95 -15
- {kinemotion-0.39.0.dist-info → kinemotion-0.40.0.dist-info}/METADATA +1 -1
- {kinemotion-0.39.0.dist-info → kinemotion-0.40.0.dist-info}/RECORD +6 -6
- {kinemotion-0.39.0.dist-info → kinemotion-0.40.0.dist-info}/WHEEL +0 -0
- {kinemotion-0.39.0.dist-info → kinemotion-0.40.0.dist-info}/entry_points.txt +0 -0
- {kinemotion-0.39.0.dist-info → kinemotion-0.40.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
"""Shared debug overlay utilities for video rendering."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
import time
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
3
9
|
import cv2
|
|
4
10
|
import numpy as np
|
|
5
11
|
|
|
@@ -11,7 +17,7 @@ def create_video_writer(
|
|
|
11
17
|
display_width: int,
|
|
12
18
|
display_height: int,
|
|
13
19
|
fps: float,
|
|
14
|
-
) -> tuple[cv2.VideoWriter, bool]:
|
|
20
|
+
) -> tuple[cv2.VideoWriter, bool, str]:
|
|
15
21
|
"""
|
|
16
22
|
Create a video writer with fallback codec support.
|
|
17
23
|
|
|
@@ -24,28 +30,43 @@ def create_video_writer(
|
|
|
24
30
|
fps: Frames per second
|
|
25
31
|
|
|
26
32
|
Returns:
|
|
27
|
-
Tuple of (video_writer, needs_resize)
|
|
33
|
+
Tuple of (video_writer, needs_resize, used_codec)
|
|
28
34
|
"""
|
|
29
35
|
needs_resize = (display_width != width) or (display_height != height)
|
|
30
36
|
|
|
31
|
-
# Try
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
# Try browser-compatible codecs first
|
|
38
|
+
# avc1/h264: H.264 (Most compatible)
|
|
39
|
+
# vp09: VP9 (Good compatibility)
|
|
40
|
+
# mp4v: MPEG-4 (Poor browser support, last resort)
|
|
41
|
+
codecs_to_try = ["avc1", "h264", "vp09", "mp4v"]
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
|
|
38
|
-
writer = cv2.VideoWriter(
|
|
39
|
-
output_path, fourcc, fps, (display_width, display_height)
|
|
40
|
-
)
|
|
43
|
+
writer = None
|
|
44
|
+
used_codec = "mp4v" # Default fallback
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
for codec in codecs_to_try:
|
|
47
|
+
try:
|
|
48
|
+
fourcc = cv2.VideoWriter_fourcc(*codec)
|
|
49
|
+
writer = cv2.VideoWriter(
|
|
50
|
+
output_path, fourcc, fps, (display_width, display_height)
|
|
51
|
+
)
|
|
52
|
+
if writer.isOpened():
|
|
53
|
+
used_codec = codec
|
|
54
|
+
if codec == "mp4v":
|
|
55
|
+
print(
|
|
56
|
+
f"Warning: Fallback to {codec} codec. "
|
|
57
|
+
"Video may not play in browsers."
|
|
58
|
+
)
|
|
59
|
+
break
|
|
60
|
+
except Exception:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
if writer is None or not writer.isOpened():
|
|
43
64
|
raise ValueError(
|
|
44
65
|
f"Failed to create video writer for {output_path} with dimensions "
|
|
45
66
|
f"{display_width}x{display_height}"
|
|
46
67
|
)
|
|
47
68
|
|
|
48
|
-
return writer, needs_resize
|
|
69
|
+
return writer, needs_resize, used_codec
|
|
49
70
|
|
|
50
71
|
|
|
51
72
|
def write_overlay_frame(
|
|
@@ -95,11 +116,12 @@ class BaseDebugOverlayRenderer:
|
|
|
95
116
|
display_height: Display height (considering SAR)
|
|
96
117
|
fps: Frames per second
|
|
97
118
|
"""
|
|
119
|
+
self.output_path = output_path
|
|
98
120
|
self.width = width
|
|
99
121
|
self.height = height
|
|
100
122
|
self.display_width = display_width
|
|
101
123
|
self.display_height = display_height
|
|
102
|
-
self.writer, self.needs_resize = create_video_writer(
|
|
124
|
+
self.writer, self.needs_resize, self.used_codec = create_video_writer(
|
|
103
125
|
output_path, width, height, display_width, display_height, fps
|
|
104
126
|
)
|
|
105
127
|
|
|
@@ -133,9 +155,67 @@ class BaseDebugOverlayRenderer:
|
|
|
133
155
|
write_overlay_frame(self.writer, frame, self.display_width, self.display_height)
|
|
134
156
|
|
|
135
157
|
def close(self) -> None:
|
|
136
|
-
"""Release video writer."""
|
|
158
|
+
"""Release video writer and re-encode if possible."""
|
|
137
159
|
self.writer.release()
|
|
138
160
|
|
|
161
|
+
# Post-process with ffmpeg ONLY if we fell back to the incompatible mp4v codec
|
|
162
|
+
if self.used_codec == "mp4v" and shutil.which("ffmpeg"):
|
|
163
|
+
temp_path = None
|
|
164
|
+
try:
|
|
165
|
+
temp_path = str(
|
|
166
|
+
Path(self.output_path).with_suffix(
|
|
167
|
+
".temp" + Path(self.output_path).suffix
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Convert to H.264 with yuv420p pixel format for browser compatibility
|
|
172
|
+
# -y: Overwrite output file
|
|
173
|
+
# -vcodec libx264: Use H.264 codec
|
|
174
|
+
# -pix_fmt yuv420p: Required for wide browser support (Chrome,
|
|
175
|
+
# Safari, Firefox)
|
|
176
|
+
# -preset fast: Reasonable speed/compression tradeoff
|
|
177
|
+
# -crf 23: Standard quality
|
|
178
|
+
# -an: Remove audio (debug video has no audio)
|
|
179
|
+
cmd = [
|
|
180
|
+
"ffmpeg",
|
|
181
|
+
"-y",
|
|
182
|
+
"-i",
|
|
183
|
+
self.output_path,
|
|
184
|
+
"-vcodec",
|
|
185
|
+
"libx264",
|
|
186
|
+
"-pix_fmt",
|
|
187
|
+
"yuv420p",
|
|
188
|
+
"-preset",
|
|
189
|
+
"fast",
|
|
190
|
+
"-crf",
|
|
191
|
+
"23",
|
|
192
|
+
"-an",
|
|
193
|
+
temp_path,
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
# Suppress output unless error
|
|
197
|
+
reencode_start = time.time()
|
|
198
|
+
subprocess.run(
|
|
199
|
+
cmd,
|
|
200
|
+
check=True,
|
|
201
|
+
stdout=subprocess.DEVNULL,
|
|
202
|
+
stderr=subprocess.PIPE,
|
|
203
|
+
)
|
|
204
|
+
reencode_duration = time.time() - reencode_start
|
|
205
|
+
print(f"Debug video re-encoded in {reencode_duration:.2f}s")
|
|
206
|
+
|
|
207
|
+
# Overwrite original file
|
|
208
|
+
os.replace(temp_path, self.output_path)
|
|
209
|
+
|
|
210
|
+
except subprocess.CalledProcessError as e:
|
|
211
|
+
print(f"Warning: Failed to re-encode debug video with ffmpeg: {e}")
|
|
212
|
+
if temp_path and os.path.exists(temp_path):
|
|
213
|
+
os.remove(temp_path)
|
|
214
|
+
except Exception as e:
|
|
215
|
+
print(f"Warning: Error during video post-processing: {e}")
|
|
216
|
+
if temp_path and os.path.exists(temp_path):
|
|
217
|
+
os.remove(temp_path)
|
|
218
|
+
|
|
139
219
|
def __enter__(self) -> "BaseDebugOverlayRenderer":
|
|
140
220
|
return self
|
|
141
221
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kinemotion
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.40.0
|
|
4
4
|
Summary: Video-based kinematic analysis for athletic performance
|
|
5
5
|
Project-URL: Homepage, https://github.com/feniix/kinemotion
|
|
6
6
|
Project-URL: Repository, https://github.com/feniix/kinemotion
|
|
@@ -12,7 +12,7 @@ kinemotion/cmj/validation_bounds.py,sha256=9ZTo68fl3ooyWjXXyTMRLpK9tFANa_rQf3oHh
|
|
|
12
12
|
kinemotion/core/__init__.py,sha256=HsqolRa60cW3vrG8F9Lvr9WvWcs5hCmsTzSgo7imi-4,1278
|
|
13
13
|
kinemotion/core/auto_tuning.py,sha256=wtCUMOhBChVJNXfEeku3GCMW4qED6MF-O_mv2sPTiVQ,11324
|
|
14
14
|
kinemotion/core/cli_utils.py,sha256=zbnifPhD-OYofJioeYfJtshuWcl8OAEWtqCGVF4ctAI,7966
|
|
15
|
-
kinemotion/core/debug_overlay_utils.py,sha256
|
|
15
|
+
kinemotion/core/debug_overlay_utils.py,sha256=-HRHw5Ew7hVH0MWwdutZV1JwPqQwzQ6Jex7xHWc3q88,7511
|
|
16
16
|
kinemotion/core/determinism.py,sha256=NwVrHqJiVxxFHTBPVy8aDBJH2SLIcYIpdGFp7glblB8,2515
|
|
17
17
|
kinemotion/core/experimental.py,sha256=IK05AF4aZS15ke85hF3TWCqRIXU1AlD_XKzFz735Ua8,3640
|
|
18
18
|
kinemotion/core/filtering.py,sha256=GsC9BB71V07LJJHgS2lsaxUAtJsupcUiwtZFDgODh8c,11417
|
|
@@ -31,8 +31,8 @@ kinemotion/dropjump/kinematics.py,sha256=kH-XM66wlOCYMpjvyb6_Qh5ZebyOfFZ47rmhgE1
|
|
|
31
31
|
kinemotion/dropjump/metrics_validator.py,sha256=CrTlGup8q2kyPXtA6HNwm7_yq0AsBaDllG7RVZdXmYA,9342
|
|
32
32
|
kinemotion/dropjump/validation_bounds.py,sha256=5b4I3CKPybuvrbn-nP5yCcGF_sH4Vtyw3a5AWWvWnBk,4645
|
|
33
33
|
kinemotion/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
-
kinemotion-0.
|
|
35
|
-
kinemotion-0.
|
|
36
|
-
kinemotion-0.
|
|
37
|
-
kinemotion-0.
|
|
38
|
-
kinemotion-0.
|
|
34
|
+
kinemotion-0.40.0.dist-info/METADATA,sha256=0X_uEEzEi-DH9d4HwfseQVEzlDmbJRw96Dn1o-m5DbI,26020
|
|
35
|
+
kinemotion-0.40.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
36
|
+
kinemotion-0.40.0.dist-info/entry_points.txt,sha256=zaqnAnjLvcdrk1Qvj5nvXZCZ2gp0prS7it1zTJygcIY,50
|
|
37
|
+
kinemotion-0.40.0.dist-info/licenses/LICENSE,sha256=KZajvqsHw0NoOHOi2q0FZ4NBe9HdV6oey-IPYAtHXfg,1088
|
|
38
|
+
kinemotion-0.40.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|