vidformer 0.1.0__py3-none-any.whl → 0.3.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: vidformer
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
4
4
|
Summary: A Python library for creating and viewing videos with vidformer.
|
5
5
|
Author-email: Dominik Winecki <dominikwinecki@gmail.com>
|
6
6
|
Requires-Python: >=3.8
|
@@ -13,3 +13,10 @@ Requires-Dist: numpy
|
|
13
13
|
|
14
14
|
# vidformer-py
|
15
15
|
|
16
|
+
## Publish
|
17
|
+
|
18
|
+
```bash
|
19
|
+
export FLIT_USERNAME='__token__' FLIT_PASSWORD='<token>'
|
20
|
+
flit publish
|
21
|
+
```
|
22
|
+
|
@@ -0,0 +1,4 @@
|
|
1
|
+
vidformer.py,sha256=hnFxf85IBD1dqaflKYcIE7bp4lYzg5jOCISSyXrvpZs,24520
|
2
|
+
vidformer-0.3.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
3
|
+
vidformer-0.3.0.dist-info/METADATA,sha256=38wZlgJ2NUTDZgsegDsJrfF6uLrxRK00Pn9IBRAjEUQ,523
|
4
|
+
vidformer-0.3.0.dist-info/RECORD,,
|
vidformer.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"""A Python library for creating and viewing videos with vidformer."""
|
2
2
|
|
3
|
-
__version__ = "0.
|
3
|
+
__version__ = "0.3.0"
|
4
4
|
|
5
5
|
import subprocess
|
6
6
|
from fractions import Fraction
|
@@ -13,6 +13,8 @@ import sys
|
|
13
13
|
import multiprocessing
|
14
14
|
import uuid
|
15
15
|
import threading
|
16
|
+
import gzip
|
17
|
+
import base64
|
16
18
|
|
17
19
|
import requests
|
18
20
|
import msgpack
|
@@ -33,12 +35,12 @@ def _check_hls_link_exists(url, max_attempts=150, delay=0.1):
|
|
33
35
|
try:
|
34
36
|
response = requests.get(url)
|
35
37
|
if response.status_code == 200:
|
36
|
-
return
|
38
|
+
return response.text.strip()
|
37
39
|
else:
|
38
40
|
time.sleep(delay)
|
39
41
|
except requests.exceptions.RequestException as e:
|
40
42
|
time.sleep(delay)
|
41
|
-
return
|
43
|
+
return None
|
42
44
|
|
43
45
|
|
44
46
|
class Spec:
|
@@ -75,15 +77,15 @@ class Spec:
|
|
75
77
|
frames.append(frame)
|
76
78
|
return {"frames": frames}, s, f
|
77
79
|
|
78
|
-
def play(self, server,
|
80
|
+
def play(self, server, method="html"):
|
79
81
|
"""Play the video live in the notebook."""
|
80
82
|
|
81
|
-
from IPython.display import HTML
|
83
|
+
from IPython.display import IFrame, HTML
|
82
84
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
spec, sources, filters = self._to_json_spec()
|
86
|
+
spec_json_bytes = json.dumps(spec).encode("utf-8")
|
87
|
+
spec_obj_json_gzip = gzip.compress(spec_json_bytes, compresslevel=1)
|
88
|
+
spec_obj_json_gzip_b64 = base64.b64encode(spec_obj_json_gzip).decode("utf-8")
|
87
89
|
|
88
90
|
sources = [
|
89
91
|
{
|
@@ -103,18 +105,18 @@ class Spec:
|
|
103
105
|
}
|
104
106
|
arrays = []
|
105
107
|
|
106
|
-
print("Sending to server")
|
107
|
-
resp = server._new(
|
108
|
+
print(f"Sending to server. Spec is {len(spec_obj_json_gzip_b64)} bytes")
|
109
|
+
resp = server._new(spec_obj_json_gzip_b64, sources, filters, arrays, self._fmt)
|
108
110
|
hls_video_url = resp["stream_url"]
|
111
|
+
hls_player_url = resp["player_url"]
|
109
112
|
namespace = resp["namespace"]
|
110
|
-
|
111
|
-
if not keep_spec:
|
112
|
-
os.remove(spec_pth)
|
113
|
-
|
114
113
|
hls_js_url = server.hls_js_url()
|
115
114
|
|
116
|
-
|
117
|
-
|
115
|
+
if method == "iframe":
|
116
|
+
return IFrame(hls_player_url, width=1280, height=720)
|
117
|
+
if method == "html":
|
118
|
+
# We add a namespace to the video element to avoid conflicts with other videos
|
119
|
+
html_code = f"""
|
118
120
|
<!DOCTYPE html>
|
119
121
|
<html>
|
120
122
|
<head>
|
@@ -138,15 +140,23 @@ class Spec:
|
|
138
140
|
</body>
|
139
141
|
</html>
|
140
142
|
"""
|
141
|
-
|
143
|
+
return HTML(data=html_code)
|
144
|
+
else:
|
145
|
+
return hls_player_url
|
142
146
|
|
143
|
-
def save(self, server, pth,
|
147
|
+
def save(self, server, pth, encoder=None, encoder_opts=None):
|
144
148
|
"""Save the video to a file."""
|
145
149
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
+
assert encoder is None or type(encoder) == str
|
151
|
+
assert encoder_opts is None or type(encoder_opts) == dict
|
152
|
+
if encoder_opts is not None:
|
153
|
+
for k, v in encoder_opts:
|
154
|
+
assert type(k) == str and type(v) == str
|
155
|
+
|
156
|
+
spec, sources, filters = self._to_json_spec()
|
157
|
+
spec_json_bytes = json.dumps(spec).encode("utf-8")
|
158
|
+
spec_obj_json_gzip = gzip.compress(spec_json_bytes, compresslevel=1)
|
159
|
+
spec_obj_json_gzip_b64 = base64.b64encode(spec_obj_json_gzip).decode("utf-8")
|
150
160
|
|
151
161
|
sources = [
|
152
162
|
{
|
@@ -166,10 +176,16 @@ class Spec:
|
|
166
176
|
}
|
167
177
|
arrays = []
|
168
178
|
|
169
|
-
resp = server._export(
|
170
|
-
|
171
|
-
|
172
|
-
|
179
|
+
resp = server._export(
|
180
|
+
pth,
|
181
|
+
spec_obj_json_gzip_b64,
|
182
|
+
sources,
|
183
|
+
filters,
|
184
|
+
arrays,
|
185
|
+
self._fmt,
|
186
|
+
encoder,
|
187
|
+
encoder_opts,
|
188
|
+
)
|
173
189
|
|
174
190
|
return resp
|
175
191
|
|
@@ -245,7 +261,7 @@ class Spec:
|
|
245
261
|
out["dve2_create_spec"] = end_t - start_t
|
246
262
|
|
247
263
|
start = time.time()
|
248
|
-
resp = server._export(pth, sources, filters, arrays, self._fmt)
|
264
|
+
resp = server._export(pth, sources, filters, arrays, self._fmt, None, None)
|
249
265
|
end = time.time()
|
250
266
|
out["dve2_exec"] = end - start
|
251
267
|
return out
|
@@ -270,11 +286,19 @@ class YrdenServer:
|
|
270
286
|
cmd = [bin, "yrden", "--port", str(self._port)]
|
271
287
|
if _in_notebook:
|
272
288
|
# We need to print the URL in the notebook
|
273
|
-
# This is
|
289
|
+
# This is a trick to get VS Code to forward the port
|
274
290
|
cmd += ["--print-url"]
|
275
291
|
self._proc = subprocess.Popen(cmd)
|
276
292
|
|
277
|
-
|
293
|
+
version = _check_hls_link_exists(f"http://{self._domain}:{self._port}/")
|
294
|
+
if version is None:
|
295
|
+
raise Exception("Failed to connect to server")
|
296
|
+
|
297
|
+
expected_version = f"vidformer-yrden v{__version__}"
|
298
|
+
if version != expected_version:
|
299
|
+
print(
|
300
|
+
f"Warning: Expected version `{expected_version}`, got `{version}`. API may not be compatible!"
|
301
|
+
)
|
278
302
|
|
279
303
|
def _source(self, name: str, path: str, stream: int, service):
|
280
304
|
r = requests.post(
|
@@ -310,9 +334,9 @@ class YrdenServer:
|
|
310
334
|
|
311
335
|
return r.json()
|
312
336
|
|
313
|
-
def _export(self, pth,
|
337
|
+
def _export(self, pth, spec, sources, filters, arrays, fmt, encoder, encoder_opts):
|
314
338
|
req = {
|
315
|
-
"spec":
|
339
|
+
"spec": spec,
|
316
340
|
"sources": sources,
|
317
341
|
"filters": filters,
|
318
342
|
"arrays": arrays,
|
@@ -320,6 +344,8 @@ class YrdenServer:
|
|
320
344
|
"height": fmt["height"],
|
321
345
|
"pix_fmt": fmt["pix_fmt"],
|
322
346
|
"output_path": pth,
|
347
|
+
"encoder": encoder,
|
348
|
+
"encoder_opts": encoder_opts,
|
323
349
|
}
|
324
350
|
|
325
351
|
r = requests.post(f"http://{self._domain}:{self._port}/export", json=req)
|
@@ -345,9 +371,9 @@ class SourceExpr:
|
|
345
371
|
|
346
372
|
def __repr__(self):
|
347
373
|
if self._is_iloc:
|
348
|
-
return f"{self._source.
|
374
|
+
return f"{self._source._name}.iloc[{self._idx}]"
|
349
375
|
else:
|
350
|
-
return f"{self._source.
|
376
|
+
return f"{self._source._name}[{self._idx}]"
|
351
377
|
|
352
378
|
def _to_json_spec(self):
|
353
379
|
if self._is_iloc:
|
@@ -511,6 +537,8 @@ class FilterExpr:
|
|
511
537
|
|
512
538
|
|
513
539
|
class UDF:
|
540
|
+
"""User-defined filter superclass"""
|
541
|
+
|
514
542
|
def __init__(self, name: str):
|
515
543
|
self._name = name
|
516
544
|
self._socket_path = None
|
vidformer-0.1.0.dist-info/RECORD
DELETED
@@ -1,4 +0,0 @@
|
|
1
|
-
vidformer.py,sha256=bLGZ4zQVkU6etFj0jWuJM8h0sJqcZXwkqA0VfdtCyk0,23257
|
2
|
-
vidformer-0.1.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
3
|
-
vidformer-0.1.0.dist-info/METADATA,sha256=2YNtgTcee8N9LM8lzMvNFLndbcNy88Fqk6mwFYhz8pQ,427
|
4
|
-
vidformer-0.1.0.dist-info/RECORD,,
|
File without changes
|