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
Reading specific frames from a video
python - ffmpeg stdin Pipe seeking - Stack Overflow
Formula to get frame display number after seek in FFmpeg - Stack Overflow
I've DOUBLED the FFmpeg Speed!
Videos
» pip install ffmpeg-python
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
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)
This seems like an X/Y problem, so I'll propose several different commands:
List of timestamps
If you want to output a list of timestamps for each keyframe:
ffprobe -v error -skip_frame nokey -show_entries frame=pkt_pts_time -select_streams v -of csv=p=0 input
0.000000
2.502000
3.795000
6.131000
10.344000
12.554000
Note the -skip_frame nokey.
select filter
Another method is to use the select filter with the scene option to output your thumbnails:
ffmpeg -i input -vf "select=gt'(scene,0.4)',scale=160:-1" -vsync vfr %04d.png
This will output all the i frames as PNG images.
ffmpeg -i 2.flv -vf "select=eq(pict_type\,I)" -vsync vfr frame-%02d.png
Credit to this comment a similar superuser.com question. How to extract all key frames from a video clip?
Hope that helps. Cheers.
Ian
with ffmpeg you can use - as input/output file name to indicate that it should read the data from stdin / write to stdout.
Then you can use the stdin/stdout arguments of Popen to read/write your data.
an example:
Copyfrom subprocess import Popen, PIPE
with open("test.avi", "rb") as infile:
p=Popen(["ffmpeg", "-i", "-", "-f", "matroska", "-vcodec", "mpeg4",
"-acodec", "aac", "-strict", "experimental", "-"],
stdin=infile, stdout=PIPE)
while True:
data = p.stdout.read(1024)
if len(data) == 0:
break
# do something with data...
print(data)
print p.wait() # should have finisted anyway
instead you supplying a file for stdin you could also use a PIPE and write directly to the processes input stream (p.stdin). or in your case you would simply use wavfile...
note that you have to specify the output format and codecs explicitly, as ffmpeg can't guess them from the file extension as it usually does.
and it will only work for muxers that don't need seekable output streams, but flac should work...
For anyone still reading this:
This can be done without subprocesses by using FFMPEG's pipe protocol instead.
If FFMPEG is called using the package ffmpeg-python, the stdout, stderr output of the FFMPEG command can be fed into Python variables as seen here:
Copyout, err = inpstream.output('pipe:', ... ).run(capture_stdout=True)
So, I'm trying to split an almost three hour long three video file into shorter files. I was originally doing so with a video editor, but this would require to re encode the video and take quite a very long time. However, I do have the specific length of the splits in frames, and I managed to create a single file like this:
ffmpeg -ss 00:00:00 -i "file.avi" -c:v copy -c:a copy -frames:v 88705 "file split 01.avi"
What I would like to do next is to set the seek function to an specific frame as the beginning to cut the video with precision. How can I do this?
From a brief look at FFMPY, you could do this using ffmpy.FFmpeg, as that allows any and all FFMPEG command line options, including -f. -- Click the link for documentation.
You could do the FFMPEG command with os.system. You'll need to import OS anyway to iterate through the files.
You would need to iterate through all the files in a directory though. This would be the more challenging bit, it's quite easy with a for loop though.
for filename in os.listdir(path):
if (filename.endswith(".mp4")): #or .avi, .mpeg, whatever.
os.system("ffmpeg -i {0} -f image2 -vf fps=fps=1 output%d.png".format(filename))
else:
continue
The above code iterates through the directory at path, and uses command prompt to execute your given FFMPEG command, using the filename (if it's a video file) in place of mymovie.avi
Dont have reputation to comment, hence adding another response.
Another version of ocelot's answer with the more readable f-string syntax of python -
for filename in os.listdir(path):
if (filename.endswith(".mp4")): #or .avi, .mpeg, whatever.
os.system(f'ffmpeg -i {filename} -f image2 -vf fps=fps=1 output%d.png')
else:
continue