vidformer 0.12.0__py3-none-any.whl → 1.0.1__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.
vidformer/cv2/__init__.py CHANGED
@@ -19,10 +19,10 @@ except Exception:
19
19
  _opencv2 = None
20
20
 
21
21
  import re
22
- import uuid
23
22
  import zlib
24
23
  from bisect import bisect_right
25
24
  from fractions import Fraction
25
+ import os
26
26
 
27
27
  import numpy as np
28
28
 
@@ -80,21 +80,36 @@ _global_cv2_server = None
80
80
  def _server():
81
81
  global _global_cv2_server
82
82
  if _global_cv2_server is None:
83
- _global_cv2_server = vf.YrdenServer()
83
+ if "VF_IGNI_ENDPOINT" in os.environ:
84
+ server_endpoint = os.environ["VF_IGNI_ENDPOINT"]
85
+ if "VF_IGNI_API_KEY" not in os.environ:
86
+ raise Exception("VF_IGNI_API_KEY must be set")
87
+ api_key = os.environ["VF_IGNI_API_KEY"]
88
+ _global_cv2_server = vf.Server(server_endpoint, api_key)
89
+ else:
90
+ raise Exception(
91
+ "No server set for the cv2 frontend. Set VF_IGNI_ENDPOINT and VF_IGNI_API_KEY environment variables or use cv2.set_server() before use."
92
+ )
84
93
  return _global_cv2_server
85
94
 
86
95
 
87
96
  def set_server(server):
88
97
  """Set the server to use for the cv2 frontend."""
89
98
  global _global_cv2_server
90
- assert isinstance(server, vf.YrdenServer) or isinstance(server, vf.IgniServer)
99
+ assert isinstance(server, vf.Server)
91
100
  _global_cv2_server = server
92
101
 
93
102
 
