Skip to content

Commit

Permalink
Add explicit control of video backend opening
Browse files Browse the repository at this point in the history
  • Loading branch information
talmo committed Sep 28, 2024
1 parent f314fe6 commit 8c5bac3
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 4 deletions.
8 changes: 6 additions & 2 deletions sleap_io/io/slp.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ def make_video(
# This is an ImageVideo.
# TODO: Path resolution.
video_path = backend_metadata["filenames"]
video_path = [
Path(Path(p).as_posix().replace("\\", "/")) for p in video_path
]

try:
backend = VideoBackend.from_filename(
Expand All @@ -117,18 +120,19 @@ def make_video(
grayscale=backend_metadata.get("grayscale", None),
input_format=backend_metadata.get("input_format", None),
)
except:
except Exception:
backend = None

return Video(
filename=video_path,
backend=backend,
backend_metadata=backend_metadata,
source_video=source_video,
open_backend=open_backend,
)


def read_videos(labels_path: str, open_backend: bool = False) -> list[Video]:
def read_videos(labels_path: str, open_backend: bool = True) -> list[Video]:
"""Read `Video` dataset in a SLEAP labels file.
Args:
Expand Down
22 changes: 20 additions & 2 deletions sleap_io/model/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ class Video:
information) without having access to the video file itself.
source_video: The source video object if this is a proxy video. This is present
when the video contains an embedded subset of frames from another video.
open_backend: Whether to open the backend when the video is available. If `True`
(the default), the backend will be automatically opened if the video exists.
Set this to `False` when you want to manually open the backend, or when the
you know the video file does not exist and you want to avoid trying to open
the file.
Notes:
Instances of this class are hashed by identity, not by value. This means that
Expand All @@ -47,12 +52,13 @@ class Video:
backend: Optional[VideoBackend] = None
backend_metadata: dict[str, any] = attrs.field(factory=dict)
source_video: Optional[Video] = None
open_backend: bool = True

EXTS = MediaVideo.EXTS + HDF5Video.EXTS + ImageVideo.EXTS

def __attrs_post_init__(self):
"""Post init syntactic sugar."""
if self.backend is None and self.exists():
if self.open_backend and self.backend is None and self.exists():
self.open()

@classmethod
Expand Down Expand Up @@ -181,7 +187,13 @@ def __getitem__(self, inds: int | list[int] | slice) -> np.ndarray:
See also: VideoBackend.get_frame, VideoBackend.get_frames
"""
if not self.is_open:
self.open()
if self.open_backend:
self.open()
else:
raise ValueError(
"Video backend is not open. Call video.open() or set "
"video.open_backend to True to do automatically on frame read."
)
return self.backend[inds]

def exists(self, check_all: bool = False) -> bool:
Expand All @@ -208,13 +220,16 @@ def is_open(self) -> bool:

def open(
self,
filename: Optional[str] = None,
dataset: Optional[str] = None,
grayscale: Optional[str] = None,
keep_open: bool = True,
):
"""Open the video backend for reading.
Args:
filename: Filename to open. If not specified, will use the filename set on
the video object.
dataset: Name of dataset in HDF5 file.
grayscale: Whether to force grayscale. If None, autodetect on first frame
load.
Expand All @@ -231,6 +246,9 @@ def open(
Values for the HDF5 dataset and grayscale will be remembered if not
specified.
"""
if self.filename:
self.replace_filename(filename, open=False)

if not self.exists():
raise FileNotFoundError(f"Video file not found: {self.filename}")

Expand Down
9 changes: 9 additions & 0 deletions tests/io/test_slp.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,3 +354,12 @@ def test_embed_two_rounds(tmpdir, slp_real_data):
== "tests/data/videos/centered_pair_low_quality.mp4"
)
assert type(labels3.video.backend) == MediaVideo


def test_lazy_video_read(slp_real_data):
labels = read_labels(slp_real_data)
assert type(labels.video.backend) == MediaVideo
assert labels.video.exists()

labels = read_labels(slp_real_data, open_videos=False)
assert labels.video.backend is None

0 comments on commit 8c5bac3

Please sign in to comment.