vidformer 0.1.0__py3-none-any.whl → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vidformer
3
- Version: 0.1.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.1.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 True
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 False
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, keep_spec=False):
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
- spec_pth = f"spec-{str(uuid.uuid4())}.json"
84
- with open(spec_pth, "w") as outfile:
85
- spec, sources, filters = self._to_json_spec()
86
- outfile.write(json.dumps(spec))
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(spec_pth, sources, filters, arrays, self._fmt)
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
- # We add a namespace to the video element to avoid conflicts with other videos
117
- html_code = f"""
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
- return HTML(data=html_code)
143
+ return HTML(data=html_code)
144
+ else:
145
+ return hls_player_url
142
146
 
143
- def save(self, server, pth, keep_spec=False):
147
+ def save(self, server, pth, encoder=None, encoder_opts=None):
144
148
  """Save the video to a file."""
145
149
 
146
- spec_pth = f"spec-{str(uuid.uuid4())}.json"
147
- with open(spec_pth, "w") as outfile:
148
- spec, sources, filters = self._to_json_spec()
149
- outfile.write(json.dumps(spec))
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(pth, spec_pth, sources, filters, arrays, self._fmt)
170
-
171
- if not keep_spec:
172
- os.remove(spec_pth)
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 also a trick to get VS Code to forward the port
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
- assert _check_hls_link_exists(f"http://{self._domain}:{self._port}/")
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, spec_pth, sources, filters, arrays, fmt):
337
+ def _export(self, pth, spec, sources, filters, arrays, fmt, encoder, encoder_opts):
314
338
  req = {
315
- "spec": spec_pth,
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.name}.iloc[{self._idx}]"
374
+ return f"{self._source._name}.iloc[{self._idx}]"
349
375
  else:
350
- return f"{self._source.name}[{self._idx}]"
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
@@ -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,,