From f7816260055ebc8ae0b5a8a6d2aaf1e30baf7e38 Mon Sep 17 00:00:00 2001 From: Lijun Yu Date: Thu, 30 Jul 2020 15:01:37 -0400 Subject: [PATCH] v1.3 --- README.md | 2 ++ avi_r/reader.py | 44 ++++++++++++++++++++++++++++++++------------ docs/version.md | 4 ++++ setup.py | 2 +- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 24814c8..2265c67 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ for frame in video: image = frame.numpy() # image is an uint8 array in a shape of (height, width, channel[BGR]) # ... Do something with the image +video.close() # Release internal buffers ``` ### Replace `cv2.VideoCapture` @@ -56,6 +57,7 @@ cap = AVIReader(video_path) ``` `AVIReader.read` follows the schema of `cv2.VideoCapture.read` but automatically inserts the missing frames while reading the video. +`AVIReader.release` also follows `cv2.VideoCapture.release`. ### Random Access diff --git a/avi_r/reader.py b/avi_r/reader.py index 4526e42..c050406 100644 --- a/avi_r/reader.py +++ b/avi_r/reader.py @@ -53,7 +53,7 @@ def __init__(self, video_path: str, parent_dir: str = '', '%s@%s' % (__name__, self.path), logging.INFO) av.logging.set_level(av.logging.INFO) self._assert_msg = 'Please open an issue with your video file at ' \ - 'https://github.com/Lijun-Yu/avi-r.' + 'https://github.com/CMU-INF-DIVA/avi-r.' self.fix_missing = fix_missing if not self.fix_missing: self._logger.warning('NOT fixing missing frames.') @@ -211,18 +211,36 @@ def get_at(self, frame_id): def reset(self): """Reset the internal states to load the video from the beginning. """ - if hasattr(self, '_container'): - self._container.close() + self._del() self._init() + def close(self): + """Close the reader and delete internal buffers. + """ + self._del() + + def release(self): + """Following the API of cv2.VideoCapture.release() for consistency + in old codes. + """ + self.close() + def __del__(self): if hasattr(self, '_container'): - self._container.close() + self._del() def _init(self, video_stream_id=0): self._container = av.open(self.path) self._stream = self._container.streams.video[video_stream_id] self._frame_gen = self._get_frame_gen() + self.reorder_buffer = [] + + def _del(self): + self._container.close() + del self._container + del self._stream + del self._frame_gen + del self.reorder_buffer def _get_frame_gen(self, start_frame_id=0, retry=5, retry_step=120): seek_frame_id = start_frame_id @@ -298,18 +316,20 @@ def _fix_missing_one(self, start_frame_id, end_frame_id, src_frame): start_frame_id, end_frame_id) def _reorder(self): - buffer = [] + self.reorder_buffer = [] for frame in self._decode(): if frame.key_frame: - for reordered_frame in sorted(buffer, key=lambda f: f.frame_id): + for reordered_frame in sorted( + self.reorder_buffer, key=lambda f: f.frame_id): yield reordered_frame - buffer = [frame] + self.reorder_buffer = [frame] else: - buffer.append(frame) - assert buffer[0].frame.key_frame - if len(buffer) > 0: - buffer = sorted(buffer, key=lambda f: f.frame_id) - for f in buffer: + self.reorder_buffer.append(frame) + assert self.reorder_buffer[0].frame.key_frame + if len(self.reorder_buffer) > 0: + self.reorder_buffer = sorted( + self.reorder_buffer, key=lambda f: f.frame_id) + for f in self.reorder_buffer: yield f def _decode(self): diff --git a/docs/version.md b/docs/version.md index 347e319..afaed1f 100644 --- a/docs/version.md +++ b/docs/version.md @@ -1,5 +1,9 @@ # Version History +## AVI-R v1.3 + +* Fix memory leak with explicit `close` method. + ## AVI-R v1.2.1 * Update video properties. diff --git a/setup.py b/setup.py index 8228f2d..2557ca9 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='avi-r', - version='1.2.1', + version='1.3', author='Lijun Yu', author_email='lijun@lj-y.com', description='A robust reader for avi videos.',