i took trimming example and try to make use in app i am working on. its simple gui (pyqt5) to help me work do batch processing.
graph / operations happening in following order
Crop > trim > pad > drawtext > watermark
i tried changing order by keeping trim in start and moving crop ahead as well. same result.
previously i was doing all above via batch files separately, it works but i hate it,
Earlier in my tests with batch file, i had noticed same issue as well. Stack OverFlow searches taught me that, adding -strict -2 before end helps. command in batch file looked like this
ffmpeg -i %dtp% -ss %s% -strict -2 -t %t% %filepath%\%filename
above line worked correctly in batch file.
Q. how can i make use of that here if my triming funtion looks like below
def trim_video(input,ss=0,t=100):
trimmed_out = (
input
.trim(start_frame=ss, end_frame=t)
)
return trimmed_out
thanks again for support
i need help (for sure) i am doing it wrong way...
NOW, function below works but mute audio(no audio in output) do i need to separately add audio at end as process.
def addTopText(input, topText="", fontName="", fontColor="white", fontSize=32,):
TOP_FONT = os.path.join(os.getcwd(), fontName)
FONT_OPTIONS = {
'fontfile': TOP_FONT,
'fontcolor': fontColor,
'shadowcolor': 'black',
'x': 'main_w-text_w-line_h',
}
textStream = (
input
.drawtext(text=topText, fontsize=fontSize, y='2*line_h', **FONT_OPTIONS)
)
return textStream
@lalamax3d
how did you manage to get the correct trim using ffmpeg-python? I get the same still frames.
i wasn't able to , so i reverted back to cmdline ffmpeg approach. except, the way i manage for now is.
a- prepare a command (based on gui settings from user
b- process using cmdline ffmpeg
def DoCropNTrim(self):
command = ['ffmpeg',
'-loglevel', 'fatal',
'-i', self.activeVideoFile]
outputStr = ""
if self.cb_Trim.isChecked():
outputStr += "_trim"
command.append('-ss')
command.append(str(self.ts.value()))
#command.append(str(datetime.timedelta(seconds=self.ts.value())))
command.append('-strict')
command.append('-2')
command.append('-t')
#command.append(str(datetime.timedelta(seconds=self.te.value())))
command.append(str(self.te.value()))
if self.cb_Crop.isChecked():
outputStr += "_crop"
p1 = self.canvas.cropStart.pos()
p2 = self.canvas.cropEnd.pos()
ow = p2.x()-p1.x()
oh = p2.y()-p1.y()
cx = p1.x()
cy = p1.y()
command.append('-vf')
command.append('crop=%d:%d:%d:%d'%(ow, oh, cx, cy))
if outputStr != "":
command.append(get_output_filename(self.activeVideoFile, outputStr))
export_video(self.activeVideoFile,command)
def ExportVideo(self,e):
'''
this is first attempt using subprocess, pretty close pipe open run, later on using
'''
command = self.createBaseCommand()
print ("BASE COMMAND",command)
filterCommand = self.createComplexCommand(command)
print ("FILTER COMMAND:",filterCommand)
if filterCommand != "":
print ( "ADDING BOTH ")
command.append(filterCommand)
command.append(get_output_filename(self.activeVideoFile, "meme"))
# SENDING FOR EXPORT
export_video(self.activeVideoFile,command)
def export_video(fileloc,command):
print(command)
ffmpeg = subprocess.Popen(command, stderr=subprocess.PIPE ,stdout = subprocess.PIPE )
out, err = ffmpeg.communicate()
if(err) : print('error',err); return None;
print (out)
to make more sense. from image. crop and trim using first function as of now.
button 1(cropntrim) top right is using first function
button 2(export mp4) is using second function,
third function is from another file, which actually doing work. currently it halts UI, but i hope it make sense unless properly preparred using QThread etc
goodluck
I think the problem may be keyframes. You can use ss on the input to seek to the needed frame.
ffmpeg.input('video.mp4', ss=20, t=10)
Starts video.mp4 at 20 seconds and plays ten seconds of it without including a paused frame.
See: https://trac.ffmpeg.org/wiki/Seeking#Cuttingsmallsections
Solved!
I observed the same issue of the 'still frames'. As ffmpeg-python is a wrapper the root cause lies in most cases in FFmpeg itself.
In this case, two additional filters are required:
ffmpeg: "Be aware that frames are taken from each input [video] in timestamp order, so it is a good idea to pass all overlay inputs through a setpts=PTS-STARTPTS filter to have them begin in the same zero timestamp, such as ..."
Translating back to ffmpeg-python, this means you have to add the following calls to you filter chains. An respective API call is available for video (but not for audio):
.setpts('PTS-STARTPTS')
A generic filter call can be used in both cases:
.filter('setpts', expr='PTS-STARTPTS'))
.filter('asetpts', expr='PTS-STARTPTS'))
--Bid
@bidspells How did you solved it i am getting still frames in the end video when i add setpts('PTS-STARTPTS'). it is starting at desired position but the duration is not getting trimmed getting still frames in the end
input1 = ffmpeg.input("/example_videos/ch01_20200202190012.mp4")
node1_1 = input1.trim(start=240).setpts('PTS-STARTPTS')
node1_2 = ffmpeg.filter(node1_1, "fps", fps=4)
node3_1.output("out.mp4").run()
@bidspells How did you solved it i am getting still frames in the end video when i add
setpts('PTS-STARTPTS'). it is starting at desired position but the duration is not getting trimmed getting still frames in the endinput1 = ffmpeg.input("/example_videos/ch01_20200202190012.mp4") node1_1 = input1.trim(start=240).setpts('PTS-STARTPTS') node1_2 = ffmpeg.filter(node1_1, "fps", fps=4) node3_1.output("out.mp4").run()
oh got it corrected the .setpts('PTS-STARTPTS') should be the last command in the node , in this case after ffmpeg.filter(node1_1, "fps", fps=4)
thanx
Most helpful comment
Solved!
I observed the same issue of the 'still frames'. As ffmpeg-python is a wrapper the root cause lies in most cases in FFmpeg itself.
In this case, two additional filters are required:
ffmpeg: "Be aware that frames are taken from each input [video] in timestamp order, so it is a good idea to pass all overlay inputs through a setpts=PTS-STARTPTS filter to have them begin in the same zero timestamp, such as ..."
Translating back to ffmpeg-python, this means you have to add the following calls to you filter chains. An respective API call is available for video (but not for audio):
.setpts('PTS-STARTPTS')A generic filter call can be used in both cases:
--Bid