vidformer 0.5.0__tar.gz → 0.5.3__tar.gz

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.5.0
3
+ Version: 0.5.3
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
@@ -1,6 +1,6 @@
1
1
  """A Python library for creating and viewing videos with vidformer."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.5.3"
4
4
 
5
5
  import subprocess
6
6
  from fractions import Fraction
@@ -77,7 +77,7 @@ class Spec:
77
77
  frames.append(frame)
78
78
  return {"frames": frames}, s, f
79
79
 
80
- def play(self, server, method="html"):
80
+ def play(self, server, method="html", verbose=False):
81
81
  """Play the video live in the notebook."""
82
82
 
83
83
  spec, sources, filters = self._to_json_spec()
@@ -103,7 +103,9 @@ class Spec:
103
103
  }
104
104
  arrays = []
105
105
 
106
- print(f"Sending to server. Spec is {len(spec_obj_json_gzip_b64)} bytes")
106
+ if verbose:
107
+ print(f"Sending to server. Spec is {len(spec_obj_json_gzip_b64)} bytes")
108
+
107
109
  resp = server._new(spec_obj_json_gzip_b64, sources, filters, arrays, self._fmt)
108
110
  hls_video_url = resp["stream_url"]
109
111
  hls_player_url = resp["player_url"]
@@ -150,7 +152,35 @@ class Spec:
150
152
  else:
151
153
  return hls_player_url
152
154
 
153
- def save(self, server, pth, encoder=None, encoder_opts=None):
155
+ def load(self, server):
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")
160
+
161
+ sources = [
162
+ {
163
+ "name": s._name,
164
+ "path": s._path,
165
+ "stream": s._stream,
166
+ "service": s._service.as_json() if s._service is not None else None,
167
+ }
168
+ for s in sources
169
+ ]
170
+ filters = {
171
+ k: {
172
+ "filter": v._func,
173
+ "args": v._kwargs,
174
+ }
175
+ for k, v in filters.items()
176
+ }
177
+ arrays = []
178
+
179
+ resp = server._new(spec_obj_json_gzip_b64, sources, filters, arrays, self._fmt)
180
+ namespace = resp["namespace"]
181
+ return Loader(server, namespace, self._domain)
182
+
183
+ def save(self, server, pth, encoder=None, encoder_opts=None, format=None):
154
184
  """Save the video to a file."""
155
185
 
156
186
  assert encoder is None or type(encoder) == str
@@ -191,6 +221,7 @@ class Spec:
191
221
  self._fmt,
192
222
  encoder,
193
223
  encoder_opts,
224
+ format,
194
225
  )
195
226
 
196
227
  return resp
@@ -273,6 +304,53 @@ class Spec:
273
304
  return out
274
305
 
275
306
 
307
+ class Loader:
308
+ def __init__(self, server, namespace: str, domain):
309
+ self._server = server
310
+ self._namespace = namespace
311
+ self._domain = domain
312
+
313
+ def _chunk(self, start_i, end_i):
314
+ return self._server._raw(self._namespace, start_i, end_i)
315
+
316
+ def __len__(self):
317
+ return len(self._domain)
318
+
319
+ def _find_index_by_rational(self, value):
320
+ if value not in self._domain:
321
+ raise ValueError(f"Rational timestamp {value} is not in the domain")
322
+ return self._domain.index(value)
323
+
324
+ def __getitem__(self, index):
325
+ if isinstance(index, slice):
326
+ start = index.start if index.start is not None else 0
327
+ end = index.stop if index.stop is not None else len(self._domain)
328
+ assert start >= 0 and start < len(self._domain)
329
+ assert end >= 0 and end <= len(self._domain)
330
+ assert start <= end
331
+ num_frames = end - start
332
+ all_bytes = self._chunk(start, end - 1)
333
+ all_bytes_len = len(all_bytes)
334
+ assert all_bytes_len % num_frames == 0
335
+ return [
336
+ all_bytes[
337
+ i
338
+ * all_bytes_len
339
+ // num_frames : (i + 1)
340
+ * all_bytes_len
341
+ // num_frames
342
+ ]
343
+ for i in range(num_frames)
344
+ ]
345
+ elif isinstance(index, int):
346
+ assert index >= 0 and index < len(self._domain)
347
+ return self._chunk(index, index)
348
+ else:
349
+ raise TypeError(
350
+ "Invalid argument type for iloc. Use a slice or an integer."
351
+ )
352
+
353
+
276
354
  class YrdenServer:
277
355
  """A connection to a Yrden server"""
278
356
 
@@ -340,7 +418,9 @@ class YrdenServer:
340
418
 
341
419
  return r.json()
342
420
 
343
- def _export(self, pth, spec, sources, filters, arrays, fmt, encoder, encoder_opts):
421
+ def _export(
422
+ self, pth, spec, sources, filters, arrays, fmt, encoder, encoder_opts, format
423
+ ):
344
424
  req = {
345
425
  "spec": spec,
346
426
  "sources": sources,
@@ -352,6 +432,7 @@ class YrdenServer:
352
432
  "output_path": pth,
353
433
  "encoder": encoder,
354
434
  "encoder_opts": encoder_opts,
435
+ "format": format,
355
436
  }
356
437
 
357
438
  r = requests.post(f"http://{self._domain}:{self._port}/export", json=req)
@@ -360,6 +441,14 @@ class YrdenServer:
360
441
 
361
442
  return r.json()
362
443
 
444
+ def _raw(self, namespace, start_i, end_i):
445
+ r = requests.get(
446
+ f"http://{self._domain}:{self._port}/{namespace}/raw/{start_i}-{end_i}"
447
+ )
448
+ if not r.ok:
449
+ raise Exception(r.text)
450
+ return r.content
451
+
363
452
  def hls_js_url(self):
364
453
  """Return the link to the yrden-hosted hls.js file"""
365
454
  return f"http://{self._domain}:{self._port}/hls.js"
@@ -440,6 +529,9 @@ class Source:
440
529
  def ts(self):
441
530
  return self._src["ts"]
442
531
 
532
+ def __len__(self):
533
+ return len(self._src["ts"])
534
+
443
535
  def __getitem__(self, idx):
444
536
  if type(idx) != Fraction:
445
537
  raise Exception("Source index must be a Fraction")
File without changes
File without changes