Open ccapizzano opened 1 year ago
I am running into the same issue - have you found a solution for this?
Have you checked this out?
I would try using \\,
or using python's raw string r"not(mod(n\,300))"
.
I didn't test this, it's just a test for you to try :)
Thanks,! Yes, I tried that. Getting rid of the backslash altogether actually does seem to work. I am copy+pasting my current def for reference below. I am not sure I understand all the details. The vsync='vfr'
is / seems to be important to dial down the frame rate / not replicate frames that have been skipped.
def trim_video(input_file, output_file, start, end, to_skip=100):
'''
Trim an input video file to start / end
and take only a subset of the original frames
'''
filter_string = f"not(mod(n,{to_skip}))"
pipe = (
ffmpeg
.input(input_file.as_posix())
.trim(start=start, end=end)
.setpts('PTS-STARTPTS')
.filter('select', filter_string)
.output(output_file.as_posix(), vsync='vfr')
.global_args('-loglevel', 'error')
.global_args('-y')
.run()
)
I actually solved the issue by accessing ffmpeg
using Python and the subprocess.call
function. Although not as streamlined, I can now loop through my videos and add appropriate timestamps, frame numbers, and titles to each image extracted at a specific interval. Using the cv2
module, I read the frame rate of each video and use it with a user-defined time duration to select out frames at specific intervals.
in_path = sub_path
out_path = video_path + "/" + sub_dir + "_%03d.jpg"
ffmpeg_path = 'C:/ffmpeg/bin/ffmpeg.exe'
fps = fps
seconds = 10
framenumber = str(fps*seconds)
cmd = ffmpeg_path +
' -i ' +
in_path +
' -vf "drawtext=fontfile=/Windows/Fonts/courbd.ttf:fontsize=40:fontcolor=white:box=1:boxcolor=black@0.4: boxborderw=8:x=10:y=h-th-10:timecode=\'00\:00\:00\:00:rate=29.97\', drawtext=fontfile=/Windows/Fonts/courbd.ttf: text=\'Frame \: %{eif\:n\:d\:6}\': start_number=0: x=w-tw:y=h-th: fontcolor=white: fontsize=40: box=1:boxcolor=black@0.4: boxborderw=8, drawtext=fontfile=/Windows/Fonts/courbd.ttf: text=' + sub_dir + ': x=w-tw:y=0: fontcolor=white: fontsize=40: box=1:boxcolor=black@0.4: boxborderw=8, select=not(mod(n\,' + framenumber + '))" -vsync vfr -q:v 2 ' +
out_path
print(cmd)
subprocess.call(args=cmd, shell=True, stdout=sys.stdout, stderr=sys.stderr)
aha, great that it worked!
Hello,
I've been able to the the
ffmpeg
library to import a video and extract a sequence of JPG images (1 frame every 300 frames) using the below command.ffmpeg -i input.mov -vf "select=not(mod(n\,300))" -vsync vfr -q:v 2 img_%03d.jpg
However, I am unable to duplicate this effort when using the
ffmpeg.filter
function in theffmpeg-python
module. When I runffmpeg.input("example.mov).filter("select","not(mod(n\,300))").output('image_%03d.jpg')
Python outputs the following error:
Traceback (most recent call last): File "<string>", line 32, in <module> File "C:\Users\CONNOR~1\MINICO~1\envs\general\Lib\site-packages\ffmpeg\_run.py", line 325, in run raise Error('ffmpeg', out, err) ffmpeg._run.Error: ffmpeg error (see stderr output for detail)
Removing the
\' in the
not(mod(n\,300))` statement allows the code to execute, but it outputs every frame in the video (30 fps * 30 seconds = 900 frames).Does anyone have any suggestions or can they provide an example where I can use the
select
filter inffmpeg-python
to extract images at specific intervals?Thanks in advance!