Reputation: 33
I'am trying to write some code that is reading from stdin and then trims a video with seeking. Thats what I got so far:
def trim():
in_use=io.BytesIO()
process = sp.Popen(shlex.split('ffmpeg -i pipe: -ss 00:00:01.0 -t 00:00:01.4 -c:v libx264 -strict -2 output.mp4'), stdin=sp.PIPE, bufsize=10**8)
# Pipewriter function
pipewriter(in_use,process)
process.wait()
The pipewriter function does look like this:
def pipewriter():
video.seek(0)
for chunk in iter(partial(video.read,1024),b''):
process.stdin.write(chunk)
process.stdin.flush()
process.stdin.close()
The file inside the in_use io.BytesIO object is a valid video and thats not the problem. The output file also does get generatet and trimmed correctly so the function does work. My problem is that because of seeking and trimming the pipewriter function does write the whole video into the pipe. But the ffmpeg process stops after -t 00:00:01.4 seconds so the rest of the video written in stdin leads to an pipe Error
Does somebody got a clean solution for that without try except. I also do have to trim the video as accurate as possible. The current solution does work good for me.
Error:
process.stdin.flush()
BrokenPipeError: [Errno 32] Broken pipe
Upvotes: 1
Views: 2453
Reputation: 5463
Can't you just do this?
def pipewriter(video, process):
video.seek(0)
for chunk in iter(partial(video.read,1024),b''):
if process.poll() is not None:
break
process.stdin.write(chunk)
if process.poll() is None:
process.stdin.flush()
process.stdin.close()
Based on the OP's addendum in the comment below:
Now I want to create n videos with variable length x and variable start point k and variable endpoint p
Maybe this one does the job:
def trim(ss, t ,outfile):
sp.run(f'ffmpeg -i pipe: -ss {ss} -t {t} -c:v libx264 -strict -2 {outfile}'),
stdin=sp.PIPE, input=in_use.getbuffer())
for mp4file, ss, t in [('out1.mp4',ss0,t0),('out2.mp4',ss1,t1),...]:
trim(ss,t,mp4file)
Upvotes: 1
Reputation: 295272
If video
is guaranteed to be a pipe or FIFO, then video.seek(0)
will never do anything useful and can simply be removed. If you're doing something that requires a multi-pass algorithm, you'll want to copy the content out to a regular file.
FIFOs are inherently unseekable; once content has been read from one once it isn't available to read again, so one cannot seek back to the beginning in any meaningful way.
Upvotes: 0
Reputation: 123400
Does somebody got a clean solution for that without try except.
No one has a fundamentally better solution because this is how the backwards propagation of a pipe closure is designed to work in Unix.
Forward propagation happens by a program reading from the closed input pipe, seeing EOF, wrapping up, and closing its output pipe (if any).
Backwards propagation happens by a program writing to the closed pipe and (by default) receiving a SIGPIPE that kills it, causing any open input pipes to be closed. Programs can choose to ignore SIGPIPE and instead handle the EPIPE exit code itself which Python uses to raise an Error in its place.
All APIs layered on top, like subprocess.communicate
, simply work with this fact under the hood. The best practice is to stop fighting Python and Unix, and just go with the flow using a try-catch (optionally tidied away in a helper function).
However, if you really want a cosmetically cleaner version without try-catch, there are several bad practices you can invoke, such as disabling Python's default signal handler:
import signal
signal.signal(signal.SIGPIPE, signal.SIG_DFL);
This will cause the Python process to immediately and silently be killed instead, which is how most programs in pipelines are stopped, such as find
in find / | head -n 1
Upvotes: 3