numpyimage 3.1.0__tar.gz → 3.1.2__tar.gz
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.
- {numpyimage-3.1.0/numpyimage.egg-info → numpyimage-3.1.2}/PKG-INFO +1 -1
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/vidio.py +24 -14
- {numpyimage-3.1.0 → numpyimage-3.1.2/numpyimage.egg-info}/PKG-INFO +1 -1
- {numpyimage-3.1.0 → numpyimage-3.1.2}/pyproject.toml +1 -1
- {numpyimage-3.1.0 → numpyimage-3.1.2}/LICENSE +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/README.md +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/__init__.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/align.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/graphics.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/imageio.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/nrrd_utils.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/operations.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/npimage/utils.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/numpyimage.egg-info/SOURCES.txt +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/numpyimage.egg-info/dependency_links.txt +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/numpyimage.egg-info/requires.txt +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/numpyimage.egg-info/top_level.txt +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/setup.cfg +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/tests/test_heic.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/tests/test_pbm.py +0 -0
- {numpyimage-3.1.0 → numpyimage-3.1.2}/tests/test_video_writers.py +0 -0
|
@@ -202,14 +202,14 @@ class VideoStreamer:
|
|
|
202
202
|
frames_pts = []
|
|
203
203
|
# Fallback to ffprobe if PyAV didn't work
|
|
204
204
|
cmd = ['ffprobe',
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
'-select_streams', 'v:0',
|
|
206
|
+
'-show_frames',
|
|
207
|
+
'-show_entries', 'frame=pts',
|
|
208
|
+
'-of', 'default=noprint_wrappers=1:nokey=1',
|
|
209
|
+
'-v', 'quiet',
|
|
210
|
+
self.filename]
|
|
211
211
|
ffprobe_result = subprocess.run(cmd, stdout=subprocess.PIPE,
|
|
212
|
-
|
|
212
|
+
stderr=subprocess.PIPE, text=True)
|
|
213
213
|
if ffprobe_result.returncode != 0:
|
|
214
214
|
raise RuntimeError(f'ffprobe failed: {ffprobe_result.stderr}')
|
|
215
215
|
|
|
@@ -377,10 +377,12 @@ class VideoStreamer:
|
|
|
377
377
|
self._current_frame_number = frame_number
|
|
378
378
|
return frame
|
|
379
379
|
if frame.pts > target_pts:
|
|
380
|
+
self._current_frame_number = self.pts_to_frame_number(frame.pts)
|
|
380
381
|
raise RuntimeError(f'Frame with PTS {target_pts} not found after'
|
|
381
382
|
f' seeking – current frame PTS: {frame.pts}')
|
|
382
|
-
raise RuntimeError('
|
|
383
|
-
f'
|
|
383
|
+
raise RuntimeError('Hit end of video before finding frame {frame_number} (PTS '
|
|
384
|
+
f'{target_pts}). Last seen frame was {self._current_frame_number}'
|
|
385
|
+
f' (PTS {self.frame_number_to_pts(self._current_frame_number)}')
|
|
384
386
|
|
|
385
387
|
if isinstance(frame_number, slice): # Support slicing
|
|
386
388
|
start, stop, step = frame_number.indices(self.n_frames)
|
|
@@ -391,11 +393,14 @@ class VideoStreamer:
|
|
|
391
393
|
or frame_number <= self._current_frame_number
|
|
392
394
|
or frame_number > self._current_frame_number + 100):
|
|
393
395
|
target_pts = self.frame_number_to_pts(frame_number)
|
|
396
|
+
if self.verbose:
|
|
397
|
+
print(f'Seeking to frame {frame_number} (PTS {target_pts})')
|
|
394
398
|
# The following actually seeks to the closest keyframe before
|
|
395
399
|
# target_pts, because it's not possible to seek directly to
|
|
396
400
|
# non-keyframes due to video files being compressed.
|
|
397
401
|
self.container.seek(target_pts, any_frame=False,
|
|
398
402
|
backward=True, stream=self.stream)
|
|
403
|
+
self._frame_iterator = self.container.decode(self.stream)
|
|
399
404
|
# Now we decode frames forward until we get to the requested frame
|
|
400
405
|
image = decode_until(frame_number)
|
|
401
406
|
if self.rotation not in [None, '0', 0]:
|
|
@@ -649,6 +654,8 @@ class FFmpegVideoWriter:
|
|
|
649
654
|
command = [
|
|
650
655
|
'ffmpeg',
|
|
651
656
|
'-hide_banner',
|
|
657
|
+
'-loglevel', 'error',
|
|
658
|
+
'-nostats',
|
|
652
659
|
'-y', # Overwrite output
|
|
653
660
|
'-f', 'rawvideo',
|
|
654
661
|
'-vcodec', 'rawvideo',
|
|
@@ -714,8 +721,8 @@ class FFmpegVideoWriter:
|
|
|
714
721
|
|
|
715
722
|
# Validate frame dimensions
|
|
716
723
|
if (width, height) != (self._width, self._height):
|
|
717
|
-
raise ValueError(f'
|
|
718
|
-
f'
|
|
724
|
+
raise ValueError(f'Cannot write image of size (w={width}, h={height}) to video'
|
|
725
|
+
f' already containing images of size {(self._width, self._height)}')
|
|
719
726
|
|
|
720
727
|
# Convert frame to bytes and write to FFmpeg
|
|
721
728
|
frame_bytes = frame.tobytes()
|
|
@@ -733,12 +740,13 @@ class FFmpegVideoWriter:
|
|
|
733
740
|
|
|
734
741
|
# Wait for FFmpeg to finish
|
|
735
742
|
if self._process:
|
|
743
|
+
stderr_data = self._process.stderr.read()
|
|
736
744
|
return_code = self._process.wait()
|
|
737
745
|
|
|
738
746
|
# Check for errors
|
|
739
747
|
if return_code != 0:
|
|
740
|
-
|
|
741
|
-
|
|
748
|
+
raise RuntimeError(f'FFmpeg failed with return code {return_code}:'
|
|
749
|
+
f' {stderr_data.decode()}')
|
|
742
750
|
finally:
|
|
743
751
|
# Clean up process references
|
|
744
752
|
self._process = None
|
|
@@ -766,7 +774,7 @@ def save_video(data, filename, time_axis=0, color_axis=None, overwrite=False,
|
|
|
766
774
|
|
|
767
775
|
Parameters
|
|
768
776
|
----------
|
|
769
|
-
data : numpy.ndarray or list of
|
|
777
|
+
data : numpy.ndarray or list of images
|
|
770
778
|
A 3D (grayscale) or 4D (RGB) numpy array of pixel values.
|
|
771
779
|
|
|
772
780
|
filename : str
|
|
@@ -820,6 +828,8 @@ def save_video(data, filename, time_axis=0, color_axis=None, overwrite=False,
|
|
|
820
828
|
raise FileExistsError(f'File {filename} already exists. '
|
|
821
829
|
'Set overwrite=True to overwrite.')
|
|
822
830
|
|
|
831
|
+
if not isinstance(data, np.ndarray):
|
|
832
|
+
data = np.array(data)
|
|
823
833
|
if color_axis is None and data.ndim == 4:
|
|
824
834
|
color_axis = utils.find_channel_axis(data, possible_channel_lengths=3)
|
|
825
835
|
if color_axis is None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|