'Terminal text becomes invisible after terminating subprocess
After terminating an ffmpeg subprocess, the terminal gets messed up - typed characters are invisible! The input still works in that commands can be executed, but keyboard input is not echoed to the terminal.
Issuing shell command reset puts everything back to normal (or !reset from within ipython), so a workaround the issue is calling os.system('reset') inside the script.
Other things I've tried: import curses; curses.initscr() before spawning the subprocess and curses.endwin() after termination, which worked somewhat but broke other stuff. Another possibly related issue is that after spawning the child process, the interactive terminal becomes laggy and sometimes fails to capture typed characters.
The code to spawn the process looks like:
with open('/tmp/stdout.log', 'w') as o:
with open('/tmp/stderr.log', 'w') as e:
proc = subprocess.Popen([args], stdout=o, stderr=e)
And later to stop it:
proc.terminate()
proc.communicate()
What could be going wrong here?
Solution 1:[1]
As stated in this answer, ffmpeg expects data from stdin. You can run ffmpeg with the -nostdin flag and it will keep your terminal from hiding keystrokes.
Solution 2:[2]
do you communicate with the subprocess? in that case i would use pexpect which makes that type of setup very simple, perhaps you must wait for the command to finish? i.e.
p = subprocess.Popen(argv, stdout=o, stderr=e)
p.wait()
if p.returncode != 0:
print("problems")
that's what i use on a dvd2h264 script i wrote a while back, never had any problems with it, but i don't redirect stdin/stderr to tmpfiles..
Solution 3:[3]
os.system('stty sane') worked for me. It reset settings making echo invisible.
Solution 4:[4]
How about:
try:
p = subprocess.Popen(argv, stdout=o, stderr=e)
except KeyboardInterrupt:
p.send_signal(signal.SIGINT)
p.wait()
Solution 5:[5]
10 years later, and just ran into the same problem (Mac, Python 3.8.2).
Per this SO answer, I switched to using Popen as a context manager, and this ensured that ffmpeg was correctly releasing any of its handles.
def raw_start_times(in_filename, silence_threshold, silence_duration, start_ms = 0, end_ms = 200 * 1000):
"""Given an in_filename, find possible split points (phrase start
times) using ffmpeg.
Note that potential phrase start times are actually when any
silence in the clip *ends*.
"""
timematch = r'(?P<deltafromstart>[0-9]+(\.?[0-9]*))'
end_re = re.compile(f'silence_end: {timematch} ')
# The time returned is the deltafromstart; i.e., the actual
# time is the start_ms + the delta.
def time_ms(m):
return start_ms + round(float(m.group('deltafromstart')) * 1000)
# ffmpeg outputs e.g. "silence_end: 123.234" to stderr.
def add_if_matches_end_re(line, arr):
s = line.decode('utf-8').strip()
end_match = end_re.search(s)
if end_match:
arr.append(time_ms(end_match))
ffmpegcmd = (
ffmpeg
.input(in_filename, ss=(start_ms/1000.0), t=(end_ms-start_ms)/1000.0)
.filter('silencedetect', n='{}dB'.format(silence_threshold), d=silence_duration)
.output('-', format='null')
.compile()
) + ['-nostats'] # FIXME: use .nostats() once it's implemented in ffmpeg-python.
logger.debug(f'Running command: {subprocess.list2cmdline(ffmpegcmd)}')
chunk_starts = [start_ms]
with subprocess.Popen(
ffmpegcmd,
stderr=subprocess.PIPE,
stdout = subprocess.PIPE) as p:
for line in p.stderr:
add_if_matches_end_re(line, chunk_starts)
return chunk_starts
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ian Hunter |
| Solution 2 | bjarneh |
| Solution 3 | Quentin Engles |
| Solution 4 | ruanhao |
| Solution 5 |