103
+ def get_server():
104
+ """Get the server used by the cv2 frontend."""
105
+ return _server()
106
+
107
+
94
108
  _PIX_FMT_MAP = {
95
109
  "rgb24": "rgb24",
96
110
  "yuv420p": "rgb24",
97
111
  "yuv422p": "rgb24",
112
+ "yuv422p10le": "rgb24",
98
113
  "yuv444p": "rgb24",
99
114
  "yuvj420p": "rgb24",
100
115
  "yuvj422p": "rgb24",
@@ -149,28 +164,16 @@ class Frame:
149
164
 
150
165
  self._mut()
151
166
  server = _server()
152
- if type(server) is vf.YrdenServer:
153
- spec = vf.YrdenSpec([Fraction(0, 1)], lambda t, i: self._f, self._fmt)
154
- loader = spec.load(_server())
155
-
156
- frame_raster_rgb24 = loader[0]
157
- assert type(frame_raster_rgb24) is bytes
158
- assert len(frame_raster_rgb24) == self.shape[0] * self.shape[1] * 3
159
- raw_data_array = np.frombuffer(frame_raster_rgb24, dtype=np.uint8)
160
- frame = raw_data_array.reshape(self.shape)
167
+ frame = server.frame(
168
+ self.shape[1], self.shape[0], self._fmt["pix_fmt"], self._f
169
+ )
170
+ assert type(frame) is bytes
171
+ assert len(frame) == self.shape[0] * self.shape[1] * self.shape[2]
172
+ raw_data_array = np.frombuffer(frame, dtype=np.uint8)
173
+ frame = raw_data_array.reshape(self.shape)
174
+ if self.shape[2] == 3:
161
175
  frame = frame[:, :, ::-1] # convert RGB to BGR
162
- return frame
163
- else:
164
- frame = server.frame(
165
- self.shape[1], self.shape[0], self._fmt["pix_fmt"], self._f
166
- )
167
- assert type(frame) is bytes
168
- assert len(frame) == self.shape[0] * self.shape[1] * self.shape[2]
169
- raw_data_array = np.frombuffer(frame, dtype=np.uint8)
170
- frame = raw_data_array.reshape(self.shape)
171
- if self.shape[2] == 3:
172
- frame = frame[:, :, ::-1] # convert RGB to BGR
173
- return frame
176
+ return frame
174
177
 
175
178
  def __getitem__(self, key):
176
179
  if not isinstance(key, tuple):
@@ -316,27 +319,19 @@ class VideoCapture:
316
319
  def __init__(self, path: str):
317
320
  server = _server()
318
321
  if type(path) is str:
319
- if isinstance(server, vf.YrdenServer):
322
+ match = re.match(r"(http|https)://([^/]+)(.*)", path)
323
+ if match is not None:
324
+ endpoint = f"{match.group(1)}://{match.group(2)}"
325
+ path = match.group(3)
326
+ if path.startswith("/"):
327
+ path = path[1:]
320
328
  self._path = path
321
- self._source = vf.YrdenSource(server, str(uuid.uuid4()), path, 0)
329
+ self._source = server.source(path, 0, "http", {"endpoint": endpoint})
322
330
  else:
323
- assert isinstance(server, vf.IgniServer)
324
- match = re.match(r"(http|https)://([^/]+)(.*)", path)
325
- if match is not None:
326
- endpoint = f"{match.group(1)}://{match.group(2)}"
327
- path = match.group(3)
328
- if path.startswith("/"):
329
- path = path[1:]
330
- self._path = path
331
- self._source = server.source(
332
- path, 0, "http", {"endpoint": endpoint}
333
- )
334
- else:
335
- raise Exception(
336
- "Using a VideoCapture source by name only works with http(s) URLs. You need to pass an IgniSource instead."
337
- )
338
- elif isinstance(path, vf.IgniSource):
339
- assert isinstance(server, vf.IgniServer)
331
+ self._path = path
332
+ self._source = server.source(path, 0, "fs", {"root": "."})
333
+ elif isinstance(path, vf.Source):
334
+ assert isinstance(server, vf.Server)
340
335
  self._path = path._name
341
336
  self._source = path
342
337
  self._next_frame_idx = 0
@@ -397,26 +392,6 @@ class VideoCapture:
397
392
 
398
393
 
399
394
  class VideoWriter:
400
- def __init__(self, *args, **kwargs):
401
- server = _server()
402
- if isinstance(server, vf.YrdenServer):
403
- self._writer = _YrdenVideoWriter(*args, **kwargs)
404
- elif isinstance(server, vf.IgniServer):
405
- self._writer = _IgniVideoWriter(*args, **kwargs)
406
- else:
407
- raise Exception("Unsupported server type")
408
-
409
- def write(self, *args, **kwargs):
410
- return self._writer.write(*args, **kwargs)
411
-
412
- def release(self, *args, **kwargs):
413
- return self._writer.release(*args, **kwargs)
414
-
415
- def spec(self, *args, **kwargs):
416
- return self._writer.spec(*args, **kwargs)
417
-
418
-
419
- class _IgniVideoWriter:
420
395
  def __init__(
421
396
  self,
422
397
  path,
@@ -426,14 +401,13 @@ class _IgniVideoWriter:
426
401
  batch_size=1024,
427
402
  compression="gzip",
428
403
  ttl=3600,
404
+ pix_fmt="yuv420p",
429
405
  vod_segment_length=Fraction(2, 1),
430
406
  ):
431
407
  server = _server()
432
- assert isinstance(server, vf.IgniServer)
433
- if path is not None:
434
- raise Exception(
435
- "Igni does not support writing to a file. VideoWriter path must be None"
436
- )
408
+ assert isinstance(server, vf.Server)
409
+ assert path is None or type(path) is str
410
+ self._path = path
437
411
  if isinstance(fps, int):
438
412
  self._f_time = Fraction(1, fps)
439
413
  elif isinstance(fps, Fraction):
@@ -446,7 +420,7 @@ class _IgniVideoWriter:
446
420
  width, height = size
447
421
  assert ttl is None or isinstance(ttl, int)
448
422
  self._spec = server.create_spec(
449
- width, height, "yuv420p", vod_segment_length, 1 / self._f_time, ttl=ttl
423
+ width, height, pix_fmt, vod_segment_length, 1 / self._f_time, ttl=ttl
450
424
  )
451
425
  self._batch_size = batch_size
452
426
  assert compression is None or compression in ["gzip"]
@@ -498,47 +472,9 @@ class _IgniVideoWriter:
498
472
 
499
473
  def release(self):
500
474
  self._flush(True)
501
-
502
-
503
- class _YrdenVideoWriter:
504
- def __init__(self, path, fourcc, fps, size):
505
- assert isinstance(fourcc, VideoWriter_fourcc)
506
- if path is not None and not isinstance(path, str):
507
- raise Exception("path must be a string or None")
508
- self._path = path
509
- self._fourcc = fourcc
510
- self._fps = fps
511
- self._size = size
512
-
513
- self._frames = []
514
- self._pix_fmt = "yuv420p"
515
-
516
- def write(self, frame):
517
- frame = frameify(frame, "frame")
518
-
519
- if frame._fmt["pix_fmt"] != self._pix_fmt:
520
- f_obj = _filter_scale(frame._f, pix_fmt=self._pix_fmt)
521
- self._frames.append(f_obj)
522
- else:
523
- self._frames.append(frame._f)
524
-
525
- def release(self):
526
- if self._path is None:
527
- return
528
-
529
- spec = self.spec()
530
- server = _server()
531
- spec.save(server, self._path)
532
-
533
- def spec(self) -> vf.YrdenSpec:
534
- fmt = {
535
- "width": self._size[0],
536
- "height": self._size[1],
537
- "pix_fmt": self._pix_fmt,
538
- }
539
- domain = _fps_to_ts(self._fps, len(self._frames))
540
- spec = vf.YrdenSpec(domain, lambda t, i: self._frames[i], fmt)
541
- return spec
475
+ if self._path is not None:
476
+ server = _server()
477
+ server.export_spec(self._spec.id(), self._path)
542
478
 
543
479
 
544
480
  class VideoWriter_fourcc:
@@ -570,82 +506,57 @@ def imread(path, *args):
570
506
  assert path.lower().endswith((".jpg", ".jpeg", ".png"))
571
507
  server = _server()
572
508
 
573
- if type(server) is vf.YrdenServer:
574
- source = vf.YrdenSource(server, str(uuid.uuid4()), path, 0)
575
- frame = Frame(source.iloc[0], source.fmt())
576
- return frame
577
- else:
578
- cap = VideoCapture(path)
579
- assert cap.isOpened()
580
- assert len(cap._source) == 1
581
- ret, frame = cap.read()
582
- assert ret
583
- cap.release()
584
- return frame
509
+ cap = VideoCapture(path)
510
+ assert cap.isOpened()
511
+ assert len(cap._source) == 1
512
+ ret, frame = cap.read()
513
+ assert ret
514
+ cap.release()
515
+ return frame
585
516
 
586
517
 
587
518
  def imwrite(path, img, *args):
588
519
  if len(args) > 0:
589
520
  raise NotImplementedError("imwrite does not support additional arguments")
590
521
 
591
- server = _server()
592
- if type(server) is vf.IgniServer:
593
- raise NotImplementedError(
594
- "imwrite is only supported with YrdenServer, not IgniServer"
595
- )
596
-
597
522
  img = frameify(img)
598
-
599
523
  fmt = img._fmt.copy()
600
524
  width = fmt["width"]
601
525
  height = fmt["height"]
602
- f = img._f
603
-
604
- domain = [Fraction(0, 1)]
605
526
 
606
527
  if path.lower().endswith(".png"):
607
- img._mut() # Make sure it's in rgb24
608
- spec = vf.YrdenSpec(
609
- domain,
610
- lambda t, i: img._f,
611
- {"width": width, "height": height, "pix_fmt": "rgb24"},
612
- )
613
- spec.save(_server(), path, encoder="png")
528
+ out_pix_fmt = "rgb24"
529
+ encoder = "png"
614
530
  elif path.lower().endswith((".jpg", ".jpeg")):
615
- if img._modified:
616
- # it's rgb24, we need to convert to something jpeg can handle
617
- f = _filter_scale(img._f, pix_fmt="yuv420p")
618
- fmt["pix_fmt"] = "yuv420p"
531
+ encoder = "mjpeg"
532
+ if img._fmt["pix_fmt"] not in ["yuvj420p", "yuvj422p", "yuvj444p"]:
533
+ out_pix_fmt = "yuvj420p"
619
534
  else:
620
- if fmt["pix_fmt"] not in ["yuvj420p", "yuvj422p", "yuvj444p"]:
621
- f = _filter_scale(img._f, pix_fmt="yuvj420p")
622
- fmt["pix_fmt"] = "yuvj420p"
623
-
624
- spec = vf.YrdenSpec(domain, lambda t, i: f, fmt)
625
- spec.save(server, path, encoder="mjpeg")
535
+ out_pix_fmt = img._fmt["pix_fmt"]
626
536
  else:
627
537
  raise Exception("Unsupported image format")
628
538
 
539
+ if img._fmt["pix_fmt"] != out_pix_fmt:
540
+ f = _filter_scale(img._f, pix_fmt=out_pix_fmt)
541
+ img = Frame(f, {"width": width, "height": height, "pix_fmt": out_pix_fmt})
542
+
543
+ writer = VideoWriter(None, None, 1, (width, height), pix_fmt=out_pix_fmt)
544
+ writer.write(img)
545
+ writer.release()
546
+
547
+ spec = writer.spec()
548
+ server = _server()
549
+ server.export_spec(spec.id(), path, encoder=encoder)
550
+
629
551
 
630
- def vidplay(video, *args, **kwargs):
552
+ def vidplay(video, method="html"):
631
553
  """
632
554
  Play a vidformer video specification.
633
-
634
- Args:
635
- video: one of [vidformer.Spec, vidformer.Source, vidformer.cv2.VideoWriter]
636
555
  """
637
- if isinstance(video, vf.YrdenSpec):
638
- return video.play(_server(), *args, **kwargs)
639
- elif isinstance(video, vf.YrdenSource):
640
- return video.play(_server(), *args, **kwargs)
641
- elif isinstance(video, VideoWriter):
642
- return vidplay(video._writer, *args, **kwargs)
643
- elif isinstance(video, _YrdenVideoWriter):
644
- return video.spec().play(_server(), *args, **kwargs)
645
- elif isinstance(video, _IgniVideoWriter):
646
- return video._spec.play(*args, **kwargs)
647
- elif isinstance(video, vf.IgniSpec):
648
- return video.play(*args, **kwargs)
556
+ if isinstance(video, VideoWriter):
557
+ return video.spec().play(method=method)
558
+ elif isinstance(video, vf.Spec):
559
+ return video.play(method=method)
649
560
  else:
650
561
  raise Exception("Unsupported video type to vidplay")
651
562
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vidformer
3
- Version: 0.12.0
3
+ Version: 1.0.1
4
4
  Summary: vidformer-py is a Python 🐍 interface for [vidformer](https://github.com/ixlab/vidformer).
5
5
  Author-email: Dominik Winecki <dominikwinecki@gmail.com>
6
6
  Requires-Python: >=3.8
@@ -8,7 +8,6 @@ Description-Content-Type: text/markdown
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Operating System :: OS Independent
10
10
  Requires-Dist: requests
11
- Requires-Dist: msgpack
12
11
  Requires-Dist: numpy
13
12
  Project-URL: Documentation, https://ixlab.github.io/vidformer/vidformer-py/
14
13
  Project-URL: Homepage, https://ixlab.github.io/vidformer/
@@ -0,0 +1,6 @@
1
+ vidformer/__init__.py,sha256=lTnRzfqleuEwb_mG4E0OZ1PgQ-8hUHiASERi_eXPiJc,29972
2
+ vidformer/cv2/__init__.py,sha256=cgnomW6xV7Ho7cCgbuw5EfS_2JJBmAwIyt-_gmtUTyY,26829
3
+ vidformer/supervision/__init__.py,sha256=dRHAcHiZN68gUH_2m3o7Ohsv3NBGxF4XGPeI0pn2_K4,20346
4
+ vidformer-1.0.1.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
5
+ vidformer-1.0.1.dist-info/METADATA,sha256=bw_C4C9EeVhsHDVywkyTwoTHPCiHJe6w3BJsWgvyAqI,1776
6
+ vidformer-1.0.1.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- vidformer/__init__.py,sha256=2_IA8eCF8xIWqgdcpC06CSEsX_b2DPpOww3tuQlY3rg,55692
2
- vidformer/cv2/__init__.py,sha256=cp1qJPpxpRGCE3elmoHDxhzafZbopZ9wIkKcZJJI8HM,30105
3
- vidformer/supervision/__init__.py,sha256=dRHAcHiZN68gUH_2m3o7Ohsv3NBGxF4XGPeI0pn2_K4,20346
4
- vidformer-0.12.0.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
5
- vidformer-0.12.0.dist-info/METADATA,sha256=C3OsKiJjYPCgiUblJUan2-aQG5TOprdCn2cduqJBow0,1800
6
- vidformer-0.12.0.dist-info/RECORD,,