Goal: To crop a video at a specific frame using FFMPEG
Problem: Video freezes at the end for ~1s
I'm new to FFMPEG, so not sure if any other details are needed to debug this.
import subprocess
import datetime
# Calculate start and end times in hh:mm:ss.ms
start_frame, end_frame = (9553, 10181)
start_time = str(datetime.timedelta(seconds=start_frame/fps))
end_time = str(datetime.timedelta(seconds=end_frame/fps))
cmd = ['ffmpeg', '-y', '-ss', start_time, '-to', end_time, '-i', input_path, '-c', 'copy', clip_path]
subprocess.call(cmd)
Values:
Start Frame: 9553
End Frame: 10181
Start Time: 0:06:22.120000
End Time: 0:06:47.240000
You will have to cut on key frames only or remove -c copy and re-encode.
Related
I'm trying to cut out a fragment from video with the given start and end frames indexes or theirs timestamps (preferably frame indexes). So far I've found this Q but it takes floats and convert them to integers hence the output video has inaccurate frames
this is a sample of what I've tried which gives me inaccurate output video
def extract_fragment(input_path, output_path):
start_time = 3.453453
end_time = 6.8768678
ffmpeg_extract_subclip(
filename=input_path,
t1=start_time,
t2=end_time,
targetname=output_path,
)
And I also tried to use ffmpeg directly
with duration
subprocess.call(
[
"ffmpeg",
"-start_at_zero",
"-copyts",
"-ss",
start_time,
"-t",
end_time - start_time,
"-i",
f"{path_to_video}",
"-c",
"copy",
f"{output_video_path}",
]
)
subprocess.call(
[
"ffmpeg",
"-y",
"-ss",
str(start_time),
"-i",
path_to_video,
"-t",
str(end_time),
"-map",
"0",
"-vcodec",
"copy",
"-acodec",
"copy",
output_video_path,
]
)
I wanna ask that I want to add drawtext filter to the video in last 3 seconds only, may the video of any length like 2 minutes or 20 minutes, whatever. I want it in Python format.
With MoviePy you can get duration or end and use it to start text at end-3 or duration-3
from moviepy.editor import *
video = VideoFileClip("input.mp4")
print('duration:', video.duration)
text = TextClip('Hello', fontsize=70, color='white')
text = text.set_position('center')
text = text.set_start(video.end-3)
text = text.set_end(video.end)
#text = text.set_start(video.duration-3)
#text = text.set_end(video.duration)
result = CompositeVideoClip([video, text])
result.write_videofile("output.mp4")
EDIT:
The same method with ffmpeg-python.
First I get duration and later I use it with enable=f"between(t,{duration-3},{duration})"
I use x='(w-text_w)/2', y='(h-text_h)/2' to center text.
import ffmpeg
info = ffmpeg.probe('input.mp4')
duration = float(info['format']['duration'])
print('duration:', duration)
(
ffmpeg
.input('input.mp4')
.drawtext(text='Hello', x='(w-text_w)/2', y='(h-text_h)/2', fontsize=70, fontcolor='red', enable=f'between(t,{duration-3},{duration})')
.output('output.mp4')
.run(overwrite_output=True)
)
EDIT:
With ffmpeg-python you can even display arguments for program ffmpeg
video = (
ffmpeg
.input(filename)
.drawtext(text='Hello', x='(w-text_w)/2', y='(h-text_h)/2', fontsize=70, fontcolor='red', enable=f'between(t,{duration-3},{duration})')
.output('output.mp4')
)
video.run(overwrite_output=True)
video.view(detail=True) # image
print(video.get_args()) # text
Result:
['-i', 'input.mp4', '-filter_complex', '[0]drawtext=enable=between(t\\,4.036\\,7.036):fontcolor=red:fontsize=70:text=Hello:x=(w-text_w)/2:y=(h-text_h)/2[s0]', '-map', '[s0]', 'output.mp4']
I called a ping command with subprocess. My calculated time difference is lower than the operational time.
latency: 361.953 [actual operation time]
calculated_latency: 0.7531721591949463 [calculated with python]
If python executes line by line, then calculated latency would be higher than the original one. I am not sure what is going on and how can I calculate the time of a function call.
import subprocess
import shlex
import re
import time
from datetime import datetime
command_line = "ping -c 1 {}".format('yahoo.com')
args = shlex.split(command_line)
try:
start = time.time()
output = subprocess.check_output(args)
end = time.time()
ping_latency_calculated = end - start
result = str(output).strip("b'")
m = re.search(r"\/(\d+\.\d+)\/", result)
ping_latency = m.group(1)
result = {'latency': ping_latency, 'calculated_latency': ping_latency_calculated}
except subprocess.CalledProcessError as e:
result = {'Status': 'Ping Failed', 'time': datetime.fromtimestamp(time.time())}
return result
calculated_latency is counted in seconds and latency is counted in milliseconds.
So the result you get actually is:
latency: 361.953 ms
calculated_latency: 753.1721591949463 ms
Is there an easy way to trim a video file in python. If I know the start time and end time, I want to save the new file as multiple shorter files based on input.
example pseudo code:
function cut_video(original_vid, start, stop):
original_vid.start_time(start)
original_vid.end_time(stop)
original_vid.trim() #based on times
new_vid = original_vid
return new_vid
Found a solution:
def get_ffmpeg_bin():
ffmpeg_dir = helper_functions.get_ffmpeg_dir_path()
FFMPEG_BIN = os.path.join(ffmpeg_dir, "ffmpeg.exe")
return FFMPEG_BIN
def split_vid_from_path(video_file_path, start_time, durration):
ffmpeg_binary = get_ffmpeg_bin()
output_file_name = get_next_file_name(video_file_path)
pipe = sp.Popen([ffmpeg_binary,"-v", "quiet", "-y", "-i", video_file_path, "-vcodec", "copy", "-acodec", "copy",
"-ss", start_time, "-t", durration, "-sn", output_file_name ])
pipe.wait()
return True
sample_vid = os.path.join(get_sample_vid_dir_path(), "Superman-01-The_Mad_Scientist.mp4")
split_vid_from_path(sample_vid, "00:00:00", "00:00:17")
https://www.ffmpeg.org/ffmpeg.html -> this documentation allows you to add your own custom flags to your ffmpeg wrapper.
Something to note, you may want to verify the user is giving you valid data.
A nice module to do these kids of things is moviepy.
Example Code:
from moviepy.editor import *
video = VideoFileClip("myHolidays.mp4").subclip(50,60)
# Make the text. Many more options are available.
txt_clip = ( TextClip("My Holidays 2013",fontsize=70,color='white')
.set_position('center')
.set_duration(10) )
result = CompositeVideoClip([video, txt_clip]) # Overlay text on video
result.write_videofile("myHolidays_edited.webm",fps=25) # Many options...
The documentation of this module can be found at https://pypi.org/project/moviepy/
I am running a lot of processes called "csm.py". Each process has a command line argument for example "testarg".
"csm.py testarg".
I am using psutil to sucessfully check if another process of the same name ("csm.py testarg") is running with this code:
for process in psutil.process_iter():
cmdline = process.cmdline
if result[0][2] in cmdline:
proc += 1
if proc >= 2:
# DO SOMETHING
What I would like to do is find out IF there is a process called "csm.py testarg" already running that is older than 1 hour, and if it is kill it but do not kill the new process (this one) that is checking for the old "csm.py testarg". Is it possible to get the processes start time / date with psutil?
Thanks
I managed to figure it out like so:
for process in psutil.process_iter():
pid = process.pid
cmdline = process.cmdline
if what_im_looking_for in cmdline:
p = psutil.Process(pid)
p.create_time
pidcreated = datetime.datetime.fromtimestamp(p.create_time)
allowed_time = pidcreated + datetime.timedelta( 0, 5400 )
now = datetime.datetime.now()
if now > allowed_time:
print "Killing process {} Start time: {} Current time: {}".format( pid, pidcreated, now)
p.kill()
>>> import os, psutil, datetime
>>> p = psutil.Process(os.getpid())
>>> p.create_time()
1307289803.47
>>> datetime.datetime.fromtimestamp(p.create_time()).strftime("%Y-%m-%d %H:%M:%S")
'2011-03-05 18:03:52'