"""RouteFrameReader indexes and reads frames across routes, by frameId or segment indices.""" from tools.lib.framereader import FrameReader class _FrameReaderDict(dict): def __init__(self, camera_paths, cache_paths, framereader_kwargs, *args, **kwargs): super(_FrameReaderDict, self).__init__(*args, **kwargs) if cache_paths is None: cache_paths = {} if not isinstance(cache_paths, dict): cache_paths = {k: v for k, v in enumerate(cache_paths)} self._camera_paths = camera_paths self._cache_paths = cache_paths self._framereader_kwargs = framereader_kwargs def __missing__(self, key): if key < len(self._camera_paths) and self._camera_paths[key] is not None: frame_reader = FrameReader(self._camera_paths[key], self._cache_paths.get(key), **self._framereader_kwargs) self[key] = frame_reader return frame_reader else: raise KeyError("Segment index out of bounds: {}".format(key)) class RouteFrameReader(object): """Reads frames across routes and route segments by frameId.""" def __init__(self, camera_paths, cache_paths, frame_id_lookup, **kwargs): """Create a route framereader. Inputs: TODO kwargs: Forwarded to the FrameReader function. If cache_prefix is included, that path will also be used for frame position indices. """ self._first_camera_idx = next(i for i in range(len(camera_paths)) if camera_paths[i] is not None) self._frame_readers = _FrameReaderDict(camera_paths, cache_paths, kwargs) self._frame_id_lookup = frame_id_lookup @property def w(self): """Width of each frame in pixels.""" return self._frame_readers[self._first_camera_idx].w @property def h(self): """Height of each frame in pixels.""" return self._frame_readers[self._first_camera_idx].h def get(self, frame_id, **kwargs): """Get a frame for a route based on frameId. Inputs: frame_id: The frameId of the returned frame. kwargs: Forwarded to BaseFrameReader.get. "count" is not implemented. """ segment_num, segment_id = self._frame_id_lookup.get(frame_id, (None, None)) if segment_num is None or segment_num == -1 or segment_id == -1: return None else: return self.get_from_segment(segment_num, segment_id, **kwargs) def get_from_segment(self, segment_num, segment_id, **kwargs): """Get a frame from a specific segment with a specific index in that segment (segment_id). Inputs: segment_num: The number of the segment. segment_id: The index of the return frame within that segment. kwargs: Forwarded to BaseFrameReader.get. "count" is not implemented. """ if "count" in kwargs: raise NotImplementedError("count") return self._frame_readers[segment_num].get(segment_id, **kwargs)[0] def close(self): frs = self._frame_readers self._frame_readers.clear() for fr in frs: fr.close() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.close()