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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpyimage
3
- Version: 3.1.0
3
+ Version: 3.1.2
4
4
  Summary: Load, save, & manipulate image files as numpy arrays
5
5
  Author-email: Jasper Phelps <jasper.s.phelps@gmail.com>
6
6
  License: MIT License
@@ -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
- '-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]
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
- stderr=subprocess.PIPE, text=True)
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('Ran out of frames before finding frame with requested'
383
- f' PTS {target_pts} current frame PTS: {frame.pts}')
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'Frame dimensions {(width, height)} do not match '
718
- f'initial dimensions {(self._width, self._height)}')
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
- stderr_output = self._process.stderr.read().decode()
741
- raise RuntimeError(f'FFmpeg failed with return code {return_code}: {stderr_output}')
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 filenames
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpyimage
3
- Version: 3.1.0
3
+ Version: 3.1.2
4
4
  Summary: Load, save, & manipulate image files as numpy arrays
5
5
  Author-email: Jasper Phelps <jasper.s.phelps@gmail.com>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'numpyimage'
7
- version = '3.1.0'
7
+ version = '3.1.2'
8
8
  description = 'Load, save, & manipulate image files as numpy arrays'
9
9
  readme.file = 'README.md'
10
10
  readme.content-type = 'text/markdown'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes