mirror of
https://github.com/iperov/DeepFaceLive
synced 2025-07-16 10:03:42 -07:00
fix ffmpeg and FileSource error handling.
This commit is contained in:
parent
552b9d49f2
commit
e1aa8a82f1
6 changed files with 51 additions and 59 deletions
|
@ -14,13 +14,12 @@ class FramePlayer(Disposable):
|
|||
class Frame:
|
||||
__slots__ = ['image','timestamp','fps','frame_num','frame_count','name','error']
|
||||
|
||||
image : np.ndarray # if none - error during loading frame
|
||||
image : np.ndarray
|
||||
timestamp : float
|
||||
fps : float
|
||||
frame_num : int
|
||||
frame_count : int
|
||||
name : str
|
||||
error : str
|
||||
|
||||
def __init__(self):
|
||||
self.image = None
|
||||
|
@ -29,7 +28,6 @@ class FramePlayer(Disposable):
|
|||
self.frame_num = None
|
||||
self.frame_count = None
|
||||
self.name = None
|
||||
self.error = None
|
||||
|
||||
def __init__(self, default_fps, frame_count):
|
||||
if frame_count == 0:
|
||||
|
@ -142,12 +140,13 @@ class FramePlayer(Disposable):
|
|||
self._req_is_playing = False
|
||||
|
||||
class ProcessResult:
|
||||
__slots__ = ['new_is_playing','new_frame_idx','new_frame']
|
||||
__slots__ = ['new_is_playing','new_frame_idx','new_frame','new_error']
|
||||
|
||||
def __init__(self):
|
||||
self.new_is_playing = None
|
||||
self.new_frame_idx = None
|
||||
self.new_frame = None
|
||||
self.new_error : str = None
|
||||
|
||||
def process(self) -> 'FramePlayer.ProcessResult':
|
||||
"""
|
||||
|
@ -225,19 +224,11 @@ class FramePlayer(Disposable):
|
|||
update_frame = True
|
||||
|
||||
if update_frame:
|
||||
|
||||
# Frame changed, construct Frame() with current values
|
||||
_frame_idx = self._frame_idx
|
||||
_cached_frames = self._cached_frames
|
||||
_cached_frames_idxs = self._cached_frames_idxs
|
||||
|
||||
p_frame = result.new_frame = FramePlayer.Frame()
|
||||
p_frame.fps = fps
|
||||
p_frame.timestamp = self._frame_timestamp
|
||||
|
||||
p_frame.frame_num = _frame_idx
|
||||
p_frame.frame_count = self._frame_count
|
||||
|
||||
frame_tuple = _cached_frames.get(_frame_idx, None)
|
||||
if frame_tuple is None:
|
||||
frame_tuple = self._on_get_frame(_frame_idx)
|
||||
|
@ -249,11 +240,18 @@ class FramePlayer(Disposable):
|
|||
frame_image, name_or_err = frame_tuple
|
||||
|
||||
if frame_image is None:
|
||||
# frame is not provided, stop playing, but return p_frame without an image
|
||||
# frame is not provided, stop playing
|
||||
new_is_playing = False
|
||||
p_frame.error = name_or_err
|
||||
result.new_error = name_or_err
|
||||
else:
|
||||
# frame is provided.
|
||||
p_frame = result.new_frame = FramePlayer.Frame()
|
||||
p_frame.fps = fps
|
||||
p_frame.timestamp = self._frame_timestamp
|
||||
|
||||
p_frame.frame_num = _frame_idx
|
||||
p_frame.frame_count = self._frame_count
|
||||
|
||||
ip = ImageProcessor(frame_image)
|
||||
if self._target_width != 0:
|
||||
ip.fit_in(TW=self._target_width)
|
||||
|
@ -262,7 +260,6 @@ class FramePlayer(Disposable):
|
|||
p_frame.image = frame_image
|
||||
p_frame.name = name_or_err
|
||||
|
||||
|
||||
if new_is_playing is not None and self._is_playing and not new_is_playing:
|
||||
# Stop playing
|
||||
result.new_is_playing = self._is_playing = False
|
||||
|
|
|
@ -50,16 +50,13 @@ class VideoFilePlayer(FramePlayer):
|
|||
|
||||
probe_info = lib_ffmpeg.probe (str(filepath))
|
||||
# Analize probe_info
|
||||
stream_idx = None
|
||||
stream_v_idx = None
|
||||
stream_fps = None
|
||||
stream_width = None
|
||||
stream_height = None
|
||||
for stream in probe_info['streams']:
|
||||
if stream_idx is None and stream['codec_type'] == 'video':
|
||||
#print(stream)
|
||||
stream_idx = stream.get('index',None)
|
||||
if stream_idx is not None:
|
||||
stream_idx = int(stream_idx)
|
||||
if stream_v_idx is None and stream['codec_type'] == 'video':
|
||||
stream_v_idx = 0
|
||||
stream_width = stream.get('width', None)
|
||||
if stream_width is not None:
|
||||
stream_width = int(stream_width)
|
||||
|
@ -75,12 +72,12 @@ class VideoFilePlayer(FramePlayer):
|
|||
stream_fps = eval(stream_fps)
|
||||
break
|
||||
|
||||
if any( x is None for x in [stream_idx, stream_width, stream_height, stream_start_time, stream_duration, stream_fps] ):
|
||||
if any( x is None for x in [stream_v_idx, stream_width, stream_height, stream_start_time, stream_duration, stream_fps] ):
|
||||
raise Exception(f'Incorrect video file.')
|
||||
|
||||
stream_frame_count = round( ( float(stream_duration)-float(stream_start_time) ) / (1.0/stream_fps) )
|
||||
|
||||
self._stream_idx = stream_idx
|
||||
self._stream_idx = stream_v_idx
|
||||
self._stream_width = stream_width
|
||||
self._stream_height = stream_height
|
||||
self._stream_fps = stream_fps
|
||||
|
@ -128,7 +125,7 @@ class VideoFilePlayer(FramePlayer):
|
|||
'-map', f'0:v:{self._stream_idx}',
|
||||
'pipe:']
|
||||
|
||||
self._ffmpeg_proc = lib_ffmpeg.run (args, pipe_stdout=True, quiet_std_err=True)
|
||||
self._ffmpeg_proc = lib_ffmpeg.run (args, pipe_stdout=True, pipe_stderr=True)
|
||||
return self._ffmpeg_proc is not None
|
||||
|
||||
def _ffmpeg_next_frame(self, frames_idx_offset=1):
|
||||
|
@ -137,15 +134,20 @@ class VideoFilePlayer(FramePlayer):
|
|||
while frames_idx_offset != 0:
|
||||
frame_buffer = self._ffmpeg_proc.stdout.read(self._ffmpeg_height*self._ffmpeg_width*3)
|
||||
if len(frame_buffer) == 0:
|
||||
err = self._ffmpeg_proc.stderr.read()
|
||||
err_lines = err.decode('utf-8').split('\r\n')
|
||||
err = '\r\n'.join(err_lines[-5:])
|
||||
|
||||
# End reached
|
||||
self._ffmpeg_stop()
|
||||
return None
|
||||
|
||||
return None, err
|
||||
frames_idx_offset -= 1
|
||||
|
||||
if frame_buffer is not None:
|
||||
frame_image = np.ndarray( (self._ffmpeg_height, self._ffmpeg_width, 3), dtype=np.uint8, buffer=frame_buffer).copy()
|
||||
return frame_image
|
||||
return None
|
||||
return frame_image, None
|
||||
return None, None
|
||||
|
||||
def _on_target_width_changed(self):
|
||||
self._ffmpeg_need_restart = True
|
||||
|
@ -168,9 +170,9 @@ class VideoFilePlayer(FramePlayer):
|
|||
frame_diff = max(1, frame_diff)
|
||||
|
||||
#frame_diff += 1
|
||||
image = self._ffmpeg_next_frame(frame_diff)
|
||||
image, err = self._ffmpeg_next_frame(frame_diff)
|
||||
if image is None:
|
||||
return (None, 'Unpredicted end of stream.')
|
||||
return (None, f'ffmpeg error: {err}')
|
||||
|
||||
return (image, f'{self._filepath.name}_{idx:06}')
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue