Skip to content

Instantly share code, notes, and snippets.

@dfaker
Last active September 30, 2019 20:31
Show Gist options
  • Select an option

  • Save dfaker/655591dc995246a0394bdfbfd22b5f82 to your computer and use it in GitHub Desktop.

Select an option

Save dfaker/655591dc995246a0394bdfbfd22b5f82 to your computer and use it in GitHub Desktop.
import os
import glob
import subprocess as sp
import itertools
import sys
"""
REQUIRES:
MPV https://mpv.io/
FFMPEG https://www.ffmpeg.org/
Can be run from the command line like:
interest.py
(to browse starting at the folder the script is located in)
or
interest.py DIR/PATH
(to browse starting at a custom folder)
or
interest.py FILE/PATH
(to open a file directly)
After a file is selected it will open in mplayer.
tap x rapidly to mark current frames as 'interesting' to mark them for later extract.
press c to start cropping, click once to start the crop and second time to complete it.
"""
def selectFromEnumerated(itemList,headerPrompt='Please select your option by the number in square brackets:',inputPrompt='>>> ',bulletStyle=' [{number}] - {entry}'):
print('')
print(headerPrompt)
selected = None
il=[]
while selected is None:
for i,e in enumerate(itemList):
il.append(i)
print( bulletStyle.format(entry=str(e),number=i))
try:
ind = int(input(inputPrompt))
selected=itemList[ind]
return selected,ind
except Exception as e:
print(e)
root = '.\\'
for arg in sys.argv:
if '.py' not in arg and os.path.exists(arg):
root=arg
while not os.path.isfile(root):
path = os.path.join(root,'*')
print(path)
folders = list(glob.glob(path))
selected,ind = selectFromEnumerated(folders)
root = selected
print(root)
os.path.exists('shotsTemp') or os.mkdir('shotsTemp')
playerProc = sp.Popen(['mpv',root,'--script', 'easycrop.lua','--input-conf','customMpvConf.conf'],stdout=sp.PIPE,stderr=sp.DEVNULL)
timeStamps=[]
buf=b''
crops = {}
while 1:
c = playerProc.stdout.read(1)
if len(c)==0:
break
buf+=c
markerCount=buf.count(b']@[')
if markerCount>0 and markerCount%2==0:
for e in buf.split(b']@['):
if b'CROP,' in e:
cropTS=0
if len(timeStamps)>0:
cropTS=timeStamps[-1]
name,w,h,x,y = e.split(b',')
print(name,w,h,x,y)
w,h,x,y = int(w),int(h),int(x),int(y)
print(name,w,h,x,y)
crops[cropTS]=(w,h,x,y)
try:
e=float(e)
timeStamps.append(e)
except:
pass
buf=b''
maxw,maxh,maxx,maxy,minx,miny=0,0,0,0,0,0
for h,w,x,y in crops.values():
maxh = max(maxh,h)
maxw = max(maxw,w)
maxx = max(maxx,x+w)
maxy = max(maxy,y+h)
minx = max(minx,x)
miny = max(miny,y)
for k,(h,w,x,y) in list(crops.items()):
h2=maxh
w2=maxw
x2 = max( min(x ,minx - h2 ) ,minx)
y2 = max( min(y ,miny - w2 ) ,miny)
crops[k] = (h2,w2,x2,y2)
playerProc.communicate()
timeStamps=sorted(timeStamps)
if len(timeStamps)==0:
exit()
tempTimestamps = []
for value,group in itertools.groupby(timeStamps,lambda x:int(x)):
listGroup = list(group)
groupLen = len(listGroup)
print('Processed', groupLen ,'tags at around second',value)
for v in listGroup:
tempTimestamps.append( (v, min(4,groupLen) ) )
timeStamps = tempTimestamps
print('Found a total of', len(timeStamps), 'tagged frames. Will now merge into sections.' )
spans=[ (timeStamps[0][0],timeStamps[0][0]) ]
lastTimeStamp=timeStamps[0][0]
for ts,bias in timeStamps:
head = spans[:-1]
tails,taile=spans[-1]
if abs(ts-taile)<0.5+(0.3*bias):
taile=ts
spans = head+[(tails,taile)]
else:
spans = head+[(tails,taile),(ts,ts)]
def diverge(s,e):
if s<e:
return (s,e)
elif e<s:
return (e,e)
else:
return (s-1,s+1)
spans = [ diverge(s,e) for s,e in sorted(spans)]
spanToCropLookup = {}
if len(crops)>0:
for s,e in spans:
mid = (s+e)/2
closest = sorted([ (k,(h,w,x,y)) for k,(h,w,x,y) in crops.items()],key=lambda x: abs(x[0]-mid) )[0][1]
spanToCropLookup[(s,e)]=closest
os.path.exists('cutsTemp') or os.mkdir('cutsTemp')
cutBaseNum = len(os.listdir('cutsTemp'))
print('Starting on ',len(spans),'sections starting cuts:')
with open(os.path.join('cutsTemp','concatInst.txt'),'w') as concatInst:
for i,(s,e) in enumerate(spans):
print('Making cut',i+1,' ar start ',s ,'seconds through to ',e,' seconds')
outfn = os.path.join('cutsTemp',str(cutBaseNum)+'_'+str(i)+'.mp4')
if len(spanToCropLookup)==0:
cutProc = sp.Popen(['ffmpeg','-ss',str(s),'-i',root,'-t',str(e-s),outfn],stdout=sp.DEVNULL,stderr=sp.DEVNULL)
else:
w,h,x,y = spanToCropLookup[(s,e)]
cmd = ['ffmpeg','-ss',str(s),'-i',root,'-t',str(e-s), "-vf", "crop={}:{}:{}:{}".format(w,h,x,y) ,outfn]
print(cmd)
cutProc = sp.Popen(cmd,stdout=sp.DEVNULL,stderr=sp.DEVNULL)
cutProc.communicate()
concatInst.write('file '+outfn.replace('\\','\\\\')+'\n')
print('Cut ',i,' complete')
os.path.exists('joinsTemp') or os.mkdir('joinsTemp')
joinBaseNum = str(len(os.listdir('joinsTemp'))) +os.path.splitext(os.path.basename(root))[0]
outfn = os.path.join('joinsTemp',joinBaseNum+'_'+str(i)+'.mp4')
print('Starting join into ',outfn)
joinProc = sp.Popen(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', os.path.join('cutsTemp','concatInst.txt'), '-c', 'copy', outfn],stdout=sp.DEVNULL,stderr=sp.DEVNULL)
joinProc.communicate()
print('Join complete into ',outfn)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment