Skip to content

Instantly share code, notes, and snippets.

@dfaker
Last active June 5, 2024 21:07
Show Gist options
  • Save dfaker/faaa4ae84d39555801d36eccf033b27a to your computer and use it in GitHub Desktop.
Save dfaker/faaa4ae84d39555801d36eccf033b27a to your computer and use it in GitHub Desktop.
ebsynth helper
import cv2
import sys
import os
import subprocess as sp
import numpy as np
import time
baseFolder = os.path.split(__file__)[0]
print("""
*** Requires Pyhton, cv2 and ffmpeg ***
You can install cv2 with:
python -m pip install opencv-python
Ffmpeg from:
https://ffmpeg.org/
1> Place in the same folder as a short .mp4 or .wmv you wish to convert.
2> On first run it will slice the video into video frames and create the keys folder in a subfolder named after the video.
3> Move video Keyframes over to the keys folder and edit them as needed.
4> run ebsynth to generate the out_folders.
5> Run this script again and it will merge them with crossfade as needed and output a final .mp4.
""")
files = [x for x in os.listdir() if os.path.isfile(x) and (x.endswith('.mp4') or x.endswith('.webm')) ]
sourceFile=None
if len(files) > 0:
while sourceFile is None:
print('Select file:\n')
if len(files) == 1:
sourceFile=files[0]
else:
for i,f in enumerate(files):
print(i,'>',f)
try:
n = int(input('Number:'))
if n>=0:
sourceFile = files[n]
except:
print('Error, try again.')
sourceFolder,sourceFilename = os.path.split(sourceFile)
namePart,extPart = os.path.splitext(sourceFilename)
workingfolder = os.path.join(baseFolder,namePart)
videoFolder = os.path.join(workingfolder,'video')
keyFolder = os.path.join(workingfolder,'key')
print('Loading', sourceFilename)
if not os.path.exists(workingfolder):
print('Creating working folder',workingfolder)
os.mkdir(workingfolder)
else:
print('Working folder',workingfolder,'already exists.')
if not os.path.exists(videoFolder):
print('Cutting source video frames.')
os.mkdir(videoFolder)
proc = sp.Popen(['ffmpeg', '-i', sourceFile, '-vf', 'fps=25', os.path.join(videoFolder,'%05d.png')])
proc.communicate()
os.path.exists(keyFolder) or os.mkdir(keyFolder)
frameMap = {}
minframe = float('inf')
maxFrame = 0
exampleFrame=None
keyframeModMap = {}
for f in os.listdir(keyFolder):
p = os.path.join(keyFolder,f)
s = os.stat(p).st_mtime
keyframeModMap[int(f.replace('.png',''))] = s
for r,dl,fl in os.walk(workingfolder):
tailfolder = os.path.split(r)[1]
if tailfolder.startswith('out_'):
n = int(tailfolder.replace('out_',''))
for f in fl:
framePath = os.path.join(r,f)
if exampleFrame is None:
exampleFrame = framePath
s = os.stat(framePath).st_mtime
if s < keyframeModMap.get(n,0):
print('Dependent generated frame',framePath,'modified after keyframe',n)
fileNumbers = sorted([ (int(x.replace('.png','')),os.path.join(r,x)) for x in fl ])
minframe = min(minframe,fileNumbers[0][0])
maxFrame = max(maxFrame,fileNumbers[-1][0])
frameMap[(n,fileNumbers[0][0],fileNumbers[-1][0])] = dict(fileNumbers)
fc = 0
if exampleFrame is None:
exit()
h,w,d = cv2.imread(exampleFrame).shape
print(w,h,d)
writeProc = sp.Popen(['ffmpeg', '-y', '-i', sourceFilename, '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '{}x{}'.format(w,h), '-r', '25', '-i', '-', '-map', '0:a:0', '-map', '1:v:0', '-shortest', os.path.join(workingfolder,'out.mp4') ],stderr=sp.DEVNULL,stdin=sp.PIPE)
k=None
startTime = time.time()
if len(frameMap.keys()) ==1:
for (an,alower,aupper),afilelist in frameMap.items():
for mi in sorted(afilelist):
try:
af = afilelist[mi]
ai = cv2.imread(af)
outimg = (ai).astype('uint8')
cv2.imshow('i',outimg)
wait = 1
print(time.time()-startTime)
fdur = startTime = time.time()
if fdur < 1/25:
wait = ((1/25)-fdur)*1000
k = cv2.waitKey(wait)
writeProc.stdin.write( outimg.tobytes() )
if k==ord('q'):
break
except:
print('frame read failure',bn,an,mi)
writeProc.stdin.write( (np.ones((h,w,d),'uint8')*127).tobytes() )
if k==ord('q'):
break
fc+=1
else:
for ((an,alower,aupper),afilelist) ,((bn,blower,bupper),bfilelist) in zip(sorted(frameMap.items()), sorted(frameMap.items())[1:]):
for mi in range(an,bn):
pc = 1-(mi-an)/(bn-an)
print('groups',an,'-',bn,'frame:',mi,'mix:',pc)
try:
af = afilelist[mi]
bf = bfilelist[mi]
ai = cv2.imread(af)
bi = cv2.imread(bf)
aipc = ai*pc
bipc = bi*(1-pc)
outimg = (aipc+bipc).astype('uint8')
cv2.imshow('i',outimg)
k = cv2.waitKey(1)
writeProc.stdin.write( outimg.tobytes() )
if k==ord('q'):
break
except:
print('frame read failure',bn,an,mi)
writeProc.stdin.write( (np.ones((h,w,d),'uint8')*127).tobytes() )
if k==ord('q'):
break
fc+=1
writeProc.communicate()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment